November 23rd, 2014

Random API of the day

Today’s random API is wait(2), which UNIX processes use to clean up after their child processes.

On UNIX, multitasking is implemented by the fork(2) system call, which applications use to create a child process. Sometimes, these child processes die, and you need to get the exit code, which is why the wait(2) system call exists. The kernel has to keep that information somewhere for you, and you tell the kernel that it doesn’t have to keep it around any more by calling wait(2).

One problem with wait(2) is that it is a blocking system call; that is, the calling program stops running until wait(2) returns. This kind of defeats the point of multitasking, because then the parent process has to stop and wait until the child process is finished. So, most applications install a signal handler so that when the kernel sends the parent a SIGCHLD signal, the parent process can call wait(2) in the signal handler to clean up after whatever child just died.

If the parent process never calls wait(2), the kernel assumes you’re just busy and will keep the child process around, just in case you want to have one last look at it before you shut it down. The kernel will wait forever for you to do this. In the meantime, the dead child process is called a zombie process. Why? Because just like real zombies, it’s dead but won’t go away. So, it’s important that wait(2) gets called reliably, because otherwise zombies will fill up the computer and start pouring out the front of it :)

Here’s a typical application:

 void sigchld_handler(int signum)
pid_t pid;
int ignored;

pid = wait(&ignored);
syslog(LOG_INFO, "pid %u finished", pid);
int main(void)

struct sigaction sa;
int rc;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchld_handler;
sa.sa_flags = SA_RESTART;
rc = sigaction(SIGCHLD, &sa, NULL);
if(rc == -1)
err(EXIT_FAILURE, "sigaction() failed");

Leave a Response

Imhotep theme designed by Chris Lin. Proudly powered by Wordpress.
XHTML | CSS | RSS | Comments RSS