进程的切换和系统的一般执行过程
一、进程调度的三个时机:
1.中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();
2.内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;
3.用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。
二、switch_to完成寄存器的切换
switch_to(prev,next,prev);
进程切换:为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换(process switch)、
任务切换(task switch)或上下文切换(context switch)。
schedule()函数选择一个新的进程来运行,调用switch_to来进行关键上下文切换。
switch_to完成寄存器的切换:先保存当前进程的寄存器,再进行堆栈切换,自此后所有的压栈都是在新进程的堆栈中了,再切换eip,这样当前进程
可以从新进程中恢复,还有其他必要的切换。
进程上下文包含了进程执行需要的所有信息,包括:
1、用户地址空间:包括程序代码,数据,用户堆栈等
2、控制信息:进程描述符,内核堆栈等
3、硬件上下文(与中断保存硬件上下文的方法不同)
三、Linux系统的一般执行过程(最一般的情况)
正在运行的用户态进程X切换到运行用户态进程Y的过程
正在运行的用户态进程X
发生中断——
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)
进入内核代码,SAVE_ALL //保存现场
(这一步也可能不发生)中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
标号1之后开始运行上一步中选中的用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
restore_all //恢复现场
iret - pop cs:eip/ss:esp/eflags from kernel stack
继续运行用户态进程Y
四、实验:
1.下载menu系统:
2.启动gdb进行调试:
3.在schedule处设置断点,点击c运行:
4.停在断点1:schedule
5.停在断点2:context_switch
6.按n单步执行:
五、总结:
Linux系统的一般执行过程:参见三。