Creating new processes: fork()

#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);

The fork() function is used to create a new process from an existing process. The new process is called the child process, and the existing process is called the parent. You can tell which is which by checking the return value from fork(). The parent gets the child's pid returned to him, but the child gets 0 returned to him. Thus this simple code illustrate's the basics of it.

pid_t pid;

switch (pid = fork())
{
case -1:
    /* Here pid is -1, the fork failed */
    /* Some possible reasons are that you're */
    /* out of process slots or virtual memory */
    perror("The fork failed!");
    break;

case 0:
    /* pid of zero is the child */
    /* Child can call getpid() to obtain its pid */

default:
    /* pid greater than zero is parent getting the child's pid */
    printf("Child's pid is %d\n",pid);
}

Of help when doing this is knowing just what is and is not inherited by the child. This list can vary depending on Unix implementation, so take it with a grain of salt. Note that the child gets copies of these things, not the real thing.

Inherited by the child from the parent:

Unique to the child:

Zombie processes: Why you wait on children.

What is a zombie?

When a program forks and the child finishes before the parent, the kernel still keeps some of its information about the child in case the parent might need it -- for example, the parent may need to check the child's exit status. To be able to get this information, the parent calls wait(); when this happens, the kernel can discard the information.

In the interval between the child terminating and the parent calling wait(), the child is said to be a `zombie'. (If you do ps, the child will have a `Z' in its status field to indicate this.) Even though it's not running, it's still taking up an entry in the process table.

This is not good, as the process table has a fixed number of entries and it is possible for the system to run out of them. Even if the system doesn't run out, there is a limit on the number of processes each user can run, which is usually smaller than the system's limit.

If the parent terminates without calling wait, the child is `adopted' by init, which handles the work necessary to cleanup after the child. (This is a special system program with process ID 1 -- it's actually the first program to run after the system boots up).

Preventing your children from becoming Zombies.

You need to ensure that your parent process calls wait (or waitpid) for every child process that terminates.

Another approach is to fork twice, and have the immediate child process exit straight away. This causes the grandchild process to be orphaned, so the init process is responsible for cleaning it up.

You can ignore your children's exit states, using signal handling (this gives you an example using sigaction; test yourself by trying to use signal to ignore the signal SIGCHLD:

    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sa.sa_flags = SA_NOCLDWAIT;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGCHLD, &sa, NULL);

If you do this do not call wait: it will not work!!You will wait until all child processes have terminated, then return failure with errno,ECHILD being set.

Another technique is to catch the SIGCHLD signal, and have the signal handler call wait