#include <sys/types.h> #include <sys/wait.h> #include <stdio.h> int main(int argc, char *argv[]) { pid_t whichone, first, second; int howmany; int status; if ((first=fork())==0) /* Parent spawns 1st child */ { printf("Hiya, I am the first child, " "and my id is %d\n", getpid() ); sleep(10); /* Sleep 10 sec, then exit */ exit(0); } else if (first == -1) { perror("1st fork: something went bananas\n"); exit(1); } else if ((second=fork())==0) /* Parent spawns 2nd child */ { printf("Hiya, I am the second child, " "and my id is %d\n", getpid() ); sleep(15); /* Sleep 15 sec, then exit */ exit(0); } else if (second == -1) { perror("2nd fork: something went bananas\n"); exit(1); } printf("This is the parent\n"); howmany=0; while (howmany < 2) /* Wait twice */ { whichone=wait(&status); howmany++; if (whichone==first) printf("First child exited "); else printf("Second child exited "); if ((status & 0xffff)==0) printf("correctly\n"); else printf("uncorrectly\n"); } return 0; }
The first part of this example, up to the howmany=0 statement, contains nothing new: just make sure you understand what the instruction flow is in the parent and in the children. The parent then enters a loop waiting for the children's completion. The wait() system call blocks the caller process until one of its immediate children (not children's children, or other siblings) terminates, and then returns the pid of the terminated process. The argument to wait() is the address on an integer variable or the NULL pointer. If it's not NULL, the system writes 16 bits of status information about the terminated child in the low-order 16 bits of that variable. Among these 16 bits, the higher 8 bits contain the lower 8 bits of the argument the child passed to exit() while the lower 8 bits are all zero if the process exited correctly, and contain error information if not (see the wait(2) man page for details). Hence, if a child exits with 0 all those 16 bits are zero. To reveal if this is actually the case we test the bitwise AND expression (status & 0xffff), which evaluates as an integer whose lower 16 bits are those of status, and the others are zero. If it evaluates to zero, everything went fine, otherwise some trouble occurred. Try changing the argument passed to exit() in one of the children.
The Posix and BSD extensions to wait() are useful when a parent must not block waiting for children, but still wants to know about the children's termination status values via the wait mechanism. We'll treat only the Posix waitpid() call, and you are referred to the man page for the BSD call.
The waitpid() call is declared as follows in the sys/wait.h header:
pid_t waitpid(pid_t pid, int *statptr, int options);
Here the meaning of the the return value and of the pointer to the status statptr is exactly the same in wait(). However this call allows you to specify which children should be waited for and how. Specifically, the first argument pid specifies the process(es) that must be waited for. The relevant (for now) cases are:
Note that the use of a loop also allows to use wait() and yet wait for one particular child: try to figure out yourself how.