4.6 Process Termination
Processes terminate either voluntarily through an exit system call or involuntarily as the result of a signal. In either case, process termination causes a status code to be returned to the parent of the terminating process (if the parent still exists). This termination status is returned through the wait4 system call. The wait4 call permits an application to request the status of both stopped and terminated processes. The wait4 request can wait for any direct child of the parent, or it can wait selectively for a single child process or for only its children in a particular process group. Wait4 can also request statistics describing the resource utilization of a terminated child process. Finally, the wait4 interface allows a process to request status codes without blocking.
Within the kernel, a process terminates by calling the exit() routine. The exit() routine first kills off any other threads associated with the process. The termination of other threads is done as follows:
- Any thread entering the kernel from userspace will thread_exit() when it traps into the kernel.
- Any thread already in the kernel and attempting to sleep will return immediately with EINTR or EAGAIN, which will force them back out to userspace, freeing resources as they go. When the thread attempts to return to userspace, it will instead hit exit().
The exit() routine then cleans up the process’s kernel-mode execution state by doing the following:
- Canceling any pending timers
- Releasing virtual-memory resources
- Closing open descriptors
- Handling stopped or traced child processes
With the kernel-mode state reset, the process is then removed from the list of active processes—the allproc list—and is placed on the list of zombie processes pointed to by zombproc. The process state is changed to show that no thread is currently running. The exit() routine then does the following:
- Records the termination status in the p_xstat field of the process structure
- Bundles up a copy of the process’s accumulated resource usage (for accounting purposes) and hangs this structure from the p_ru field of the process structure
- Notifies the deceased process’s parent
Finally, after the parent has been notified, the cpu_exit() routine frees any machine-dependent process resources and arranges for a final context switch from the process.
The wait4 call works by searching a process’s descendant processes for ones that have entered the ZOMBIE state (e.g., that have terminated). If a process in ZOMBIE state is found that matches the wait criterion, the system will copy the termination status from the deceased process. The process entry then is taken off the zombie list and is freed. Note that resources used by children of a process are accumulated only as a result of a wait4 system call. When users are trying to analyze the behavior of a long-running program, they will find it useful to be able to obtain this resource usage information before the termination of a process. Although the information is available inside the kernel and within the context of that program, there is no interface to request it outside that context until process termination.