进程的切换和系统的一般执行过程【转】

转自:http://www.cnblogs.com/20135124freedom/p/5391170.html

陈民禾 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

一.关于进程调度的基本知识

      进程的几种不同分类:第一种分类:类型一:I/O-bound:频繁的进行I/O,通常会花费很多的时间等待I/O操作的完成;类型二:CPU-bound:计算密集型 ,需要大量的CPU时间进行运算第二种分类:类型一:批处理进程 ;类型二:实时进程;类型三:交互式进程。

      调度策略:是一组规则,它们决定什么时候以怎样的方式选择一个新的进程运行,Linux的调度基于分时和优先级:随着版本的变化,分时技术在不断变化,Linux既支持普通的分时进程,也支持实时进程,Linux中的调度是多种调度策略和调度算法的混合。

     Linux的进程根据优先级排队:根据特定的算法计算出进程的优先级,用一个值表示,这个值表示把进程如何适当的分配给CPU。

     Linux中进程的优先级是动态的:调度优先级会根据进程的行为周期性的调整进程的优先级:较长时间未分配到CPU的进程,通常上升;已经在CPU上运行了较长时间的进程,通常下降。挂起正在CPU上执行的进程,与中断时保存现场是不同的,中断前后是在同一个进程上下文中,只是由用户态转向内核态执行

     进程上下文包含了进程执行所需要的所有信息。

          用户地址空间:包括程序代码,数据,用户堆栈等

          控制信息:进程描述符,内核堆栈等

          硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)

    Linux系统的一般执行过程分析:这时候我们可以有了一个条件来理解linux系统的一般运行状态,其中有一个用户态进程X需要切换到用户进程Y。从正在运行的用户态进程X切换到正在运行的用户态进程Y的过程

          1.正在运行的用户态进程X

          2.发生中断——save cs:eip/esp/eflags(current)to kernel stack,then load cs:eip(entry of a specific ISR)and ss:esp(point to kernel stack)

          3.SAVE_ALL//保存现场

          4.中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换

          5.标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)

          6.restore-all//恢复现场

          7.iret -pop cs:eip/ss:eip/eflags from kernel stack

          8.继续运行用户态进程Y

 

二.进程调度关键代码分析

      我们还有很多的系统调用可以实现进程的优先级,比如说以下的代码:

    nice
    getpriority
    sched_getscheduler/sched_setscheduler
    sched_getparam/sched_setparam
    sched_yield
    sched_get_priority_min/sched_get_priority_max    sched_rr_get_interval

      调度算法策略只是一个策略算法而已,不管使用什么策略,都是从队伍中选择了下一个进程来执行,将调度算法与其他部分耦合了。

      进程调度的时机须知道以下四点:中断处理过程(包括时钟中断、I\O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态的时根据need_resched标记调用schedule();内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程进行调度,也就是说内核线程作为一类特殊的进程可以主动,也可以被动调度;用户态进程无法实现主动调度,仅能通过陷入内核态的某个时机进行调度,即在中断处理过程中进行调度;用户态只能被动调度,内核线程是只有内核态没有用户态的特殊进程,内核线程可以主动调度也可以被动调度。

      schedule函数:schedule函数实现调度,目的:在运行队伍中找到一个进程,把CPU分配给它,调用方法:直接使用schedule();松散调用,根据need_resched标记

next = pick_next_task(rq, prev); //进程调度算法都封装这个函数内部

context_switch(rq, prev, next); //进程上下文切换

switch_to切换堆栈和寄存器的状态,利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

 进程上下文调度相关代码分析:在switch()中:

31#define switch_to(prev, next, last)
32do {
33  /*
34   * Context-switching clobbers all registers, so we clobber
35   * them explicitly, via unused output variables.
36   * (EAX and EBP is not listed because EBP is saved/restored
37   * explicitly for wchan access and EAX is the return value of
38   * __switch_to())
39   */
40  unsigned long ebx, ecx, edx, esi, edi;
41
42  asm volatile("pushfl\n\t"      /* save    flags */          //保存当前进程的flags
43           "pushl %%ebp\n\t"        /* save    EBP   */       //把当前进程的堆栈基址压栈
44           "movl %%esp,%[prev_sp]\n\t"  /* save    ESP   */   //把当前的栈顶保存到prev->thread.sp
45           "movl %[next_sp],%%esp\n\t"  /* restore ESP   */   //把下一个进程的栈顶保存到esp中,这两句完成了内核堆栈的切换
46           "movl $1f,%[prev_ip]\n\t"    /* save    EIP   */   //保存当前进程的EIP,可以从这恢复
47           "pushl %[next_ip]\n\t"   /* restore EIP   */       //把下一个进程的起点位置压到堆栈,就是next进程的栈顶。next_ip一般是$1f,对于新创建的子进程是ret_from_fork
             //一般用return直接把next_ip pop出来
48           __switch_canary
49           "jmp __switch_to\n"  /* regparm call  */  //jmp通过寄存器传递参数,即后面的a,d。 函数__switch_to也有return把next_ip pop出来
50           "1:\t"              //认为从这开始执行next进程(EIP角度),第一条指令是next_ip这个起点,但前面已经完成内核堆栈的切换,早就是next进程的内核堆栈(算prev进程,比较模糊)
51           "popl %%ebp\n\t"     /* restore EBP   */  //next进程曾经是prev进程,压栈过ebp
52           "popfl\n"         /* restore flags */
53
54           /* output parameters */
55           : [prev_sp] "=m" (prev->thread.sp),     //当前进程的,在中断内部,在内核态,sp是内核堆栈的栈顶
56             [prev_ip] "=m" (prev->thread.ip),     //当前进程的EIP
57             "=a" (last),
58
59             /* clobbered output registers: */
60             "=b" (ebx), "=c" (ecx), "=d" (edx),
61             "=S" (esi), "=D" (edi)
62
63             __switch_canary_oparam
64
65             /* input parameters: */
66           : [next_sp]  "m" (next->thread.sp),    //下一个进程的内核堆栈的栈顶
67             [next_ip]  "m" (next->thread.ip),    //下一个进程的执行起点
68
69             /* regparm parameters for __switch_to(): */
70             [prev]     "a" (prev),               //寄存器的传递
71             [next]     "d" (next)
72
73             __switch_canary_iparam
74
75           : /* reloaded segment registers */
76          "memory");
77} while (0)

三.Linux系统执行过程中的几个特殊情况:

1.通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;

2.内核线程主动调用schdule(),只有进程上下文的切换,没有中断上下文的切换,与最一般的情况略简略;

3.创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;

4.加载一个新的可执行程序后返回到用户态的情况,如execve;

四.视频中的小总结:

 Linux操作系统架构概览我们在这里总结一下这个课学习的内容:

任何计算机系统都包含一个基本的程序集合,称为操作系统

-内核(进程管理,进程调度,进程间通讯机制,内存管理,中断异常处理,文件系统,I/O系统,网络部分)

-其它程序(例如函数库,shell程序、系统程序等等)

操作系统的目的

-与硬件交互,管理所有的硬件资源

-为用户程序(应用程序)提供一个良好的执行环境

那么我们可以看一张图:最底层有磁盘管理,物理内存的管理,内存控制器还有控制台,这个地方它有一个Kernel Intelface to the hardware,

也就是对硬件资源的管理,然后呢在上一层就是内核的实现,内核的实现也就是CPU调度,内存管理,按需调度,虚拟内存等等,还有其他的驱动,磁盘管理,文件系统等等,这些操作系统的内核,我们这门课分析的内核只是计算机操作系统里面最最关键的一些代码,实际上整个操作系统非常复杂,很多其他的部分都没有涉及。那么呢,这个地方有一个系统调用接口,这里涉及到不同的部分,基础软件也就是share共享库lib ,动态加载器这些等等。

2.ls命令——最简单与最复杂的操作

3.从CPU和内存的角度来看Linux系统的执行

1.从在CPU执行指令的角度看:

2.从内存的角度看

五.实验过程截图及分析

搭建实验环境:

cd LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_exec.c test.c
make rootfs

gdb调试

qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
gdb
file ../linux-3.18.6/vmlinux
target remote:1234
设置断点:
b schedule
b pick_next_task
b context_switch
b switch_to

3.在schedule处设置断点,运行,并用list展开函数

4.单步运行,直至__schedule()

5.在context_switch处设立断点,执行

六.知识总结

    进程调度程序是内核重要的组成部分,因为运行着的进程首先在使用计算机(至少在我们大多数人看来)。然而,满足进程调度的各种需要绝不是轻而易举的,很难找到“一刀切”的算棒,既适合众多的可运行进程,又具有可伸缩性,还能在调度周期和吞吐量之间求得平衡,同时还满足各种负载的需求。不过, Linux 内核的新CFS 调度程序尽量满足了各个方面的需求,并以较完善的可伸缩性和新颖的方挫提供了最佳的解决方案。前面的章节覆盖了进程管理的相关内容,本章则考察了进程调度所遵循的基本原理、具体实现、调度算能以及目前Linux 内核所使用的接口。

时间: 2024-10-03 11:43:36

进程的切换和系统的一般执行过程【转】的相关文章

第八周 进程的切换和系统的一般执行过程【转】

转自:http://www.cnblogs.com/20135305yg/p/5379542.html 一.进程切换的关键代码switch_to分析 进程的调度时机与进程的切换: 操作系统中的进程调度算法是从运行队列中选择一个新进程,选择的过程中运用了不同的策略 进程调度的时机: 中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule() 内核线程可以直接调用schedule()进行进程切换,

日志系统之定时任务执行引擎

概述 最近这段时间在强化日志系统自身的稳定性和可靠性,一个稳定可靠的系统离不开监控,我们这里谈及的监控除了服务是否存活还有这些组件的核心metrics采集与抓取,为此我们将这些任务做成了定时任务来执行.由于大致的思路以及设计已经成型,所以今天来分享一下日志系统在定时任务这块的选型与设计. 组件运行时监控 从我之前分享的文章中不难看出我们日志系统的各个组件的选型: 采集agent : Flume-NG 消息系统 : Kafka 实时流处理 : Storm 分布式搜索/日志存储(暂时) : Elas

Linux中进程前后台切换相关命令

我们使用Linux时大多数是用shell命令行.一个命令窗口是无法直接执行多任务的.我们可以把某个任务先切到后台,再切别的任务到前台来操作.这个帖子整理一下这些常用的命令. 后台进程查看: jobs是用于后台进程查看的很方便的命令. jobs -l 可以显示出进程的pid. 注意一点:shell收到了SIGHUP信号后在退出前将SIGHUP转发给所有的作业(jobs).jobs由于收到SIGHUP而终止运行.(这取决于shell的) 将前台任务放到后台: 按下ctrl + z ,就将任务移到后台

《Android的设计与实现:卷I》——第3章 3.3init进程的执行过程

3.3 init进程的执行过程 init进程是用户空间的第一个进程,进程号为1.Android世界中,很多重要的工作都是从它开始的.init进程相关源码位于/system/core/init目录下,从其编译文件Android.mk中可以看到这部分源代码最终被编译为可执行文件init,代码如下: 注意 pollfd是Linux中定义的结构体,用于存放需要监控事件的文件描述符,其定义如下: struct pollfd { int fd; //需要监控的文件描述符 short events; //监控

光纤自动切换保护系统应用探讨

1.引言要在现有几十万千米高速干线光缆通信网上实现无阻断通信,除传输设备外,运营商首先要考虑的是如何实现光传输物理路由的自动保护.光纤自动切换保护系统是一个集监测.保护和管理为一体的.独立于传输系统的.完全建立在光缆物理层上的自动监测保护系统.该系统能进行光纤运行状态.性能指标的实时.在线.远程.自动监测与主备光缆的切换保护,保证光缆网络安全可靠地运行.2.工作原理自动切换模块可分为单片机控制电路.光功率监测电路.光切换电路.测试 光源电路几部分,其工作原理如图1所示.控制电路控制其他模块电路协

如何从网络服务器中下载数据及针对数据操作的方法到android系统中并执行?

问题描述 如何从网络服务器中下载数据及针对数据操作的方法到android系统中并执行? 有几千组数据和针对数据操作的方法,每组的数据和方法都不相同.每次仅需下载其中的几组.该方法要在android上执行,不知如何实现? 如果用SQLite数据库存贮数据,触发器来实现针对数据操作的方法,android只需从SQLite数据库中取数据.但这样一方面担心某些方法太复杂,触发器实现不了.另一方面担心响应速度过慢. 不知android下可否把不同的代码封装成windows下的DLL文件一样?这样需要哪个就

多进程-模拟进程并发执行过程

问题描述 模拟进程并发执行过程 如何模拟进程并发执行过程(Java) 老师讲,主程序调用三个随机函数,以死循环输出 y有更好的办法吗 解决方案 模拟shell进程进程的执行过程 解决方案二: 直接调用进程http://blog.csdn.net/mindhawk/article/details/3447845

winform-C#关闭进程,如何判断系统是否正在运行此进程

问题描述 C#关闭进程,如何判断系统是否正在运行此进程 准备用C#关闭某进程,比如explorer进程,如何判断系统是否正在运行此进程,从而避免因为系统不存在此进程而报错? 用的是这个方法,但是如果系统中未运行该进程,就会报错 string ProcessName = ""explorer""; Process[] MyProcess = Process.GetProcessesByName(ProcessName); MyProcess[0].Kill(); 解决

百度切换广告系统让Google得利还是站长得利

中介交易 SEO诊断 淘宝客 云主机 技术大厅 路透社发表分析文章称,百度切换广告系统,让Google有机会提高其在中国互联网搜索市场的份额,以下为原文内容: 2005年,中国在一个搜索市场报告中进行了一次拼写测试,要求受访者拼出"Google"一词,结果只有60%的人通过测试,而20%多的人则拼错.4年后,在全世界多数地区,Google公司的名称已经成为互联网搜索的代名词,但是在中国这个全球最大的互联网市场,Google依然在为努力获得认可,本土竞争对手百度通知了该市场. 然而,百度