也即 : 关于pause和fork的内嵌问题
首先,我们要明确的是,不是任务0从main开始执行就不能使用栈,它可以使用栈,比如它按函数方式调用了
trap_init等,这些都会"污染"栈,但是这些栈都在函数返回时被自动清理了.
我们说的任务0不能使用栈,是指在执行fork之前,要保证栈中没有多余的内容.
而由于普通C的调用函数都会用到栈,所以fork才使用汇编的方式被调用 .
但根本原因是:
任务0和任务1都使用同一个栈,此时我们已经不用管它是属于内核还是用户。
总之任务0使用一个栈区,而任务1(一开始也"被迫"使用这个栈区)。
在任务0在用户栈调用 fork时,如果以普通函数调用的方式,那么此时用户栈中肯定会被以下内容"污染"
Fork后原下一条指令的地址
任务0的栈顶ebp ?----- 新的esp栈
然后中断到系统调用 fork中去。
而forkà copy_process 中
将把旧任务(即任务0)的所有寄存器内容(包括栈相关的SS:ESP)都复制给任务1
而虽然现在没有真正在主内存中给任务1分配物理内存空间,但这会在将来能过Copy-on-write的方式来复制到主内存,创建任务1的栈
接着fork调用完了后,返回。但是由于fork本身也是一个系统调用 ,只要是系统调用返回时都会进行schedule检查。
所以内核并不能保证fork返回后,任务0和任务1哪个先执行。
如果任务1先执行,并且它进行了栈操作。则产生page fault,进行copy-on-write,然后任务1的真正的用户栈被建立 ,但是建立是以先复制任务0的栈为前提的
而此时任务0的栈中有上面提到的"污染"内容在里面。
如果任务0先执行,那么在fork返回后,虽然任务0将它的栈"清空",但是紧接着任务0会执行pause调用 ,如果还是以函数的方式,则在任务0调用pause返回前,如果不巧,进行了schedule到任务1,任务1又使用了栈的话,又会造成上面的情况。