WAIT(2) WAIT(2)
wait, waitpid, wait3 - wait for child processes to stop or terminate
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait (int *statptr);
pid_t waitpid (pid_t pid, int *statptr, int options);
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
pid_t wait3 (int *statptr, int options, struct rusage *rusage);
wait 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 wait will return prematurely if a signal is
received. If all child processes stopped or terminated prior to the call
on wait, return is immediate.
If the call is successful, the process ID of a child is returned.
wait3 is BSD's extension of wait. It provides an alternate interface for
programs that must not block when collecting the status of child
processes.
waitpid is POSIX's extension of wait. The pid argument specifies a set
of child processes for which status is requested. waitpid only returns
the status of a child process from this set.
statptr (all functions): If statptr is non-zero, 16 bits of information
called status are stored in the low-order 16 bits of the location pointed
to by statptr. Status may be evaluated with the macros described on
wstat(5). Status can be used to differentiate between stopped and
terminated child processes. If the child process terminated, status
identifies the cause of termination and passes useful information to the
parent. status is interpreted as follows:
If the child process stopped, the predicate WIFSTOPPED(*statptr)
will evaluate to non-zero and WSTOPSIG(*statptr) will return the
signal number that caused the process to stop. (The high-order 8
bits of status will contain the signal number and the low-order 8
bits are set equal to WSTOPFLG.)
If the child process terminated due to an exit call, the predicate
WIFEXITED(*statptr) will evaluate to non-zero, and
WEXITSTATUS(*statptr) will return the argument that the child
process passed to _exit or exit, or the value the child process
Page 1
WAIT(2) WAIT(2)
returned from main [see exit(2)]. (The low-order 8 bits of status
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 exit.)
If the child process terminated due to a signal, the predicate
WIFSIGNALED(*statptr) will evaluate to non-zero, and
WTERMSIG(*statptr) will return the signal number that caused the
termination. (The high-order 8 bits of status will be zero and the
low-order 8 bits will contain the number of the signal.) In
addition, if WCOREFLG is set, a ``core image'' will have been
produced [see signal(2)].
rusage (wait3): If 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).
pid (waitpid):
1) If pid is equal to -1, status is requested for any child process.
In this respect, waitpid is then equivalent to wait.
2) If pid is greater than zero, it specifies the process ID of a
single child process for which status is requested.
3) If pid is equal to zero, status is requested for any child
process whose process group ID is equal to that of the calling
process.
4) If pid is less than -1, status is requested for any child process
whose process group ID is equal to the absolute value of pid.
options (waitpid and wait3): The options argument is constructed from the
bitwise inclusive OR of zero or more of the following flags, defined in
the header <sys/wait.h>:
WNOHANG The function will not suspend execution of the calling
process if status is not immediately available for one of
the child processes.
WUNTRACED The status of child processes that are stopped due to a
SIGTTIN, SIGTTOU, SIGTSTP, or SIGSTOP signal, and whose
status has not yet been reported since they stopped, are
reported to the requesting process.
If a parent process terminates without waiting for its child processes to
terminate, the parent process ID of each child process is set to 1. This
means the initialization process inherits the child processes [see
intro(2)].
Page 2
WAIT(2) WAIT(2)
SIGCLD HANDLING
IRIX has three distinct version of signal routines: System V (signal(2)
and sigset(2)), 4.3BSD (signal(3B) and sigvec(3B)), and POSIX
(sigaction(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
SIGCLD 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.
Note that System V refers to this signal as SIGCLD, whereas BSD calls it
SIGCHLD. For compatibility with both systems they are defined to be the
same signal number, and may therefore be used interchangeably.
System V: System V's SIGCLD mechanism guarantees that no SIGCLD signals
will be lost. It accomplishes this by forcing the process to reinstall
the handler (via signal or sigset calls) when leaving the handler. Note
that whereas signal(2) sets the signal disposition back to SIG_DFL each
time the handler is called, sigset(2) keeps it installed, so SIGCLD 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. The code below is the System V example. Note that the
sigpause(2) creates a window during which SIGCLD is not blocked, allowing
the parent to enter its handler.
/*
* 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\n", getpid());
exit(0);
}
}
while (kids > 0) {
sigpause(SIGCLD);
Page 3
WAIT(2) WAIT(2)
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\n", pid, kids);
/*
* Now reinstall handler & cause SIGCLD to be re-raised
* if any more children exited while we were in here.
*/
sigset(SIGCLD, handler);
}
BSD: 4.3BSD solved this problem differently: instead of guaranteeing that
no SIGCHLD signals are lost, it provides a WNOHANG option to wait3 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 SIGCHLD signals arrived while the parent was in its
handler, the signal will remain pending, the parent will reenter the
handler, and the wait3 call will return 0. Note that it is not necessary
to call sigvec upon exit from the handler.
/*
* 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;
Page 4
WAIT(2) WAIT(2)
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\n", 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\n", pid, kids);
}
}
POSIX: POSIX improved on the BSD method by providing waitpid, that allows
a parent to wait on a particular child process if desired. In addition,
the IRIX implementation of sigaction(2) checks for zombied children upon
exit from the system call if the specified signal was SIGCLD and the
disposition of the signal handling was changed. If zombied children
exist, another SIGCLD 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 system(3)) creates and waits on its own
children.
Two problems have classically arisen in such a scheme: 1) until the
advent of waitpid, 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 SIGCLD 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 SIGCLD handler would reap and discard those
children. The addition of waitpid and the IRIX implementation of
sigaction solves both of these problems. Note that neither the BSD nor
the System V signal routines on IRIX have these properties, in the
interests of compatibility.
Page 5
WAIT(2) WAIT(2)
WARNING: programs that install SIGCLD handlers that set flags instead of
executing waitpids and then attempt to restore the previous signal
handler (via sigaction) upon return from the handler will create infinite
loops.
/*
* 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\n", getpid());
exit(0);
}
}
while (kids > 0) {
sigsuspend(&emptyset);
}
}
Page 6
WAIT(2) WAIT(2)
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\n", pid, kids);
pid = waitpid(ANYKID, &status, WNOHANG);
}
}
wait fails and its actions are undefined if statptr points to an invalid
address. If wait, wait3, or waitpid return due to a stopped or
terminated child process, the process ID of the child is returned to the
calling process. wait3 and waitpid return 0 if WNOHANG is specified and
there are currently no stopped or exited children (although children DO
exist). Otherwise, a value of -1 is returned and errno is set to
indicate the error:
[EINTR] The calling process received a signal.
[ECHILD] The calling process has no existing unwaited-for child
processes.
[ECHILD] The process or process group specified by pid does not
exist or is not a child of the calling process (waitpid
only).
[EFAULT] The rusage or statptr arguments (where applicable) point
to illegal addresses.
[EINVAL] The value of the options argument is not valid (waitpid
and wait3 only).
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).
Currently, wait3 returns zero for the ru_ixrss, ru_idrss and ru_isrss
fields in rusage.
PPPPaaaaggggeeee 7777 [ Back ]
|