Based on this: http://man7.org/tlpi/code/online/book/procexec/multi_wait.c.html
int
main(int argc, char *argv[])
{
int numDead; /* Number of children so far waited for */
pid_t childPid; /* PID of waited for child */
int j;
if (argc < 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s sleep-time...\n", argv[0]);
setbuf(stdout, NULL); /* Disable buffering of stdout */
for (j = 1; j < argc; j++) { /* Create one child for each argument */
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Child sleeps for a while then exits */
printf("[%s] child %d started with PID %ld, sleeping %s "
"seconds\n", currTime("%T"), j, (long) getpid(),
argv[j]);
sleep(getInt(argv[j], GN_NONNEG, "sleep-time"));
_exit(EXIT_SUCCESS);
default: /* Parent just continues around loop */
break;
}
}
numDead = 0;
for (;;) { /* Parent waits for each child to exit */
childPid = wait(NULL);
if (childPid == -1) {
if (errno == ECHILD) {
printf("No more children - bye!\n");
exit(EXIT_SUCCESS);
} else { /* Some other (unexpected) error */
errExit("wait");
}
}
numDead++;
printf("[%s] wait() returned child PID %ld (numDead=%d)\n",
currTime("%T"), (long) childPid, numDead);
}
}
On error, wait returns -1. One possible error is that the calling
process has no (previous unwaited-for) children, which is indicated by
the errno value ECHILD.
$ ./multi_wait 7 1 4
[13:41:00] child 1 started with PID 21835, sleeping 7 seconds
[13:41:00] child 2 started with PID 21836, sleeping 1 seconds
[13:41:00] child 3 started with PID 21837, sleeping 4 seconds
[13:41:01] wait() returned child PID 21836 (numDead=1)
[13:41:04] wait() returned child PID 21837 (numDead=2)
[13:41:07] wait() returned child PID 21835 (numDead=3)
No more children - bye!
Question
How does the system know there is no more unwaited-for children and return ECHILD.
For example, in this example, what if some children sleep for very long time?
The kernel maintains a data structure for each running process. It also maintains data structures for dead but unwaited-for processes (zombies). The parent process’s data structure has information on the children it hasn’t waited for yet (whether thay are zombies or are still alive, the main difference of zombies is that they have almost no flesh, i.e. their data structures only contain the exit status, resource usage, and not much more, so they are very loghtweight).