分析基于内核版本2.6.12.6
在什么情况下,会触发调度?
Linux进程的调度主要分为主动调度和被动调度两大类。
◆主动调度
主动调度就是进程自己缺少相应的所申请的资源,显示调用schedule,让出处理器。
◆被动调度
在整个linux运行过程中,被动调度又可细分为两种:
●用户态抢占调度
●内核态抢占调度
下面就结合内核代码分析上述各种调度时机的详细情况。
被动调度
整个linux运行过程中,被动调度分为用户态抢占调度和内核态抢占调度。
用户态抢占调度
用户态抢占调度发生在当系统调用、中断处理、异常处理等返回用户态时,或者进程的时间片用完时。
系统调用返回
当一个进程由于系统调用进入内核态,在系统调用处理完,返回用户态时,是一个调度点。这个时候会检测有没有设置TIF_NEED_RESCHED标志。下面分析下内核中系统调用返回相关的代码片段。
上面代码片段是系统调用的入口。这个系统调用的入口是在syscall_init函数里调用wrmsrl(MSR_LSTAR,system_call)设置的,通过一个MSR寄存器来保存系统调用的地址,而不再像I386架构下面是通过中断。
用户进程和内核都使用
x8664_pda
SAVE_ARGS宏主要是将一些寄存器压栈。
下面接着分析系统调用代码:
.globlret_from_sys_call
ret_from_sys_call:
sysret_check:
sysret_careful*/
swapgs
sysretq
/*Handlereschedules*/
sysret_careful:
TIF_NEED_RESCHED标志*/
sti
pushq%rdi
popq%rdi
上面代码是系统调用后的处理部分。在处理完系统调用返回用户态前,首先检查是否还有其他工作需要完成,如果有其他工作,则跳转到
sysret_careful开始就检测是否有设置TIF_NEED_RESCHED标志,如果没有设置此标志,则跳转到sysret_signal标签处执行。如果有设置此标志,则首先开中断,然后调用schedule函数。
下面接着分析sysret_signal标签处的代码:
sysret_signal:
jz1f
/*Reallyasignal*/
/*edx:workflags(arg3)*/
callptregscall_common
1:movl$_TIF_NEED_RESCHED,%edi
jmpsysret_check
上面代码片段是处理信号部分代码。首先检测是否有信号需要处理,有信号处理的情况下,将do_notify_resume函数的地址赋给ptregscall_common函数处执行。在ptregscall_common中会调用call*%rax,,进入do_notify_resume函数执行。
下面是上面分析的系统调用相关代码的流程图。
图-systemcall流程图
图-ret_from_sys_call流程图
版权声明:本文为博主原创文章,未经博主允许不得转载。
最美不过偷瞄你是你忽然转头,看见你的微笑