我正在查看_do_fork()
函数(),试图了解如何fork()
返回父进程的子PID和子进程的0。
我认为其中nr
包含子进程的PID(将返回给调用者进程),但是我看不到它如何能够向子进程返回0。
答案fork()如何知道何时返回0?表示返回值是在为新流程创建的堆栈上传递的,但是(虽然不是很了解),但是我在代码中找不到。
那么,子进程的返回值0设置在哪里呢?
该_do_fork()
函数的代码复制如下:
long _do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr,
unsigned long tls)
{
struct task_struct *p;
int trace = 0;
long nr;
/*
* Determine whether and which event to report to ptracer. When
* called from kernel_thread or CLONE_UNTRACED is explicitly
* requested, no event is reported; otherwise, report if the event
* for the type of forking is enabled.
*/
if (!(clone_flags & CLONE_UNTRACED)) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_VFORK;
else if ((clone_flags & CSIGNAL) != SIGCHLD)
trace = PTRACE_EVENT_CLONE;
else
trace = PTRACE_EVENT_FORK;
if (likely(!ptrace_event_enabled(current, trace)))
trace = 0;
}
p = copy_process(clone_flags, stack_start, stack_size,
child_tidptr, NULL, trace, tls, NUMA_NO_NODE);
add_latent_entropy();
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
*/
if (!IS_ERR(p)) {
struct completion vfork;
struct pid *pid;
trace_sched_process_fork(current, p);
pid = get_task_pid(p, PIDTYPE_PID);
nr = pid_vnr(pid);
if (clone_flags & CLONE_PARENT_SETTID)
put_user(nr, parent_tidptr);
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
get_task_struct(p);
}
wake_up_new_task(p);
/* forking complete and child started to run, tell ptracer */
if (unlikely(trace))
ptrace_event_pid(trace, pid);
if (clone_flags & CLONE_VFORK) {
if (!wait_for_vfork_done(p, &vfork))
ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
}
put_pid(pid);
} else {
nr = PTR_ERR(p);
}
return nr;
}
您已使用正确标识了如何将新的进程ID返回给父进程return nr
。但是,return 0
由于此代码是在父线程上执行的,所以您将永远看不到任何地方。此代码不适用于创建的新过程。
现在让我们检查一下_do_fork
功能。
...
}
p = copy_process(clone_flags, stack_start, stack_size,
child_tidptr, NULL, trace, tls, NUMA_NO_NODE);
add_latent_entropy();
...
这是所有魔术发生的地方。当您调用copy_process时,它在内部调用copy_thread
目标特定代码。该函数负责处理与线程相关的数据结构。
现在说我们的目标为X86_64,调用约定为在%rax
寄存器中返回返回值。然后,此函数复制0
到(指令指针)中,并将地址%rax
的值复制return_from_fork
到%rip
(指令指针)中。
在其他平台上,ABI可能需要返回值才能进入堆栈。在这种情况下0
,将其放在堆栈上。copy_thread
是特定于目标的,但copy_process
不是。
这是copy_thread
X86_64 的实现。您可以在第160行看到sp寄存器正在设置。在第182行,您可以看到%ax
(它是%rax的子寄存器)被设置为0。
我希望这可以消除一些混乱。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句