Linux0.11分析之创建进程


Linux0.11 中父进程创建子进程的通用模式如下所示。

Father :

……

if (!(pid = fork ()))

{

……

(子进程执行部分)

}

……

(父进程执行部分)

为什么父进程和子进程的执行路径会是这样?

大二孙志岗老师讲操作系统课程的时候,我就对这个问题非常纳闷,时隔两年多啊,现在才搞清楚了,感慨颇多啊。

大家都知道,对于父进程 fork 返回子进程号,对于子进程 fork 返回 0 ,这也是执行路径如此的原因所在。但是, fork 的返回不同值的原因又是什么,这就得看 fork 的实现了。

fork 先是调用 find_empty_process 为子进程找到一个空闲的任务号,然后调用 copy_process 复制进程, fork 返回 copy_process 的返回值 last_pid ,也就是子进程号。

从上面的实现看来, fork 的返回值不会是 0 , last_pid 从 1 开始,父进程执行 if 外面的部分,上面的逻辑正是父进程的执行逻辑。

对于子进程,先看子进程的初始状态, copy_process 中创造了子进程的上下文执行环境,这个上下文环境正是父进程 fork 系统调用时的环境,其中, p->tss.eip 正是被赋值为 fork 之后下一条指令地址,这就是子进程和父进程都返回到 fork 下一条指令处的原因。同时,需要注意的是, p->tss.eax 被赋了值 0 ,当调度到子进程开始执行时,首先加载其上下文环境, eip 被加载为 fork 之后下一条指令, eax 就被加载为 0 ,所以,对于子进程来说,和父进程唯一的区别就是返回值( eax )为 0 ,子进程执行 if 里面的部分。

关于父进程堆栈变化以及子进程上下文建立情况,请参考下图。

之所以造成这样一个函数的不同代码段被两个进程执行,是和 linux0.11 的内核创建进程实现相关的,像一些嵌入式实时系统就不是这样的,比如 vxworks 、 ucos ,它们在创建子进程时是指定一个函数入口作为子进程入口,这个函数入口就是子进程代码实现,然后完全初始化一个新的上下文环境,而不是继承父进程正执行的上下文环境,这样的实现逻辑上要比 Linux 的清晰些。

相关内容