Patrzyłem na funkcję _do_fork()
() próbując zrozumieć, jak fork()
zwraca PID dziecka dla procesu macierzystego i 0 na proces potomny.W jaki sposób _do_fork() zwraca dwa różne PID (jeden dla procesu nadrzędnego i jeden dla procesu potomnego)
Myślę, że nr
zawiera PID procesu potomnego (który zostanie zwrócony do procesu wywołującego), ale nie widzę, jak jest on w stanie zwrócić 0 do procesu potomnego.
Odpowiedź How does fork() know when to return 0? mówi, że zwracana wartość jest przekazywana na stos utworzony dla nowego procesu, ale (poza tym niezupełnie go rozumiemy) Nie mogę znaleźć tego w kodzie.
Tak, gdzie wartość zwracana 0 jest ustawiona dla procesu potomnego?
Kod funkcji _do_fork()
są kopiowane poniżej:
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;
}
Chcesz zrozumieć kod Linuksa, Niektórzy próbowali, ale mieli problemy. – Stargateur