卡尔的回答很棒。我想补充一点,在许多操作系统中,返回值是在寄存器之一中传递的。在 x86 架构中,该寄存器可能是 eax,在 ARM 架构中,该寄存器可能是 R0,等等。
每个进程还有一个进程控制块 (PCB),用于存储发生某些中断、系统调用或异常并将控制权传递给操作系统时的寄存器值。下次调度进程时,将从 PCB 恢复寄存器的值。
现在,当 fork() 发生时,操作系统可以执行以下操作:
child_process->PCB[return_value_register] = 0;
parrent_process->PCB[return_value_register] = child_pid;
因此,当重新调度进程时,每个进程都会看到不同的返回值。
作为一个例子,你可以看到xv6 fork 的实现 https://github.com/heapsource/xv6/blob/ff2783442ea2801a4bf6c76f198f36a6e985e7dd/proc.c#L129。在那里,父进程仍然处于运行状态,因此它使用简单的 return 语句返回父进程的返回值。但它将子进程的 EAX 寄存器的值设置为 0,因此当子进程被调度时,它会将 0 视为返回值:
// Clear %eax so that fork returns 0 in the child.
np->tf->eax = 0;
请注意,return 0 也会编译为类似“mov eax, 0”的内容。
Update:我刚刚为我正在做的一个业余爱好操作系统实现了 fork() 。你可以看源码here https://github.com/pykello/arunos/blob/master/kernel/proc/syscall_fork.c.