564 lines
13 KiB
Groff
564 lines
13 KiB
Groff
'\"macro stdmacro
|
|
.if n .pH g2.wait @(#)wait 30.2 of 12/25/85
|
|
.TH WAIT 2
|
|
.Op c p a
|
|
.SH NAME
|
|
wait, waitpid, wait3 \- wait for child processes to stop or terminate
|
|
.SH C SYNOPSIS
|
|
\f4#include <sys/types.h>\fP
|
|
.br
|
|
\f4#include <sys/wait.h>\fP
|
|
.PP
|
|
\f4pid_t wait (int \(**statptr);\fP
|
|
.br
|
|
\f4pid_t waitpid (pid_t pid, int \(**statptr, int options);\fP
|
|
.PP
|
|
\f4#include <sys/types.h>\fP
|
|
.br
|
|
\f4#include <sys/wait.h>\fP
|
|
.br
|
|
\f4#include <sys/resource.h>\fP
|
|
.PP
|
|
\f4pid_t wait3 (int \(**statptr, int options, struct rusage \(**rusage);\fP
|
|
.Op
|
|
.Op f
|
|
.SH NAME
|
|
wait \- wait for child processes to stop or terminate
|
|
.SH FORTRAN SYNOPSIS
|
|
.nf
|
|
.B integer function wait (status)
|
|
.B integer status
|
|
.Op
|
|
.fi
|
|
.SH DESCRIPTION
|
|
\f4wait\f1
|
|
suspends the calling process until
|
|
one of the immediate children
|
|
terminate, or until a child that is
|
|
being traced stops because it has hit an event of interest.
|
|
The \f4wait\f1 will return
|
|
prematurely if a signal is received.
|
|
If all child processes stopped or terminated prior to the call
|
|
on \f4wait\f1,
|
|
return is immediate.
|
|
.PP
|
|
If the call is successful, the process
|
|
.SM ID
|
|
of a child is returned.
|
|
.Op c p a
|
|
.PP
|
|
\f4wait3\f1
|
|
is \s-1BSD\s+1's extension of
|
|
\f4wait\f1.
|
|
It provides an alternate interface for programs
|
|
that must not block when collecting the status
|
|
of child processes.
|
|
.PP
|
|
\f4waitpid\f1
|
|
is \s-1POSIX\s+1's extension of
|
|
\f4wait\f1.
|
|
The
|
|
\f4pid\f1
|
|
argument specifies a set of child processes for which status is
|
|
requested.
|
|
\f4waitpid\f1
|
|
only returns the status of a child process from this set.
|
|
.Op
|
|
.SH PARAMETERS
|
|
.PP
|
|
.B statptr (all functions):
|
|
If
|
|
.I statptr\^
|
|
is non-zero, 16 bits of information called
|
|
.I status
|
|
are stored in the low-order 16 bits of the location pointed to by
|
|
.IR statptr.
|
|
.I Status\^
|
|
may be evaluated with the
|
|
macros described on \f4wstat\fP(5).
|
|
.I Status\^
|
|
can be used to differentiate between stopped and terminated child
|
|
processes. If the child process terminated,
|
|
\f2status\f1
|
|
identifies the cause of termination
|
|
and passes useful information to the parent.
|
|
\f2status\f1
|
|
is interpreted as follows:
|
|
.IP
|
|
If the child process stopped,
|
|
the predicate
|
|
.BR \s-1WIFSTOPPED\s0 (\(**\f2statptr\fP)
|
|
will evaluate to non-zero and
|
|
.BR \s-1WSTOPSIG\s0 (\(**\f2statptr\fP)
|
|
will return the signal number that caused the process to stop.
|
|
(The high-order 8 bits of \f2status\f1 will
|
|
contain the signal number and
|
|
the low-order 8 bits are set equal to \f4WSTOPFLG\fP.)
|
|
.IP
|
|
If the child process terminated due to an
|
|
\f4exit\f1
|
|
call, the predicate
|
|
.BR \s-1WIFEXITED\s0 (\(**\f2statptr\fP)
|
|
will evaluate to non-zero, and
|
|
.BR \s-1WEXITSTATUS\s0 (\(**\f2statptr\fP)
|
|
will return the argument that the child process passed to
|
|
\f4_exit\f1 or \f4exit\f1,
|
|
or the value the child process returned from
|
|
.I main
|
|
[see
|
|
.IR exit (2)].
|
|
(The low-order 8 bits of \f2status\f1 will be zero and the
|
|
high-order 8 bits
|
|
will contain the low-order 8 bits of the argument that the child process
|
|
passed to \f4exit\f1.)
|
|
.IP
|
|
If the child process terminated due to a signal,
|
|
the predicate
|
|
.BR \s-1WIFSIGNALED\s0 (\(**\f2statptr\fP)
|
|
will evaluate to non-zero, and
|
|
.BR \s-1WTERMSIG\s0 (\(**\f2statptr\fP)
|
|
will return the signal number that caused the termination.
|
|
(The high-order 8 bits of \f2status\f1 will be zero and the low-order 8 bits
|
|
will contain the number of the signal.)
|
|
In addition, if \f4WCOREFLG\fP is set,
|
|
a ``core image'' will have been produced [see
|
|
.IR signal (2)].
|
|
.Op c p a
|
|
.PP
|
|
.B rusage (wait3):
|
|
If
|
|
.I rusage
|
|
non-zero, a summary of the resources used by the terminated
|
|
process and all its
|
|
children is returned (this information is currently not available
|
|
for stopped processes).
|
|
.PP
|
|
.B pid (waitpid):
|
|
.IP
|
|
1) If
|
|
.I pid
|
|
is equal to \-1, status is requested for any child process.
|
|
In this
|
|
respect,
|
|
\f4waitpid\f1
|
|
is then equivalent to
|
|
\f4wait\f1.
|
|
.IP
|
|
2) If
|
|
\f2pid\f1
|
|
is greater than zero, it specifies the process
|
|
.SM ID
|
|
of a single
|
|
child process for which status is requested.
|
|
.IP
|
|
3) If
|
|
\f2pid\f1
|
|
is equal to zero, status is requested for any child process whose
|
|
process group
|
|
.SM ID
|
|
is equal to that of the calling process.
|
|
.IP
|
|
4) If
|
|
\f2pid\f1
|
|
is less than \-1, status is requested for any child process whose
|
|
process group
|
|
.SM ID
|
|
is equal to the absolute value of
|
|
\f2pid\f1.
|
|
.PP
|
|
.B options (waitpid and wait3):
|
|
The
|
|
.I options argument
|
|
is constructed from the bitwise inclusive
|
|
.SM OR
|
|
of zero or more of the following flags, defined in the header
|
|
.RI < sys/wait.h >:
|
|
.TP 15
|
|
\%WNOHANG
|
|
The
|
|
function will not suspend execution of the calling process if status is
|
|
not immediately available for one of the child processes.
|
|
.TP
|
|
\%WUNTRACED
|
|
The status of child processes
|
|
that are stopped
|
|
due to a
|
|
.BR \s-1SIGTTIN\s0 ,
|
|
.BR \s-1SIGTTOU\s0 ,
|
|
.BR \s-1SIGTSTP\s0 ,
|
|
or
|
|
.B \s-1SIGSTOP\s0
|
|
signal,
|
|
and whose status has not yet been reported since they
|
|
stopped, are reported to the requesting process.
|
|
.PP
|
|
If a parent process terminates without waiting for its child processes
|
|
to terminate, the parent process
|
|
.SM ID
|
|
of each child process is set to 1.
|
|
This means the initialization process inherits the child processes [see
|
|
.IR intro (2)].
|
|
.Op
|
|
.SH SIGCLD HANDLING
|
|
.SM IRIX
|
|
has three distinct version of signal routines: System V (\f4signal\fP(2)
|
|
and \f4sigset\fP(2)),
|
|
4.3\c
|
|
.SM BSD
|
|
(\f4signal\fP(3B) and \f4sigvec\fP(3B)),
|
|
and
|
|
.SM POSIX
|
|
(\f4sigaction\fP(2)).
|
|
Each version has a method by which
|
|
a parent can be certain that it waits on all of its children even
|
|
if they are executing concurrently.
|
|
In each version, the parent installs a signal handler for
|
|
.B \s-1SIGCLD\s0
|
|
to wait for its children, but the specific code differs in subtle,
|
|
albeit vital, ways.
|
|
Sample programs below are used to illustrate each of the three methods.
|
|
.PP
|
|
Note that System V refers to this signal as
|
|
.BR \s-1SIGCLD\s0 ,
|
|
whereas
|
|
.SM BSD
|
|
calls it
|
|
.BR \s-1SIGCHLD\s0 .
|
|
For compatibility with both systems they
|
|
are defined to be the same signal number, and may therefore
|
|
be used interchangeably.
|
|
.\"-----------------------------------
|
|
.PP
|
|
\f3System V:\fP System V's
|
|
.B \s-1SIGCLD\s0
|
|
mechanism guarantees that no
|
|
.B \s-1SIGCLD\s0
|
|
signals will be lost.
|
|
It accomplishes this by forcing the process to reinstall the handler
|
|
(via \f4signal\fP or \f4sigset\fP calls) when leaving the handler.
|
|
Note that whereas \f4signal\fP(2) sets the signal disposition back to
|
|
.B \s-1SIG_DFL\s0
|
|
each time the handler is called, \f4sigset\fP(2) keeps it installed, so
|
|
.B \s-1SIGCLD\s0
|
|
is the only signal that demands this reinstallation,
|
|
and that only because the installation call allows the kernel to check
|
|
for additional instances of the signal that occurred while the
|
|
process was executing in the handler.
|
|
.Op c p a
|
|
The code below is the System V example.
|
|
Note that the \f4sigpause\fP(2) creates a window during which
|
|
.B \s-1SIGCLD\s0
|
|
is not blocked, allowing the parent to enter its handler.
|
|
.\"-----------------------------------
|
|
.PP
|
|
.Ex
|
|
/*
|
|
* System V example of wait-in-SIGCLD-handler usage
|
|
*/
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <sys/wait.h>
|
|
|
|
static void handler(int);
|
|
|
|
#define NUMKIDS 4
|
|
volatile int kids = NUMKIDS;
|
|
|
|
main()
|
|
{
|
|
int i, pid;
|
|
|
|
sigset(SIGCLD, handler);
|
|
sighold(SIGCLD);
|
|
for (i = 0; i < NUMKIDS; i++) {
|
|
if (fork() == 0) {
|
|
printf("Child %d\en", getpid());
|
|
exit(0);
|
|
}
|
|
}
|
|
while (kids > 0) {
|
|
sigpause(SIGCLD);
|
|
sighold(SIGCLD);
|
|
}
|
|
}
|
|
|
|
static void
|
|
handler(int sig)
|
|
{
|
|
int pid, status;
|
|
|
|
printf("Parent (%d) in handler, ", getpid());
|
|
pid = wait(&status);
|
|
kids--;
|
|
printf("child %d, now %d left\en", pid, kids);
|
|
/*
|
|
* Now reinstall handler & cause SIGCLD to be re-raised
|
|
* if any more children exited while we were in here.
|
|
*/
|
|
sigset(SIGCLD, handler);
|
|
}
|
|
.Ee
|
|
.PP
|
|
.SM
|
|
\f3BSD:\fP
|
|
4.3\c
|
|
.SM BSD
|
|
solved this problem differently: instead of
|
|
guaranteeing that no
|
|
.B \s-1SIGCHLD\s0
|
|
signals are lost, it provides a
|
|
.SM
|
|
.B WNOHANG
|
|
option to \f4wait3\fP
|
|
that allows parent processes to do non-blocking waits in loops,
|
|
until no more stopped or zombied children exist.
|
|
Note that the handler must be able to deal with the case
|
|
in which no applicable children exist; if one or
|
|
more children exit while the parent is in the handler, all may get
|
|
reaped, yet if one or more
|
|
.B \s-1SIGCHLD\s0
|
|
signals arrived while the parent was in its handler,
|
|
the signal will remain pending, the parent will
|
|
reenter the handler, and the \f4wait3\fP call will return 0.
|
|
Note that it is not necessary to call \f4sigvec\fP upon exit from the
|
|
handler.
|
|
.PP
|
|
.Ex
|
|
/*
|
|
* BSD example of wait3-in-SIGCHLD handler usage
|
|
*/
|
|
|
|
#define _BSD_SIGNALS
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <sys/wait.h>
|
|
|
|
static int handler(int);
|
|
|
|
#define NUMKIDS 4
|
|
volatile int kids = NUMKIDS;
|
|
|
|
main()
|
|
{
|
|
int i, pid;
|
|
struct sigvec vec;
|
|
|
|
vec.sv_handler = handler;
|
|
vec.sv_mask = sigmask(SIGCHLD);
|
|
vec.sv_flags = 0;
|
|
|
|
sigvec(SIGCHLD, &vec, NULL);
|
|
sigsetmask(sigmask(SIGCHLD));
|
|
for (i = 0; i < NUMKIDS; i++) {
|
|
if (fork() == 0) {
|
|
printf("Child %d\en", getpid());
|
|
exit(0);
|
|
}
|
|
}
|
|
while (kids > 0) {
|
|
sigpause(0);
|
|
}
|
|
}
|
|
|
|
static int
|
|
handler(int sig)
|
|
{
|
|
int pid;
|
|
int status;
|
|
|
|
printf("Parent (%d) in handler, ", getpid());
|
|
while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
|
|
kids--;
|
|
printf("child %d, now %d left\en", pid, kids);
|
|
}
|
|
}
|
|
.Ee
|
|
.PP
|
|
\f3POSIX:\fP
|
|
.SM POSIX
|
|
improved on the
|
|
.SM BSD
|
|
method by providing
|
|
\f4waitpid\fP,
|
|
that allows a parent to wait on a particular child process if
|
|
desired.
|
|
In addition, the
|
|
.SM IRIX
|
|
implementation of \f4sigaction\fP(2)
|
|
checks for zombied children upon exit from the system call
|
|
if the specified signal was
|
|
.B \s-1SIGCLD\s0
|
|
and the disposition of the signal handling was changed.
|
|
If zombied children exist, another
|
|
.B \s-1SIGCLD\s0
|
|
is raised.
|
|
This solves the problem that occurs when a
|
|
parent creates children, but a module that it links with (typically
|
|
a libc routine such as \f4system\fP(3)) creates and waits on its own children.
|
|
.PP
|
|
Two problems have classically arisen in such a scheme: 1) until the advent of
|
|
\f4waitpid\f1,
|
|
the called routine could not specify which children to wait on;
|
|
it therefore looped, waiting and discarding children until the
|
|
one (or ones) it had created terminated, and 2) if the called routine
|
|
changed the disposition of
|
|
.B \s-1SIGCLD\s0
|
|
and then restored the previous handler upon exit, children
|
|
of the parent (calling) process that had terminated while the called
|
|
routine executed would be missed in the parent, because the called routine's
|
|
.B \s-1SIGCLD\s0
|
|
handler would reap and discard those children.
|
|
The addition of
|
|
\f4waitpid\f1
|
|
and the
|
|
.SM IRIX
|
|
implementation of
|
|
\f4sigaction\f1
|
|
solves both of these problems.
|
|
Note that neither the
|
|
.SM BSD
|
|
nor the System V signal routines on
|
|
.SM IRIX
|
|
have these properties,
|
|
in the interests of compatibility.
|
|
.PP
|
|
.SM WARNING:
|
|
programs that install
|
|
.B \s-1SIGCLD\s0
|
|
handlers that set flags instead of executing \f4waitpid\fPs and then
|
|
attempt to restore the previous signal handler (via \f4sigaction\fP)
|
|
upon return from the handler will create infinite loops.
|
|
.PP
|
|
.Ex
|
|
/*
|
|
* POSIX example of waitpid-in-SIGCHLD handler usage
|
|
*/
|
|
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <sys/wait.h>
|
|
|
|
static void handler(int);
|
|
|
|
#define NUMKIDS 4
|
|
volatile int kids = NUMKIDS;
|
|
|
|
/*
|
|
* If waitpid's 1st argument is -1, it waits for any child.
|
|
*/
|
|
#define ANYKID -1
|
|
|
|
main()
|
|
{
|
|
int i;
|
|
pid_t pid;
|
|
struct sigaction act;
|
|
sigset_t set, emptyset;
|
|
|
|
act.sa_handler = handler;
|
|
sigemptyset(&act.sa_mask);
|
|
sigaddset(&act.sa_mask, SIGCHLD);
|
|
act.sa_flags = 0;
|
|
|
|
sigaction(SIGCHLD, &act, NULL);
|
|
sigemptyset(&set);
|
|
sigemptyset(&emptyset);
|
|
sigaddset(&set, SIGCHLD);
|
|
sigprocmask(SIG_BLOCK, &set, NULL);
|
|
setbuf(stdout, NULL);
|
|
|
|
for (i = 0; i < NUMKIDS; i++) {
|
|
if (fork() == 0) {
|
|
printf("Child %d\en", getpid());
|
|
exit(0);
|
|
}
|
|
}
|
|
while (kids > 0) {
|
|
sigsuspend(&emptyset);
|
|
}
|
|
}
|
|
|
|
static void
|
|
handler(int sig)
|
|
{
|
|
pid_t pid;
|
|
int status;
|
|
|
|
printf("Parent (%d) in handler, ", getpid());
|
|
pid = waitpid(ANYKID, &status, WNOHANG);
|
|
while (pid > 0) {
|
|
kids--;
|
|
printf("child %d, now %d left\en", pid, kids);
|
|
pid = waitpid(ANYKID, &status, WNOHANG);
|
|
}
|
|
}
|
|
.Ee
|
|
.Op
|
|
.SH DIAGNOSTICS
|
|
\f4wait\f1
|
|
fails and its actions are undefined if
|
|
\f2statptr\f1
|
|
points to an invalid address.
|
|
If
|
|
\f4wait\f1,
|
|
\f4wait3\f1,
|
|
or
|
|
\f4waitpid\f1
|
|
return due to a stopped
|
|
or terminated child process, the process
|
|
.SM ID
|
|
of the child is returned to the calling process.
|
|
\f4wait3\f1
|
|
and
|
|
\f4waitpid\f1
|
|
return 0 if
|
|
.SM
|
|
.B WNOHANG
|
|
is specified and there are currently no stopped
|
|
or exited children (although children
|
|
.SM DO
|
|
exist).
|
|
Otherwise, a value of \-1
|
|
is returned and \f2errno\fP is set to indicate the error:
|
|
.TP 15
|
|
.SM
|
|
\%[EINTR]
|
|
The calling process received a signal.
|
|
.TP 15
|
|
.SM
|
|
\%[ECHILD]
|
|
The calling process has no existing unwaited-for child processes.
|
|
.TP 15
|
|
.SM
|
|
\%[ECHILD]
|
|
The process or process group specified by
|
|
\f2pid\f1
|
|
does not exist or is not a child of the calling process (\f4waitpid\f1 only).
|
|
.TP 15
|
|
.SM
|
|
\%[EFAULT]
|
|
The \f2rusage\fP or \f2statptr\fP arguments (where applicable) point to
|
|
illegal addresses.
|
|
.TP 15
|
|
.SM
|
|
\%[EINVAL]
|
|
The value of the
|
|
\f2options\f1
|
|
argument is not valid (\f4waitpid\f1 and \f4wait3\f1 only).
|
|
.\" @(#)wait.2 6.2 of 9/6/83
|
|
.SH "SEE ALSO"
|
|
exec(2), exit(2), fork(2), intro(2), pause(2), ptrace(2), signal(2),
|
|
sigset(2), sigpause(2), sigaction(2), sigsuspend(2), sigprocmask(2),
|
|
signal(3B), sigvec(3B), sigpause(3B), wait(3b), getrusage(3), wstat(5).
|
|
.Op c p a
|
|
.SH NOTE
|
|
Currently,
|
|
\f4wait3\f1
|
|
returns zero for the
|
|
.I ru_ixrss, ru_idrss
|
|
and
|
|
.I ru_isrss
|
|
fields in
|
|
.IR rusage .
|
|
.Op
|