我知道fork()在较高的层次上是什么。我想知道的是:
一旦有一个fork调用,就会跟随一个陷阱指令,并控制跳转执行fork“处理程序”。现在,这个处理程序如何通过创建另一个地址空间和进程控制块来复制父进程来创建子进程并返回2个值,每个进程一个值?
在执行的哪个时刻,fork会返回2个值?
简而言之,可以有人解释一下在fork调用后,在较低层次上发生的步骤事件吗?
我知道fork()在较高的层次上是什么。我想知道的是:
一旦有一个fork调用,就会跟随一个陷阱指令,并控制跳转执行fork“处理程序”。现在,这个处理程序如何通过创建另一个地址空间和进程控制块来复制父进程来创建子进程并返回2个值,每个进程一个值?
在执行的哪个时刻,fork会返回2个值?
简而言之,可以有人解释一下在fork调用后,在较低层次上发生的步骤事件吗?
这并不难 - fork() 系统调用的内核半部分可以通过进程控制块区分两个进程,但你甚至不需要这样做。因此,伪代码如下:
int fork()
{
int orig_pid = getpid();
int new_pid = kernel_do_fork(); // Now there's two processes
// Remember, orig_pid is the same in both procs
if (orig_pid == getpid()) {
return new_pid;
}
// Must be the child
return 0;
}
编辑: 简单版本的实现正如您所描述的那样——它创建一个新的进程上下文,复制所有相关的线程上下文、复制所有页面和文件映射,并将新进程放入“准备运行”列表中。
我认为您混淆的部分是,当这些进程恢复时(即当父进程从kernel_do_fork返回并且子进程第一次被调度时),它会在函数的中间开始执行(即执行第一个'if')。这是一个精确的副本——两个进程都将执行函数的后半部分。
每个进程返回的值都不同。父/原始线程获得子进程的PID,而子进程获得0。
在x86上,Linux内核通过在父进程中复制当前线程时更改eax寄存器中的值来实现这一点。