|
» |
|
|
|
| | |
When a process finishes executing, HP-UX terminates it using
the exit system call. Circumstances might require a process to synchronize its execution
with a child process. This is done with the wait system call, which
has several related routines. During the exit system call,
a process enters the zombie state and must dispose of child processes.
Releasing process and thread structures no longer needed by the
exiting process or thread is handled by three routines -- freeproc(),
freethread(), and kissofdeath(). This section will describe each process-termination routine
in turn. The exit System Call | |
exit() may be called by a
process upon completion, or the kernel may have made the call on
behalf of the process due to a problem. If the parent process of the calling process is executing
a wait(), wait3(),
or waitpid(), it is notified of
the calling process's termination. If the parent of the
calling process is not executing a wait(),
wait3(), or waitpid(),
and does not have SIGCLD ( death
of a child) signal set to SIG_IGN
(ignore signal), the calling process is transformed into a zombie
process. The parent process ID is set to 1 for all of the calling
process's existing child processes and zombie processes.
This means the process 1 (init)
inherits each of the child processes. exit() passes status to the
system and terminates the calling process in the following manner: Clear the process' STRC
(process being traced) flag by calling STRC_EXIT(p,kt). Issue a process-wide directive to reduce an exiting
multi-threaded process to a single thread of execution. Clear
the multi-threaded flag for non-vfork
processes. Set the process p_flag
to SWEXIT to indicate it is exiting. Set process to ignore signal information. Make sure the "no swap" counter
is balanced. Determine whether the exiting process is a controlling
process. If it has a controlling tty,
send SIGHUP and free tty
for another session. Release memory-mapped semaphores. Disarm all timers and clear any related pending
siginfos. Do exit processing for graphics and iomap driver,
if needed. If the process was created via vfork()
release the virtual memory and return resources to the parent. Cancel all the process's pending asynchronous
I/O requests and sleep until all are completed. Free up space taken by the table of pointers to
file-descriptor chunks. Release MQ resources, NFS lock manager resources,
audit-control structures, and process-wide and thread copies of
credentials. Do exit processing for semaphores. Destroy any adopted processes. Search all processes for zombies whose p_dptr
field is not set; send SIGCLD to
the parent and wake it up, if parent has called wait(). Signal the process group that exit is causing it
to become an orphan with stopped processes. Deal with orphaned
process group and any children. Notify init that
zombies are waiting. Unlink from active list of processes. Unlink current thread from active list of threads
and set the thread state. Process enters SZOMB
state, and thread enters TSZOMB
state. Choose which process to send SIGCLD.
If exiting process is a daemon, make it a child of init. Awaken init to
start the cleanup process. If vfork() created
the process, reset vfork_state
to VFORK_CHILDEXIT, to allow resume()
to restore the parent. Verify that the thread state is set to TSSLEEP. Retain the "thread lock" across
the context switch path. Both signal path and init process
must wait until the last thread is non-TSRUNPROC. Call swtch() to
release the process lock.
wait System Call | |
From the user perspective, the wait system call is actually
four different interfaces used to synchronize
a child to parent process. All four versions call the wait1() routine,
which does the actual work./ The following table summarizes the basic differences among
the wait() functions. For further
information, consult kern_exit.c, wait(2)
manpage, and wait.h header file. Table 1-8 User interfaces
to the wait system call Interface | Purpose |
---|
wait() | Calls wait1()
to determine if any zombie process are present; if not, wait1()
sleeps. wait() determines which
process is of interest based on the pid argument and passes it on
to wait1(): -1, all processes>0,
processes with process ID == pid 0, processes in same process group as caller<-1,
processes with process group ID == -pid Once
wait1() returns, wait() passes
the exit status of the terminated
child back to the calling process. | waitpid() | POSIX version of the wait()
system call. It allows the caller to also wait on processes with
the same group ID and translate information for wait1(). | waitid() | Suspends the calling process until one of its
children changes state. It records the current state of a child
in infop (passes signal information between threads). The id_type,
which contains the set of processes that should receive the signal,
can be one of the following: P_PID,
process id P_PGID,
process group id P_ALL
all processes | wait3() | Almost identical to wait();
however, wait3() can be passed
a WNOHANG flag through the argument
options. If the child has not exited, the WNOHANG
flag will not block if no one is waiting. |
wait1() searches for a terminated
(zombie) child, to gather its status information and remove it.
wait1() also looks for stopped
(traced) and continued children, and passes back status from them
to their parents. wait1() determines
which process is interesting based on the pid
argument passed. The following are some of the steps performed
by wait1(): Hold the pm_sema
to ensure that a process already checked does not become a zombie
while other processes are being checked, thus resulting in a lost
wakeup. Find and count the step-children who do not belong
to the parent process being waited on. If zombies, undebug them
and signal their parents. If stopped, signal the step-parent. Search all processes. This is mainly due to the
fact SZOMB processes are no longer
on the active process list. While under the protection of an MP_PROCESS_LOCK,
make sure that p_zombies_exist = 0. If an SZOMB process
is found, the entry is removed from any proc
hash table (proc_unhash()) and
the thread is deallocated (thread_deallocate()). Call freeproc()
to release the process structures SZOMB.
freeproc(), freethread(),
and kissofdeath() RoutinesThe freeproc(), freethread(),
and kissofdeath() routines complete
the clean-up effort on behalf of wait1()
for a terminating process Table 1-9 Final process
termination routines Routine | Purpose |
---|
freeproc() | Called from wait1()
to release process structures that zombie processes are no longer
using. freeproc() performs the
following steps: Under the protection
of an MP_PROCESS_LOCK, clear p_pl_flags.all,
set p_stat to SUNUSED,
and verify that p_sigwaiters is
set to NULL. Decrement the number of active proc
table entries. Add the child's rusage
(sum of stats of the reaped child) structure to the parent.. Release the rusage
data sturcture, process timers data, msginfo, and any queued.signals
pending against the process. Release the virtual address space. Return the proc
entry to the free list
| freethread() | Called from wait1()
to release the thread structure. freethread()
performs the following steps: Under
the protection of an MP_PROCESS_LOCK,
clear kt_cntxt_flags and set kt_stat
to TSUNUSED. Decrement the number of active thread table entries. Clear the thread fields. If a thread was not cached,
dismantle its uarea by calling kissofdeath(). Release the thread entry by calling link_thread_to_free-list().
| kissofdeath() | Called from freethread()
and freeproc() to clear the kernel
stack and uarea of a named process. |
|