The answer to the question of what the parent process does while the child process runs is quite simple - either it waits for the child process to terminate or it just gets on with whatever else it needs to do.
In the case of the shell, for instance, the choice is given to the user. Normally, if you just enter a command to the shell, it will wait until the command has finished before it gives you another prompt. If you put an ampersand (&) on the end of the line then the shell will not wait but will return a new prompt immediately.
In order to wait for a child process to terminate, a parent process will just execute a wait() system call. This call will suspend the parent process until any of its child processes terminates, at which time the wait() call returns and the parent process can continue.
The prototype for the wait( call is:
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status);
The return value from wait is the PID of the child process which terminated. The parameter to wait() is a pointer to a location which will receive the child's exit status value when it terminates.
When a process terminates it executes an exit() system call, either directly in its own code, or indirectly via library code. The prototype for the exit() call is:
#include <std1ib.h> void exit(int status);
The exit() call has no return value as the process that calls it terminates and so couldn't receive a value anyway. Notice, however, that exit() does take a parameter value - status. As well as causing a waiting parent process to resume execution, exit() also returns the status parameter value to the parent process via the location pointed to by the wait() parameter.
In fact, wait() can return several different pieces of information via the value to which the status parameter points. Consequently, a macro is provided called WEXITSTATUS() (accessed via <sys/wait.h>) which can extract and return the child's exit status. The following code fragment shows its use:
#include <sys/wait.h> int statval, exstat; pid_t pid; pid = wait(&statval); exstat = WEXITSTATUS(statval);
It is now possible to draw up a picture of the life of a child process from creation by fork(), through execution via exec(), then termination with exit(), while the parent process is suspended with wait(). This sequence is illustrated in Figure 4.
In fact, the version of wait() that we have just seen is only the simplest version available under Linux. The new POSIX version is called waitpid. The prototype for waitpid() is:
#include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid, int *status, int options);
where pid specifies what to wait for, status is the same as the simple wait() parameter and options allows you to specify that a call to waitpid() should not suspend the parent process if no child process is ready to report its exit status.
The various possibilities for the pid parameter are:
pid | meaning |
< -1 | wait for a child whose PGID is -pid |
-1 | same behavior as standard wait() |
0 | wait for child whose PGID = PGID of calling process |
> 0 | wait for a child whose PID = pid |
The standard wait() call is now redundant as the following waitpid() call is exactly equivalent:
#include <sys/wait.h> int statval; pid_t pid; pid = waitpid(-1, &statval, 0);
It is possible for a child process which only executes for a very short time to terminate before its parent process has had the chance to wait() for it. In these circumstances the child process will enter a state, known as a zombie state, in which all its resources have been released back to the system except for its process data structure, which holds its exit status. When the parent eventually wait()s for the child, the exit status is delivered immediately and then the process data structure can also be released back to the system.