微信公众号:奔跑吧linux社区
本文节选自《奔跑吧linux内核》第二版卷1第7.3.6章
在用户空间可以使用fork()接口函数来创建一个用户进程,或者使用clone()接口函数来创建一个用户线程,它们在内核空间都是调用_do_fork()函数来实现的。读者常常会对_do_fork()函数的返回感到疑惑,例如以下两个问题。
1. 以fork()接口函数为例,为什么会有两次返回?其中父进程的返回值是子线程的PID,而子进程返回0。子线程是如何返回0的?
2. 子进程第一次返回用户空间时,它是返回到哪里?
对于第一个问题,在调用_do_fork()函数创建子进程后,子进程也会加入内核的调度器里,在调度器中参与调度。子进程会在稍后时刻得到调度和执行,因此fork()函数会有两次返回,一次是父进程的返回,另一次是子进程被调度执行后的返回。
另外,在copy_thread()函数里会复制父进程struct pt_regs栈框的全部内容到子进程的栈框里,这个栈框描述内核栈上保存寄存器的全部信息,以ARM64架构为例,包括X0~X30寄存器、栈指针寄存器、PC寄存器以及PSTATE寄存器等信息。另外,copy_thread()函数还会修改子进程的栈框中X0寄存器的值为0,因此在返回用户空间时子进程的返回值就是0,通过X0寄存器来传递返回值。
copy_thread()函数的代码片段如下。
<arch/arm64/kernel/process.c>
1 int copy_thre