switch_to及ret_from_sys_call控制任务的切换与返回
2011-05-12 06:26
453 查看
当进程A在用户态下执行着,出现了系统调用(int 0x80),CPU转而执行_system_call(system_call.s L80)中断处理过程,
_system_call 保持了进程A在用户态时的现场信息,然后执行call _sys_call_table(, %eax, 4)指令,当执行完本指令时,进程
A请求的系统调用已经完成了,_system_call剩下的代码是该系统调用中断处理过程的退出阶段。
当执行到jne reschedule时,处于内核态的进程A希望主动放弃CPU,实现进程调度,reschedule代码如下:
reschedule:
pushl $ret_from_sys_call
jmp _schedule
先将ret_from_sys_call地址入栈,然后跳转到sched.c L104 函数schedule入口处执行该函数,当执行到switch_to(next)时,
如果此时next = B,意味着CPU的使用权将从进程A切换到进程B,当在switch_to(next)中执行完指令ljmp %0/n/t时,此时
CPU自动将进程A的内核态现场环境保存到A对应的tss中,例如将ss, esp保存为进程A内核态堆栈,
将cs保存为0x0008(内核代码段)将eip保存为switch_to(next)中指令cmpl %%ecx,_last_task_used_math/n/t的地址
(即当下一次CPU重新切换到进程A时, 即将执行的指令)。
当CPU将进程A内核态的现在保存完毕时,又自动将进程B对应的tss中的现在信息加载到CPU的寄存器中,
这样CPU就开始执行进程B的指令了。
一段时间后,CPU控制权再次切换到进程A中(此时进程A处于内核态,进程A之前占有CPU的进程X执行了switch_to(B)),
此时cs = 0x0008,eip等于指令cmpl %%ecx,_last_task_used_math/n/t的地址,故而进程A执行指令cmpl %%
ecx,_last_task_used_math,接着执行jne 1f/n/t,clts/n,当执行完clts/n指令后,接着执行ret指令,此时eip等于
ret_from_sys_call的地址,故而函数schedule执行完毕,程序返回到ret_from_sys_call处继续执行。
执行movl _current, %eax,_current指向进程A的struct tast_struct(进程A的任务数据结构),如果是进程A是任务0,则
立即跳出进程A的系统调用中断处理程序;执行cmpw $0x0f,CS(%esp),如果进程A用户态的cs不是普通用户代码段,则退出;
执行cmpw $0x17,OLDSS(%esp),如果进程A用户态堆栈不在用户数据段中,则退出。
当排除了以上可能后,确定了进程A是一个普通的用户态进程(区别于cs=0x08,ds=ss=0x10的进程--内核进程
(这个称呼可能不准确)),然后进行信号量处理,处理完信号量后,执行L121处标号3的代码,进程A的系统调用中断处理程序
全部结束,进程A从内核态返回当用户态,继续执行下一条指令。
附:
switch_to
_system_call 保持了进程A在用户态时的现场信息,然后执行call _sys_call_table(, %eax, 4)指令,当执行完本指令时,进程
A请求的系统调用已经完成了,_system_call剩下的代码是该系统调用中断处理过程的退出阶段。
当执行到jne reschedule时,处于内核态的进程A希望主动放弃CPU,实现进程调度,reschedule代码如下:
reschedule:
pushl $ret_from_sys_call
jmp _schedule
先将ret_from_sys_call地址入栈,然后跳转到sched.c L104 函数schedule入口处执行该函数,当执行到switch_to(next)时,
如果此时next = B,意味着CPU的使用权将从进程A切换到进程B,当在switch_to(next)中执行完指令ljmp %0/n/t时,此时
CPU自动将进程A的内核态现场环境保存到A对应的tss中,例如将ss, esp保存为进程A内核态堆栈,
将cs保存为0x0008(内核代码段)将eip保存为switch_to(next)中指令cmpl %%ecx,_last_task_used_math/n/t的地址
(即当下一次CPU重新切换到进程A时, 即将执行的指令)。
当CPU将进程A内核态的现在保存完毕时,又自动将进程B对应的tss中的现在信息加载到CPU的寄存器中,
这样CPU就开始执行进程B的指令了。
一段时间后,CPU控制权再次切换到进程A中(此时进程A处于内核态,进程A之前占有CPU的进程X执行了switch_to(B)),
此时cs = 0x0008,eip等于指令cmpl %%ecx,_last_task_used_math/n/t的地址,故而进程A执行指令cmpl %%
ecx,_last_task_used_math,接着执行jne 1f/n/t,clts/n,当执行完clts/n指令后,接着执行ret指令,此时eip等于
ret_from_sys_call的地址,故而函数schedule执行完毕,程序返回到ret_from_sys_call处继续执行。
执行movl _current, %eax,_current指向进程A的struct tast_struct(进程A的任务数据结构),如果是进程A是任务0,则
立即跳出进程A的系统调用中断处理程序;执行cmpw $0x0f,CS(%esp),如果进程A用户态的cs不是普通用户代码段,则退出;
执行cmpw $0x17,OLDSS(%esp),如果进程A用户态堆栈不在用户数据段中,则退出。
当排除了以上可能后,确定了进程A是一个普通的用户态进程(区别于cs=0x08,ds=ss=0x10的进程--内核进程
(这个称呼可能不准确)),然后进行信号量处理,处理完信号量后,执行L121处标号3的代码,进程A的系统调用中断处理程序
全部结束,进程A从内核态返回当用户态,继续执行下一条指令。
附:
switch_to
#define switch_to(n) {\ struct {long a,b;} __tmp; \ __asm__("cmpl %%ecx,_current\n\t" \ "je 1f\n\t" \ "movw %%dx,%1\n\t" \ "xchgl %%ecx,_current\n\t" \ "ljmp %0\n\t" \ "cmpl %%ecx,_last_task_used_math\n\t" \ "jne 1f\n\t" \ "clts\n" \ "1:" \ ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ "d" (_TSS(n)),"c" ((long) task )); \ }
相关文章推荐
- switch_to及ret_from_sys_call控制任务的切换与返回
- switch_to及ret_from_sys_call控制任务的切换与返回
- xenomai 3.0.2 -任务切换《xnarch_switch_to》
- Linux任务切换代码(switch_to)详解
- linux0.11任务切换switch_to
- File System Redirector and Sysnative - how to call 64 bit program from 32 bit application
- Linux任务切换代码(switch_to)详解(转)
- error C2440:cannotconvertfrom 'void (__thiscall CMainFrame::*)'to'LRESULT(__thiscall CWnd::*)
- error C2440: ’static_cast’ : cannot convert from ‘UINT (__thiscall CStaticLink::* )(CPoint)’ to ‘LRE
- error C2440: 'static_cast' : cannot convert from 'void (__thiscall CMainFrame::* )(void)' to 'LRESUL
- 硬件文境的切换 -- __switch_to()
- error C2440: 'static_cast' : cannot convert from 'void (__thiscall CMainFrame::* )(void)' to 'LRESUL
- How to call Visual Basic .NET run-time library members from Visual C#
- 去掉返回键(KEYCODE_BACK)和任务键(KEYCODE_APP_SWITCH)
- Call From SparkMaster/192.168.237.128 to 0.0.0.0:10020 failed on connection exception
- error C2440: 'static_cast' : cannot convert from 'void (__thiscall CTrunkPage::* )(void)' to 'void (__thiscall CCmdTarget::* )(N
- 错误信息:cannot jump from switch statement to this case
- 版本控制:tortoise svn的 revert to this revision和 revert changes from this revision有什么区别?
- 不同特权级间代码段的跳转{ 门 + 跳转(jmp + call) + 返回(ret) }
- ubuntu上运行eclipse出现 Call From master to localhost:9000 failed on connection exception