- 论坛徽章:
- 0
|
回复 #17 frank_seng 的帖子
#
Linux kernel启动时第一次进入cpu_idle的简单分析,下图为其流程图,从图中可知,由于current(也就是init_task)的need_resched现在等于1,故立刻开始执行schedule();
|
+-------------->|
| +------------>|
| | v
| | _,,-,,_
| | ,,.-'`` ``'-.,,
| | current->need_resched==0? ---+
| | `'-.,, ,,.-'`` |
| | ``'--'`` | N
| | Y| |
| | v v
| | +--------------+ +--------------+
| | | idle() | | schedule() |
| | +--------------+ +--------------+
| | | |
| +-------------+ |
+--------------------------------+
- 现在就两个进程:init_task和new_task(init),很显然schedule->switch_to会选中new_task开始执行,同时将init_task.need_resched置0;
- new_task 的esp、eip在(3)中已经被设置好了,故esp寄存器被恢复为new_task->thread.esp,也就是 union2.pt_regs底部;eip寄存器被恢复为new_task->thread.eip也就是ret_from_fork, new_task从ret_from_fork处开始执行,由于new_task系统堆栈中保存的用于返回的EIP是从原来的init_task中复制过来的,而且new_task->need_resched=0,因此new_task返回到kernel_thread中;
- 随后在kernel_thread中,此时将esp和esi比较(esi中保存的是刚进kernel_thread时的esp),对于new_task而言,很明显,这里是不相等的,esp为new_task堆栈指针地址,esi为init_task堆栈指针地址;
- 执行函数init(),在init中会执行execve("/sbin/init")【内核中的execve宏定义见_syscall3】,也就是 sys_excve("/sbin/init),new_task完全被/sbin/init替代,其永远不会再回到kernel_thread了,在 sys_execve中会构造用户空间,/sbin/init也会启动一些列应用层初始化进程,系统主要起始进程启动成功;
- 关于kernel_thread需要说明的是:如果这里不是init()函数,而是一个普通函数,则kernel_thread在执行完该普通函数后,执行sys_exit退出并释放该任务;
|
|