关于时间片轮转多道程序内核代码分析
【当前进程与处于运行状态的目标进程切换】 asm volatile(
1 "pushl %%ebp\n\t"
/* save ebp */
2 "movl %%esp,%0\n\t"
/* save esp */
3 "movl %2,%%esp\n\t"
/* restore
esp */
4 "movl $1f,%1\n\t"
/* save eip */
5 "pushl %3\n\t"
6 "ret\n\t"
/* restore
eip */
"1:\t"
/* next process start here */
7 "popl %%ebp\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
|
-------------------------------------------------------------------------------- %0: prev->thread.sp(原进程的栈顶指针) %1:prev->thread.ip(原进程的指令指针) %2:next->thread.sp(目标进程的栈顶指针) %3:next->thread.ip(目标进程的指令指针) 1、ebp入栈保护 2、当前esp保存到调度前的原进程控制块中(thread.sp) 3、将调度后目标进程的原esp恢复到esp寄存器中 4、保存eip的值 其中立即数"1f"是标号"1:"相对于当前指令的偏移 以便下次恢复eip后从“1:”处继续执行 5、调度后的目标进程eip入栈 6、ret操作将恢复eip,开始目标进程的任务 7、待执行完成后ebp出栈恢复 |
目标进程没有运行的情况
【当前进程与处于非运行状态的目标进程切换】 asm volatile(
1 "pushl %%ebp\n\t"
/* save ebp */
2 "movl %%esp,%0\n\t"
/* save esp */
3 "movl %2,%%esp\n\t"
/* restore
esp */
4 "movl %2,%%ebp\n\t"
/* restore
ebp */
5 "movl $1f,%1\n\t"
/* save eip */
6 "pushl %3\n\t"
7 "ret\n\t"
/* restore
eip */
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
|
---------------------------------------------------------------------------------- %0: prev->thread.sp(原进程的栈顶指针) %1:prev->thread.ip(原进程的指令指针) %2:next->thread.sp(目标进程的栈顶指针) %3:next->thread.ip(目标进程的指令指针) 1、ebp入栈保护 2、当前esp保存到调度前的原进程控制块中(thread.sp) 3、将调度后目标进程的原esp恢复到esp寄存器中 4、将调度后目标进程的原esp恢复到ebp寄存器中 (新进程的ebp=esp) 5、保存eip的值 其中立即数"1f"是标号"1:"相对于当前指令的偏移 以便下次恢复eip后从“1:”处继续执行 (因为下次切换时目标进程为运行状态对于上面的处理逻辑) 6、调度后的目标进程eip入栈 7、ret操作将恢复eip,开始目标进程的任务 |
总结:
关于任务调度的机制其实是操作系统内核在一个时间片周期结束的时候保存任务现场,主要是当前的eip,esp等寄存器,然后恢复下一个任务的相关寄存器状态,由于计算机硬件在执行指令主要就是靠(CS:IP)来顺序执行指令,在切换过程中通过这些相关寄存器的保存与恢复从而实现任务的切换。
在某些单片机中,有些不可能实现操作系统,就是通过定时器中断与指令指针的存取实现一个模拟的伪多线程操作,其核心思想与PC上的操作系统类似。