日期:2014-05-16  浏览次数:20686 次

linux进程解析--进程切换
为了控制进程的执行,linux内核必须有能力挂起正在cpu上运行的进程,换入想要切换的进程,也就是恢复以前某个挂起的进程,这就是linux的进程切换。
 1进程切换的时机
一般来说,进程切换都是发生在从中断或者系统调用返回用户态的时候,最常见的是时钟中断。在允许内核抢占的情况下,系统调用被中断打断也有可能会引发进程切换。中断处理和系统调用处理都发生在内核态,所以进程之间的切换实际上也是发生在了内核态。
2进程切换做的工作
2.1切换页全局目录以安装一个新的地址空间。
2.2切换内核态堆栈和硬件上下文,硬件上下文提供了新进程运行所需要的所有的寄存器的所有信息。
3进程切换的过程
进程切换统一发生在schedule()函数中,在这个里面我们仅仅先来关注切换的过程,在内核代码中切换进程的过程在switch_to()中,switch_to()是一个宏,其定义如下:
#define switch_to(prev,next,last) do { \
unsigned long esi,edi; \
asm volatile("pushfl\n\t" \
    "pushl %%ebp\n\t" \
    "movl %%esp,%0\n\t" /* save ESP */ \
    "movl %5,%%esp\n\t" /* restore ESP */ \
    "movl $1f,%1\n\t" /* save EIP */ \
    "pushl %6\n\t" /* restore EIP */ \
    "jmp __switch_to\n" \
    "1:\t" \
    "popl %%ebp\n\t" \
    "popfl" \
    :"=m" (prev->thread.esp),"=m" (prev->thread.eip), \
     "=a" (last),"=S" (esi),"=D" (edi) \
    :"m" (next->thread.esp),"m" (next->thread.eip), \
     "2" (prev), "d" (next)); \
} while (0)
3.1参数说明
prev存放的是当前的current进程描述符指针。
next存放的是需要被替换进来的进程的描述符指针。
last比较麻烦,在一次进程被切换出去又切换进来的过程中,一般会涉及到3个进程,进程A,B,C,当进程A运行时,切换到进程B,然后再系统运行一段时间后,系统中运行的进程变为了进程C,然后由进程调度程序调度进程A运行,当调度进程A运行时,进程A使用的是自己的内核栈,里面的prev和next就还是从A切换到B时的prev, next,即prev = A, next=B.然而本次从C切换到A应该将prev改变为C才对,而不是A了。
为解决这个问题switch_to()宏在进入后,会把prev先保存到寄存器eax中,当完成进程切换后,把eax的值存入变量last中。
 
3.2过程说明
采用标准的汇编语言说明如下:
1在eax,edx寄存器中分别保存prev和next的值。
movl prev, %eax
   movl next, %edx
2把eflags和ebp寄存器存入prev进程的内核栈中,ebp寄存器中存放的是当前函数栈帧的栈底。
pushfl