Linux sys_exec中可执行文件映射的建立及读取(7)

2020-06-01 00:00:00 函数 执行 进程 中断 也就是

关于schedule和cpu_idle的一些问题:

   1. schedule会从一系列进程中选择合适的进程来运行,假设某一时刻没有合适的进程(在寻找待切换入进程时next时,先将next设置为init_task,然后在runqueue_head运行队列中找合适的进程,找到,就将其赋给next,注意,init_task不会在runqueue_head队列中,没找到,则就是init_task了),则只能选择 init_task,这样便回到了init_task在cpu_idle->schedule()中被换出时的点,由于此时 init_task.need_resched==0,故进入idle(一般为poll_idle函数,在此函数中, init_task.need_resched被设置为-1),此时CPU halt了,直到中断的到来,CPU才会停止halt;
   2. 如果此时来了个中断,则中断处理完毕后返回前,发现current(也就是init_task)的need_resched为-1(!=0),又会主动调用 schedule,在schedule中,首先将current(也就是init_task)的need_resched清零,然后选择合适的进程来运行,如果找不到合适的,则schedule直接就返回了,此时也就是从中断处理中返回,这样又回到了cpu_idle->idle-> halt被中断时的点,再次进行1->2这样的循环;如果schedule找到了另一个合适的进程,则就切换到该进程去运行了, init_task则被挂起在idle->halt被中断时点的那个位置; 


#
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退出并释放该任务;

文章来源CU社区: Linux sys_exec中可执行文件映射的建立及读取

相关文章