淘先锋技术网

首页 1 2 3 4 5 6 7

有关进程的知识在前面的博客中已经提到了,有不懂的地方请参考我前面的博客,今天我直接从进程调度和切换开始讲。

Linux一个较大的优势就是进程调度,因为Linux是一个多进程系统,它怎么进行进程调度直接影响这个系统的性能,而Linux系统的一个优势就是它的系统在进程调度这里做的很好。

在讲进程调度前,我们先来看下有关Linux知识(以下4张图片摘自孟宁老师课件)。

图1.Linux内核架构

图2.Linux执行过程

图3.CPU执行指令角度

图4.从内存角度看待Linux系统执行

首先一起来看下Linux的进程的类型,一般将进程分为三种,一种为I/O消耗型进程,另一种是处理器消耗型进程,还有一种是混合型,也就是I/O消耗型进程和处理器消耗型进程混合在一起的。从他们的名字可以看出,这是以进程消耗资源的种类来进行分类的。

在Linux系统中,是按照什么规则来进行调度的呢?我们所知的有优先级调度,还有时间片调度。其中优先级指的是进程的优先级,而时间片则指的是进程所需要消耗的时间。

那么Linux系统中进程调度的过程到底是一个什么流程呢?主要是以下几个方面

1.从schedule()函数开始,进行调度选择

2.从CPU的值变化上,解读switch_to宏执行分析

3.到堆栈发生切换位置,在切换堆栈前后,current_thread_info变化

4.再到地址空间发生切换,解释地址空间的切换不会影响后续切换代码的执行

5.Current宏代表的进程发生变化的源码位置

6.任务状态段中关于内核堆栈的信息发生变化的源码位置

下面来详细的讲解一下各个环节

在Linux内核中,schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换。部分函数具体代码如下,一个调度新进程,一个是进行上下文切换,还有相关堆栈信息的保存。

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

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

switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

Schedule:主要负责帮助系统选定下一个执行的进程

调度时机:

1.进程状态转换的时刻,进程终止、进程睡眠。

2.当前进程的时间片用完时。

3.设备驱动程序调用。

4.进程从中断、异常及系统调用返回到用户态时。

进程的从睡眠状态到唤醒状态,完成了一次进程的调度,中间有保存相应的进程信息,有相应的队列进行保存。

进程调度中还有一个现象是抢占,就是优先级高的进程进行抢占低优先级的执行机会,用户抢占发生在两种情况下,一个是从系统调用返回用户空间,另一个是从中断处理程序返回用户空间。

而内核抢占发生在:

1.当从中断处理程序正在执行,且返回内核空间之前;

2.当内核代码再一次具有可抢占性的时候;

3.如果内核中的任务显式调用;

4.内核中的任务被阻塞。

上下文的切换也是进程调用中一个比较重要的问题,其中有一个context_switch()函数完成以下工作,switch_mm()——该函数负责把虚拟内存从上一个进程映射切换到新进程中。而switch_to()——负责从上一个进程的处理器状态切换到新进程的处理器状态。切换的过程包括保存、恢复栈信息和寄存器信息。

其中各种进程之间的调度又有很多方法,主要有先进先出、时间片轮转等方式,这里就不具体分析,有兴趣的可以自行查阅相应的调度方法。

下面来看下具体实验过程:

图5.相关指令操作,创建文件

图6.文件内部修改处

图7.文件内部修改处

图8.调试启动

图9.设置断点

图10.查看context_switch处相关点代码

图11.中途的代码调试过程

总结:从上面可以看出,Linux系统的进程切换的一般执行过程是这样的,从进程X转向进程Y的过程是这样的。

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

2.发生中断——savecs:eip/esp/eflags(current)tokernelstack,thenloadcs:eip(entryofaspecificISR)and

ss:esp(pointtokernelstack)。

3.SAVE_ALL//保存现场。

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

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

6.restore_all//恢复现场。

7.iret-popcs:eip/ss:esp/eflagsfromkernelstack//恢复。

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

好了,从上面可以看到,整个Linux系统的进程切换的执行流程就是这个样子的!