我知道 fork() 在更高级别上做了什么。我想知道的是这个——
一旦有 fork 调用,就会出现一条陷阱指令,并且控制跳转以执行 fork“处理程序”。现在,这个创建子进程的处理程序如何通过创建另一个地址空间和进程控制块来复制父进程,返回 2 个值,每个进程一个?
叉子在什么执行点返回 2 个值?
简而言之,有人可以解释分叉调用后在较低级别发生的分步事件吗?
我知道 fork() 在更高级别上做了什么。我想知道的是这个——
一旦有 fork 调用,就会出现一条陷阱指令,并且控制跳转以执行 fork“处理程序”。现在,这个创建子进程的处理程序如何通过创建另一个地址空间和进程控制块来复制父进程,返回 2 个值,每个进程一个?
叉子在什么执行点返回 2 个值?
简而言之,有人可以解释分叉调用后在较低级别发生的分步事件吗?
这并不难,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 返回时,并且子进程第一次被安排时),它从函数中间开始(即首先执行'如果')。这是一个精确的副本——两个进程都将执行函数的第二部分。
返回给每个进程的值是不同的。父/原线程get的是子进程的PID,子进程get的是0。
Linux 内核在 x86 上通过在复制父进程中的当前线程时更改 eax 寄存器中的值来实现这一点。