我知道fork()对子进程和父进程的返回方式不同,但我无法找到有关如何发生这种情况的信息.子进程如何从fork接收返回值0?有关调用堆栈的区别是什么?据我了解,对于父母来说,它是这样的:
parent进程 - 调用fork - > system_call - 调用fork - > fork执行 - 返回 - > system_call - 返回 - > parent进程.
儿童过程会发生什么?
Ste*_*ker 23
%man fork
返回值
Run Code Online (Sandbox Code Playgroud)Upon successful completion, fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent process. Otherwise, a value of -1 is returned to the parent process, no child process is created, and the global variable [errno][1] is set to indi- cate the error.
发生的事情是在fork系统调用中,整个过程是重复的.然后,每个fork调用返回.现在这些是不同的上下文,因此它们可以返回不同的返回码.
如果您真的想知道它在低级别的工作原理,您可以随时查看来源!如果你不习惯阅读内核代码,代码有点混乱,但是内联注释提供了一个很好的提示,告诉你发生了什么.
对你的问题有明确答案的源代码中最有趣的部分是fork()定义本身的最后一部分 -
if (error == 0) {
td->td_retval[0] = p2->p_pid;
td->td_retval[1] = 0;
}
Run Code Online (Sandbox Code Playgroud)
"td"显然包含不同线程的返回值列表.我不确定这个机制是如何工作的(为什么没有两个独立的"线程"结构).如果错误(从fork1返回,"真正的"分叉函数)为0(无错误),则取"第一个"(父)线程并将其返回值设置为p2(新进程)的PID.如果它是"第二个"线程(在p2中),则将返回值设置为0.
该fork()系统调用返回两次(除非它失败).
其中一个返回在子进程中,返回值为0.
另一个返回在父进程中,并且返回值为非零(如果fork失败则为负数,或者指示子项的PID的非零值).
父母和孩子之间的主要区别是:
POSIX标准中列出了其他更加模糊的差异.
在某种意义上,如何真的不是你的问题.操作系统需要达到结果.然而,O/S的克隆父进程,使得第二子方法,该方法是父的几乎精确的复制品,设定必须是正确的新值的不同的属性,且通常为标记数据页为CoW的(复制上写入)或等效的,以便当一个进程修改一个值时,它获得一个单独的页面副本,以免干扰另一个.这与被弃用的(至少我 - 非标准的POSIX)vfork()系统调用不同,即使它在您的系统上可用,您也应该避免使用它.每个进程fork()在函数返回之后继续- 所以(正如我上面所说的那样),fork()系统调用返回两次,两次进程中的每一次都是一次,这两个进程几乎是彼此相同的克隆.
小智 7
由于在子上下文中操作CPU寄存器,父和子都返回不同的值.
linux内核中的每个进程都由task_struct表示.task_struct在thread_info结构中被包含(指针),该结构位于内核模式堆栈的末尾.所有CPU上下文(寄存器)都存储在此thread_info结构中.
struct thread_info {
struct task_struct *task; /* main task structure */
struct cpu_context_save cpu_context; /* cpu context */
}
Run Code Online (Sandbox Code Playgroud)
所有fork/clone()系统调用都调用内核等效函数do_fork().
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
Run Code Online (Sandbox Code Playgroud)
这是执行的顺序
do_fork() - > copy_process-> copy_thread() (copy_thread是特定于arch的函数调用)
copy_thread()从父项复制寄存器值并将返回值更改为0(如果是arm)
struct pt_regs *childregs = task_pt_regs(p);
*childregs = *regs; /* Copy register value from parent process*/
childregs->ARM_r0 = 0; /*Change the return value*/
thread->cpu_context.sp = (unsigned long)childregs;/*Write back the value to thread info*/
thread->cpu_context.pc = (unsigned long)ret_from_fork;
Run Code Online (Sandbox Code Playgroud)
当孩子被安排时,它执行一个程序集例程ret_from_fork(),它将返回零.对于父级,它从do_fork()获取返回值,该值是进程的pid
nr = task_pid_vnr(p);
return nr;
Run Code Online (Sandbox Code Playgroud)