Sunday, November 6, 2011

Zombies and Orphans in C Under Linux

We know that the ps –A command lists all the running processes. But from where does the ps program get this information? Well, Linux maintains a table containing information about all the processes. This table is called ‘Process Table’. Apart from other information the process table contains an entry of ‘exit code’ of the process. This integer value indicates the reason why the process was terminated. Even though the process comes to an end its entry would remain in the process table until such time that the parent of the terminated process queries the exit code. This act of querying deletes the entry of the terminated process from the process table and returns the exit code to the parent that raised the query.

When we fork a new child process and the parent and the child continue to execute there are two possibilities—either the child process ends first or the parent process ends first. Let us discuss both these possibilities.
(a) Child terminates earlier than the parent

In this case till the time parent does not query the exit code of the terminated child the entry of the child process would continue to exist. Such a process in Linux terminology is known as a ‘Zombie’ process. Zombie means ghost, or in plain simple Hindi a ‘Bhoot’. Moral is, a parent process should query the process table immediately after the child process has terminated. This would prevent a zombie.
What if the parent terminates without querying. In such a case the zombie child process is treated as an ‘Orphan’ process. Immediately, the father of all processes—init—adopts the orphaned process. Next, as a responsible parent init queries the process table as a result of which the child process entry is eliminated from the process table

(b) Parent terminates earlier than the child

Since every parent process is launched from the Linux shell, the parent of the parent is the shell process. When our parent process terminates, the shell queries the process table. Thus a proper cleanup happens for the parent process. However, the child process which is still running is left orphaned. Immediately the init process would adopt it and when its execution is over init would query the process table to clean up the entry for the child process. Note that in this case the child process does not become a zombie.

Thus, when a zombie or an orphan gets created the OS takes over and ensures that a proper cleanup of the relevant process table entry happens. However, as a good programming practice our program should get the exit code of the terminated process and thereby ensure a proper cleanup. Note that here cleanup is important (it happens anyway). Why is it important to get the exit code of the terminated process. It is because, it is the exit code that would give indication about whether the job assigned to the process was completed successfully or not. The following program shows how this can be done.

# include <unistd.h>
# include <sys/types.h>
int main( )
{
unsigned int i = 0 ;
int pid, status ;
pid = fork( ) ;
if ( pid == 0 )
{
while ( i < 4294967295U )
i++ ;
printf ( "The child is now terminating\n" ) ;
}
else
{
waitpid ( pid, &status, 0 ) ;
if ( WIFEXITED ( status ) )
printf ( "Parent: Child terminated normally\n" ) ;
else
printf ( "Parent: Child terminated abnormally\n" ) ;
}
return 0 ;
}

In this program we have applied a big loop in the child process. This loop ensures that the child does not terminate immediately. From within the parent process we have made a call to the waitpid( ) function. This function makes the parent process wait  till the time the execution of the child process does not come to an end. This ensures that the child process never becomes orphaned. Once the child process, terminates the waitpid( ) function queries its exit code and returns back to the parent. As a result of querying, the child process does not become a zombie.

The first parameter of waitpid( ) function is the pid of the child process for which the wait has to be performed. The second parameter is the address of an integer variable which is set up with the exit status code of the child process. The third parameter is used to specify some options to control the behavior of the wait operation. We have not used this parameter and hence we have passed a 0. Next we have made use of the WIFEXITED( ) macro to test if the child process exited normally or not. This macro takes the status value as a parameter and returns a non-zero value if the process terminated normally. Using this macro the parent suitably prints a message to report the status (normal/abnormal) termination of its child process.

1 comment:

  1. u r just copying from let us c book....what the hack yaar...wth yaar..but still you are sharing knowledge its good buddy...guys like ram,shyam,lopo,popo,mumtaz never do it

    ReplyDelete