fork 系统调用代码是怎么写的。我想知道一个函数如何返回两个不同的值以及返回到两个不同的进程的一些细节。总之想知道fork系统调用是怎么实现的?
4 回答
卡尔的回答很棒。我想补充一点,在许多操作系统中,返回值是在其中一个寄存器中传递的。在 x86 架构中,这个寄存器可能是 eax,在 ARM 架构中,这个寄存器可能是 R0,等等。
每个进程还有一个进程控制块 (PCB),它存储在某些中断、系统调用或异常发生并将控制权传递给操作系统时的寄存器值。下一次调度进程时,寄存器的值将从 PCB 中恢复。
现在,当 fork() 发生时,操作系统可以:
child_process->PCB[return_value_register] = 0;
parrent_process->PCB[return_value_register] = child_pid;
因此,当重新安排进程时,每个进程都会看到不同的返回值。
例如,您可以看到xv6 的 fork 实现。在那里,父进程仍处于运行状态,因此它使用简单的 return 语句返回父进程的返回值。但是它将子进程的 EAX 寄存器的值设置为 0,因此当子进程被调度时,它会将 0 视为返回值:
// Clear %eax so that fork returns 0 in the child.
np->tf->eax = 0;
请注意,return 0 也将编译为“mov eax, 0”之类的内容。
更新:我刚刚为我正在做的一个爱好操作系统实现了 fork()。您可以在此处查看源代码。
您已经通过说这是一个系统调用来解释它。完成所有这些工作是操作系统的工作,并且操作系统几乎可以在您的程序上下文或您正在实现它的任何语言的规则之外做它想做的任何事情。这是一个简单的例子发生:
- 程序调用
fork()
系统调用 - 内核fork系统调用复制了运行程序的进程
- 内核为原始程序和副本设置系统调用的返回值(副本的PID和0,分别)
- 内核将两个进程都放入调度程序队列
- 随着每个进程的调度,内核“返回”到两个程序中的每一个。
Ken Thompson 和 Dennis Ritchie 自己对大学的Unix V6源代码手册中的注释进行了注释,描述了双重返回的实际工作原理。评论以以下句子结尾:
你不应该理解这一点。
fork()
例如,通过移动IP/EIP/RIP寄存器在函数中克隆进程以跳过函数中的一些指令,例如:
return pid;
return 0;
第一个进程将执行第一条指令并从堆栈中弹出函数,第二个进程将开始但从第二条指令返回 0。