赵连讯 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
进程切换的一般场景分析
当前linux系统中正在运行用户态进程X,需要切换到用户态进程Y的时候:
1.用户态进程X正在运行
2.运行的过程当中,发生了中断。中断可以是硬件中断,比如来自了外部的gpio的中断,可以是时钟中断,可以是系统调用。或者可能是异常发生,可以是缺页异常。缺页异常肯定是发生在内核中的。但是此时仍然是当前的进程,我们理解为是当前进程的内核态。在内核态中发生了中断行为。
但是我们这里还是讲解的从用户态进入到内核态中。因此发生的中断是系统调用或者硬件中断。
用户空间好像无法引起异常行为。
当进程从用户态进入到内核态的时候会保存那些内容呢?
cs:eip
esp
eflags
所有当前的进程上下文将会被压入到内核的栈中。
然后更新如下寄存器:
cs:eip
esp
更新的新的内容来自当前进程的内核栈和中断服务程序的入口地址
上面的保存和加载是CPU替我们自动完成的。这里应当再好好理解一下。
3.SAVE_ALL
保存现场。保存的是内核当前的现场。为开始执行新的陷入内核中断处理函数做准备。
4.执行中断服务函数。执行结束后返回到应用空间之前,将会可能调用函数schedule。一旦发生调度,则会执行switch_to函数,发生内核的堆栈信息。切换进入到Y进程的内核上下文中。
5开始执行Y的内核代码,就是从标号1的位置开始执行。此时仍然在内核空间中。这里将会说明Y进程肯定已经进入到内核中过。在fork的时候就会给他创建一个内核的栈。
6.restore_all此时是Y进程的恢复现场。
7.iret将会pop出Y进程发生中断时保存的用户空间的cs:eip和ss:sp的值。
8.开始执行Y的应用层空间。
特殊情况
系统在运行时除了一般的系统切换过程之外还有那些特殊情况呢?
当用户态的进程切换到内核进程时,此时内核进程将不会再进入到用户态中,因此将会缺少一次进程上下文切换。
内核线程可以主动的调度schedule函数,但是用户态进程不可以。此时不再需要中断,因此也没有中断上下文切换。
fork的新的进程发生切换时入口地址是ret_from_fork而不是标号1F。
execve加载一个新的可执行程序后,返回到应用空间时,中断保存的信息将会被修改。
总结
一般切换流程中有CPU的上下文的切换和内核中的进程上下文的切换。
一般切换的过程是针对了进程已经创建好了,并且多次进入到内核中。如果新创建的进程和一个已经运行的进程之间会不会发生进程的切换呢?也可以发生进程切换。不同的地方是新创建的子进程的入口地址将不会是1F,而是ret_from_fork这个入口地址。
内核空间是被进程共享的,共享如何更好的理解,还需要更多的案例分析。