VI: WAIT4 () system call
In the parent process, the WAIT4 () can be used to get the exit status of the child process and prevent the child process from exiting the zombie state before the parent process exits. This is the last section of our analysis.
About WAIT4 () in user space to call the way you can refer to the relevant data, here is only to discuss the kernel of this system call implementation process.
The system call entry for WAIT4 () is SYS_WAIT4 (). The code looks like this:
Asmlinkage long SYS_WAIT4 (pid_t pid, int __user *stat_addr,
int options, struct rusage __user *ru)
{
long ret;
The sign of the options is a combination of wnohang...__wall, otherwise the
action of the relevant flag will be do_wait () to analyze
if (Options & ~ (wnohang| wuntraced| wcontinued|
__wnothread|__wclone|__wall))
Return-einval;
ret = do_wait (PID, Options | wexited, NULL, stat_addr, RU);
/* Avoid regparm breakage on x86: * *
Prevent_tail_call (ret);
return ret;
}
Do_wait () is one of the core processing functions. The code is as follows:
Static long do_wait (pid_t pid, int options, struct siginfo __user *infop, int __user *stat_addr, struct rusage
Ser *ru) {//initialization of a wait queue declare_waitqueue (waiting, current);
struct Task_struct *tsk;
int flag, retval;
int allowed, denied;
Adds the current process to the wait queue, and the child process exits to send a signal to the parent process wake up some waiting queues Add_wait_queue (&current->signal->wait_chldexit,&wait);
Repeat:flag = 0;
allowed = denied = 0;
Sets the process state to task_interruptible. The next schedule must wait until the child process wakes up. Current->state = task_interruptible;
Read_lock (&tasklist_lock);
Tsk = current;
Do {struct task_struct *p;
struct List_head *_p;
int ret;
The subprocess under the traversal process List_for_each (_p,&tsk->children) {p = list_entry (_p, struct task_struct, sibling);
To determine whether we are going to wait for the subprocess of the process ret = Eligible_child (PID, Options, p);
if (!ret) continue;
if (Unlikely (Ret < 0)) {denied = ret;
Continue
} allowed = 1; Switch (p-> state) {//subprocess is task_traced. That is, it is being tracked.
Then the relevant information of the fetch subprocess case task_traced:flag = 1; Determines whether a subprocess is tracked by the parent process//or returns 1 if it is.
Not return 0 if (!my_ptrace_child (p)) continue;
/*fallthrough*/case task_stopped:flag = 1; Wuntraced: The subprocess is stopped and immediately returns//does not define the wuntraced parameter. Continue traversing subprocess/* This is seen. A biological father process is a subprocess that does not handle the stop state. Only the incoming trace is initiated. The process will be * * * if (!
Options & wuntraced) &&!my_ptrace_child (p)) continue;
Wnowait: The exit state of the zombie subprocess is not revoked//the next time the Wait series function is called, the exit state can be continued retval = Wait_task_stopped (p, ret = 2,
(Options & Wnowait), Infop, stat_addr, RU);
if (retval = =-eagain) goto repeat; if (retval!= 0)/* He released the lock.
* * Goto END;
Break Default://Case Exit_dead://No need to process DEAD status if (p->exit_state = = Exit_dead) continue;
Case Exit_zombie://subprocess is zombie state if (p->exit_state = = Exit_zombie) {if (ret = 2)
Goto check_continued;
if (!likely (Options & wexited)) continue;
retval = Wait_task_zombie (p, Options & wnowait), Infop, stat_addr, RU); /* He released the lock.
*/if (retval!= 0) goto end;
Break } check_continued: * * * running now, so it might later * exit, stop, or stop and then C
Ontinue.
* * flag = 1;
Wcontinued: reports the status of any child processes that continue to run the specified process number (!unlikely (Options & wcontinued)) continue; Take the relevant state of the process retval = wait_task_continued (p, Options & wnowait), Infop, stat_addr, Ru)
; if (retval!= 0)/* He released the lock.
*/ Goto end;
Break }//Traversal of the child processes being traced//can be seen from here. If a subprocess is tracked. Then the exit//operation of the subprocess is not performed by the biological father process if (!flag) {List_for_e
Ach (_p, &tsk->ptrace_children) {p = list_entry (_p, struct task_struct, ptrace_list);
if (!eligible_child (PID, Options, p)) continue;
flag = 1;
Break
} if (Options & __wnothread) break;
It is also possible that the threads in the process tsk = Next_thread (tsk) of the fork of the thread in the wait.
bug_on (tsk->signal!= current->signal);
while (tsk!= current);
Read_unlock (&tasklist_lock);
if (flag) {retval = 0;
If Whnohang is defined: immediately exit if (Options & Wnohang) goto end;
retval =-erestartsys;
if (signal_pending) goto end;
Schedule ();
Goto repeat;
} retval =-echild;
if (unlikely (denied) &&!allowed) retval = denied; End://Set process to run state, remove current->s from wait queueTate = task_running;
Remove_wait_queue (&current->signal->wait_chldexit,&wait);
if (INFOP) {if (retval > 0) retval = 0; else {/* * for a Wnohang return, clear out all the fields * we would set so user can easily tell
The * difference.
*/if (!retval) retval = Put_user (0, &infop->si_signo);
if (!retval) retval = Put_user (0, &infop->si_errno);
if (!retval) retval = Put_user (0, &infop->si_code);
if (!retval) retval = Put_user (0, &infop->si_pid);
if (!retval) retval = Put_user (0, &infop->si_uid);
if (!retval) retval = Put_user (0, &infop->si_status);
} return retval; }