PM cleanup: merge exit and coredump paths

This commit is contained in:
David van Moolenbroek 2009-07-08 17:16:53 +00:00
parent 5e173f55f5
commit 67d986f882
8 changed files with 127 additions and 259 deletions

View file

@ -162,7 +162,7 @@ int result;
/* Use SIGILL signal that something went wrong */
rmp->mp_sigstatus = SIGILL;
pm_exit(rmp, 0, FALSE /*!for_trace*/);
exit_proc(rmp, 0, PM_EXIT);
return;
}
setreply(rmp-mproc, result);

View file

@ -7,11 +7,12 @@
* exits first, it continues to occupy a slot until the parent does a WAIT.
*
* The entry points into this file are:
* do_fork: perform the FORK system call
* do_pm_exit: perform the EXIT system call (by calling pm_exit())
* pm_exit: actually do the exiting
* do_wait: perform the WAITPID or WAIT system call
* tell_parent: tell parent about the death of a child
* do_fork: perform the FORK system call
* do_fork_nb: special nonblocking version of FORK, for RS
* do_exit: perform the EXIT system call (by calling exit_proc())
* exit_proc: actually do the exiting, and tell FS about it
* exit_restart: continue exiting a process after FS has replied
* do_waitpid: perform the WAITPID or WAIT system call
*/
#include "pm.h"
@ -26,7 +27,9 @@
#define LAST_FEW 2 /* last few slots reserved for superuser */
FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
FORWARD _PROTOTYPE (void zombify, (struct mproc *rmp) );
FORWARD _PROTOTYPE (void tell_parent, (struct mproc *child) );
FORWARD _PROTOTYPE (void cleanup, (register struct mproc *rmp) );
/*===========================================================================*
* do_fork *
@ -173,35 +176,45 @@ PUBLIC int do_fork_nb()
}
/*===========================================================================*
* do_pm_exit *
* do_exit *
*===========================================================================*/
PUBLIC int do_pm_exit()
PUBLIC int do_exit()
{
/* Perform the exit(status) system call. The real work is done by pm_exit(),
/* Perform the exit(status) system call. The real work is done by exit_proc(),
* which is also called when a process is killed by a signal.
*/
pm_exit(mp, m_in.status, FALSE /*!for_trace*/);
exit_proc(mp, m_in.status, PM_EXIT);
return(SUSPEND); /* can't communicate from beyond the grave */
}
/*===========================================================================*
* pm_exit *
* exit_proc *
*===========================================================================*/
PUBLIC void pm_exit(rmp, exit_status, for_trace)
PUBLIC void exit_proc(rmp, exit_status, exit_type)
register struct mproc *rmp; /* pointer to the process to be terminated */
int exit_status; /* the process' exit status (for parent) */
int for_trace;
int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */
{
/* A process is done. Release most of the process' possessions. If its
* parent is waiting, release the rest, else keep the process slot and
* become a zombie.
*/
register int proc_nr, proc_nr_e;
int parent_waiting, right_child, r;
pid_t pidarg, procgrp;
int parent_waiting, r;
pid_t procgrp;
struct mproc *p_mp;
clock_t user_time, sys_time;
/* Do not create core files for set uid execution */
if (exit_type == PM_DUMPCORE && rmp->mp_realuid != rmp->mp_effuid)
exit_type = PM_EXIT;
/* System processes are destroyed before informing FS, meaning that FS can
* not get their CPU state, so we can't generate a coredump for them either.
*/
if (exit_type == PM_DUMPCORE && (rmp->mp_flags & PRIV_PROC))
exit_type = PM_EXIT;
proc_nr = (int) (rmp - mproc); /* get process slot number */
proc_nr_e = rmp->mp_endpoint;
@ -213,7 +226,7 @@ int for_trace;
/* Do accounting: fetch usage times and accumulate at parent. */
if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK)
panic(__FILE__,"pm_exit: sys_times failed", r);
panic(__FILE__,"exit_proc: sys_times failed", r);
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
p_mp->mp_child_utime += user_time + rmp->mp_child_utime; /* add user time */
@ -227,7 +240,7 @@ int for_trace;
*/
sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */
if((r=vm_willexit(proc_nr_e)) != OK) {
panic(__FILE__, "pm_exit: vm_willexit failed", r);
panic(__FILE__, "exit_proc: vm_willexit failed", r);
}
if (proc_nr_e == INIT_PROC_NR)
@ -240,16 +253,16 @@ int for_trace;
{
/* Tell FS about the exiting process. */
if (rmp->mp_fs_call != PM_IDLE)
panic(__FILE__, "pm_exit: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= (for_trace ? PM_EXIT_TR : PM_EXIT);
panic(__FILE__, "exit_proc: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= exit_type;
r= notify(FS_PROC_NR);
if (r != OK) panic(__FILE__, "pm_exit: unable to notify FS", r);
if (r != OK) panic(__FILE__, "exit_proc: unable to notify FS", r);
if (rmp->mp_flags & PRIV_PROC)
{
/* destroy system processes without waiting for FS */
if((r= sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "pm_exit: sys_exit failed", r);
panic(__FILE__, "exit_proc: sys_exit failed", r);
}
}
else
@ -264,18 +277,12 @@ int for_trace;
/* Keep the process around until FS is finished with it. */
rmp->mp_exitstatus = (char) exit_status;
pidarg = p_mp->mp_wpid; /* who's being waited for? */
parent_waiting = p_mp->mp_flags & WAITING;
right_child = /* child meets one of the 3 tests? */
(pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
if (parent_waiting && right_child) {
tell_parent(rmp); /* tell parent */
} else {
rmp->mp_flags &= (IN_USE|PRIV_PROC|HAS_DMA);
rmp->mp_flags |= ZOMBIE; /* parent not waiting, zombify child */
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
}
/* For normal exits, try to notify the parent as soon as possible.
* For core dumps, notify the parent only once the core dump has been made.
*/
if (exit_type != PM_DUMPCORE)
zombify(rmp);
/* If the process has children, disinherit them. INIT is the new parent. */
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
@ -284,9 +291,11 @@ int for_trace;
rmp->mp_parent = INIT_PROC_NR;
parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
if (parent_waiting && (rmp->mp_flags & ZOMBIE) &&
!(rmp->mp_flags & TOLD_PARENT) &&
rmp->mp_fs_call != PM_EXIT) {
cleanup(rmp);
!(rmp->mp_flags & TOLD_PARENT)) {
tell_parent(rmp);
if (rmp->mp_fs_call == PM_IDLE)
cleanup(rmp);
}
}
}
@ -295,6 +304,46 @@ int for_trace;
if (procgrp != 0) check_sig(-procgrp, SIGHUP);
}
/*===========================================================================*
* exit_restart *
*===========================================================================*/
PUBLIC void exit_restart(rmp, reply_type)
struct mproc *rmp; /* pointer to the process being terminated */
int reply_type; /* one of PM_EXIT_REPLY(_TR), PM_CORE_REPLY */
{
/* FS replied to our exit or coredump request. Perform the second half of the
* exit code.
*/
int r;
/* For core dumps, now is the right time to try to contact the parent. */
if (reply_type == PM_CORE_REPLY)
zombify(rmp);
if (!(rmp->mp_flags & PRIV_PROC))
{
/* destroy the (user) process */
if((r=sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "exit_restart: sys_exit failed", r);
}
/* Release the memory occupied by the child. */
if((r=vm_exit(rmp->mp_endpoint)) != OK) {
panic(__FILE__, "exit_restart: vm_exit failed", r);
}
if (reply_type == PM_EXIT_REPLY_TR && rmp->mp_parent != INIT_PROC_NR)
{
/* Wake up the parent, completing the ptrace(T_EXIT) call */
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
setreply(rmp->mp_parent, OK);
}
/* Clean up if the parent has collected the exit status */
if (rmp->mp_flags & TOLD_PARENT)
cleanup(rmp);
}
/*===========================================================================*
* do_waitpid *
*===========================================================================*/
@ -305,7 +354,7 @@ PUBLIC int do_waitpid()
* really wait.
* A process calling WAIT never gets a reply in the usual way at the end
* of the main loop (unless WNOHANG is set or no qualifying child exists).
* If a child has already exited, the routine cleanup() sends the reply
* If a child has already exited, the routine tell_parent() sends the reply
* to awaken the caller.
* Both WAIT and WAITPID are handled by this code.
*/
@ -335,7 +384,7 @@ PUBLIC int do_waitpid()
/* This child meets the pid test and has exited. */
tell_parent(rp); /* this child has already exited */
if (rp->mp_fs_call == PM_IDLE)
real_cleanup(rp);
cleanup(rp);
return(SUSPEND);
}
if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
@ -363,27 +412,40 @@ PUBLIC int do_waitpid()
}
/*===========================================================================*
* cleanup *
* zombify *
*===========================================================================*/
PRIVATE void cleanup(child)
register struct mproc *child; /* tells which process is exiting */
PRIVATE void zombify(rmp)
struct mproc *rmp;
{
/* Finish off the exit of a process. The process has exited or been killed
* by a signal, and its parent is waiting.
/* Zombify a process. If the parent is waiting, notify it immediately.
* Otherwise, send a SIGCHLD signal to the parent.
*/
struct mproc *p_mp;
int parent_waiting, right_child;
pid_t pidarg;
if (child->mp_fs_call != PM_IDLE)
panic(__FILE__, "cleanup: not idle", child->mp_fs_call);
if (rmp->mp_flags & ZOMBIE)
panic(__FILE__, "zombify: process was already a zombie", NO_NUM);
tell_parent(child);
real_cleanup(child);
rmp->mp_flags &= (IN_USE|PRIV_PROC|HAS_DMA);
rmp->mp_flags |= ZOMBIE;
p_mp = &mproc[rmp->mp_parent];
pidarg = p_mp->mp_wpid; /* who's being waited for? */
parent_waiting = p_mp->mp_flags & WAITING;
right_child = /* child meets one of the 3 tests? */
(pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
if (parent_waiting && right_child)
tell_parent(rmp); /* tell parent */
else
sig_proc(p_mp, SIGCHLD); /* send parent a "child died" signal */
}
/*===========================================================================*
* tell_parent *
*===========================================================================*/
PUBLIC void tell_parent(child)
PRIVATE void tell_parent(child)
register struct mproc *child; /* tells which process is exiting */
{
int exitstatus, mp_parent;
@ -405,9 +467,9 @@ register struct mproc *child; /* tells which process is exiting */
}
/*===========================================================================*
* real_cleanup *
* cleanup *
*===========================================================================*/
PUBLIC void real_cleanup(rmp)
PRIVATE void cleanup(rmp)
register struct mproc *rmp; /* tells which process is exiting */
{
/* Release the process table entry and reinitialize some field. */

View file

@ -596,34 +596,7 @@ message *m_ptr;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
if (!(rmp->mp_flags & PRIV_PROC))
{
/* destroy the (user) process */
if((r=sys_exit(proc_e)) != OK)
{
panic(__FILE__,
"PM_EXIT_REPLY: sys_exit failed", r);
}
}
/* Release the memory occupied by the child. */
if((s=vm_exit(rmp->mp_endpoint)) != OK) {
panic(__FILE__, "vm_exit() failed", s);
}
if (m_ptr->m_type == PM_EXIT_REPLY_TR &&
rmp->mp_parent != INIT_PROC_NR)
{
/* Wake up the parent */
mproc[rmp->mp_parent].mp_reply.reply_trace = 0;
setreply(rmp->mp_parent, OK);
}
/* Clean up if the parent has collected the exit
* status
*/
if (rmp->mp_flags & TOLD_PARENT)
real_cleanup(rmp);
exit_restart(rmp, m_ptr->m_type);
break;
@ -675,10 +648,6 @@ message *m_ptr;
case PM_CORE_REPLY:
{
int parent_waiting, right_child;
pid_t pidarg;
struct mproc *p_mp;
proc_e= m_ptr->PM_CORE_PROC;
if (pm_isokendpt(proc_e, &proc_n) != OK)
{
@ -694,43 +663,7 @@ message *m_ptr;
/* Call is finished */
rmp->mp_fs_call= PM_IDLE;
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
pidarg = p_mp->mp_wpid; /* who's being waited for? */
parent_waiting = p_mp->mp_flags & WAITING;
right_child = /* child meets one of the 3 tests? */
(pidarg == -1 || pidarg == rmp->mp_pid ||
-pidarg == rmp->mp_procgrp);
if (parent_waiting && right_child) {
tell_parent(rmp); /* tell parent */
} else {
/* parent not waiting, zombify child */
rmp->mp_flags &= (IN_USE|PRIV_PROC|HAS_DMA);
rmp->mp_flags |= ZOMBIE;
/* send parent a "child died" signal */
sig_proc(p_mp, SIGCHLD);
}
if (!(rmp->mp_flags & PRIV_PROC))
{
/* destroy the (user) process */
if((r=sys_exit(proc_e)) != OK)
{
panic(__FILE__,
"PM_CORE_REPLY: sys_exit failed", r);
}
}
/* Release the memory occupied by the child. */
if((s=vm_exit(rmp->mp_endpoint)) != OK) {
panic(__FILE__, "vm_exit() failed", s);
}
/* Clean up if the parent has collected the exit
* status
*/
if (rmp->mp_flags & TOLD_PARENT)
real_cleanup(rmp);
exit_restart(rmp, m_ptr->m_type);
break;
}

View file

@ -33,12 +33,11 @@ _PROTOTYPE( void exec_restart, (struct mproc *rmp, int result) );
/* forkexit.c */
_PROTOTYPE( int do_fork, (void) );
_PROTOTYPE( int do_fork_nb, (void) );
_PROTOTYPE( int do_pm_exit, (void) );
_PROTOTYPE( int do_exit, (void) );
_PROTOTYPE( int do_waitpid, (void) );
_PROTOTYPE( void pm_exit, (struct mproc *rmp, int exit_status,
int for_trace) );
_PROTOTYPE (void tell_parent, (struct mproc *child) );
_PROTOTYPE( void real_cleanup, (struct mproc *rmp) );
_PROTOTYPE( void exit_proc, (struct mproc *rmp, int exit_status,
int exit_type) );
_PROTOTYPE( void exit_restart, (struct mproc *rmp, int reply_type) );
/* getset.c */
_PROTOTYPE( int do_getset, (void) );

View file

@ -34,7 +34,6 @@
#include "mproc.h"
#include "param.h"
FORWARD _PROTOTYPE( int dump_core, (struct mproc *rmp) );
FORWARD _PROTOTYPE( void unpause, (int pro, int for_trace) );
FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp) );
@ -422,6 +421,7 @@ int signo; /* signal to send to process (1 to _NSIG) */
int s;
int slot;
int sigflags;
int exit_type;
slot = (int) (rmp - mproc);
if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) {
@ -520,16 +520,13 @@ doterminate:
}
rmp->mp_sigstatus = (char) signo;
exit_type = PM_EXIT;
if (sigismember(&core_sset, signo) && slot != FS_PROC_NR) {
printf("PM: signal %d for %d / %s\n", signo, rmp->mp_pid, rmp->mp_name);
s= dump_core(rmp);
if (s == SUSPEND) {
return;
}
/* Not dumping core, just call exit */
printf("PM: coredump signal %d for %d / %s\n", signo, rmp->mp_pid,
rmp->mp_name);
exit_type = PM_DUMPCORE;
}
pm_exit(rmp, 0, FALSE /*!for_trace*/); /* terminate process */
exit_proc(rmp, 0, exit_type); /* terminate process */
}
/*===========================================================================*
@ -669,124 +666,3 @@ int for_trace; /* for tracing */
r= notify(FS_PROC_NR);
if (r != OK) panic("pm", "unpause: unable to notify FS", r);
}
/*===========================================================================*
* dump_core *
*===========================================================================*/
PRIVATE int dump_core(rmp)
register struct mproc *rmp; /* whose core is to be dumped */
{
/* Make a core dump on the file "core", if possible. */
int r, proc_nr, proc_nr_e, parent_waiting;
pid_t procgrp;
#if 0
vir_bytes current_sp;
#endif
struct mproc *p_mp;
clock_t user_time, sys_time;
printf("dumpcore for %d / %s\n", rmp->mp_pid, rmp->mp_name);
/* Do not create core files for set uid execution */
if (rmp->mp_realuid != rmp->mp_effuid) return OK;
/* Make sure the stack segment is up to date.
* We don't want adjust() to fail unless current_sp is preposterous,
* but it might fail due to safety checking. Also, we don't really want
* the adjust() for sending a signal to fail due to safety checking.
* Maybe make SAFETY_BYTES a parameter.
*/
#if 0
if ((r= get_stack_ptr(rmp->mp_endpoint, &current_sp)) != OK)
panic(__FILE__,"couldn't get new stack pointer (for core)", r);
adjust(rmp, rmp->mp_seg[D].mem_len, current_sp);
#endif
/* Tell FS about the exiting process. */
if (rmp->mp_fs_call != PM_IDLE)
panic(__FILE__, "dump_core: not idle", rmp->mp_fs_call);
rmp->mp_fs_call= PM_DUMPCORE;
r= notify(FS_PROC_NR);
if (r != OK) panic(__FILE__, "dump_core: unable to notify FS", r);
/* Also perform most of the normal exit processing. Informing the parent
* has to wait until we know whether the coredump was successful or not.
*/
proc_nr = (int) (rmp - mproc); /* get process slot number */
proc_nr_e = rmp->mp_endpoint;
/* Remember a session leader's process group. */
procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
/* If the exited process has a timer pending, kill it. */
if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr_e, (unsigned) 0);
/* Do accounting: fetch usage times and accumulate at parent. */
if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK)
panic(__FILE__,"dump_core: sys_times failed", r);
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
p_mp->mp_child_utime += user_time + rmp->mp_child_utime; /* add user time */
p_mp->mp_child_stime += sys_time + rmp->mp_child_stime; /* add system time */
/* Tell the kernel the process is no longer runnable to prevent it from
* being scheduled in between the following steps. Then tell FS that it
* the process has exited and finally, clean up the process at the kernel.
* This order is important so that FS can tell drivers to cancel requests
* such as copying to/ from the exiting process, before it is gone.
*/
sys_nice(proc_nr_e, PRIO_STOP); /* stop the process */
if((r=vm_willexit(proc_nr_e)) != OK) {
panic(__FILE__,"dump_core: vm_willexit failed", r);
}
if(proc_nr_e != FS_PROC_NR) /* if it is not FS that is exiting.. */
{
if (rmp->mp_flags & PRIV_PROC)
{
/* destroy system processes without waiting for FS */
if((r= sys_exit(rmp->mp_endpoint)) != OK)
panic(__FILE__, "dump_core: sys_exit failed", r);
/* Just send a SIGCHLD. Dealing with waidpid is too complicated
* here.
*/
p_mp = &mproc[rmp->mp_parent]; /* process' parent */
sig_proc(p_mp, SIGCHLD);
/* Zombify to avoid calling sys_endksig */
rmp->mp_flags |= ZOMBIE;
}
}
else
{
printf("PM: FS died\n");
return SUSPEND;
}
/* Pending reply messages for the dead process cannot be delivered. */
rmp->mp_flags &= ~REPLY;
/* Keep the process around until FS is finished with it. */
/* If the process has children, disinherit them. INIT is the new parent. */
for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
/* 'rmp' now points to a child to be disinherited. */
rmp->mp_parent = INIT_PROC_NR;
parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
if (parent_waiting && (rmp->mp_flags & ZOMBIE))
{
tell_parent(rmp);
real_cleanup(rmp);
}
}
}
/* Send a hangup to the process' process group if it was a session leader. */
if (procgrp != 0) check_sig(-procgrp, SIGHUP);
return SUSPEND;
}

View file

@ -15,7 +15,7 @@ char core_name[] = "core"; /* file name where core images are produced */
_PROTOTYPE (int (*call_vec[]), (void) ) = {
no_sys, /* 0 = unused */
do_pm_exit, /* 1 = exit */
do_exit, /* 1 = exit */
do_fork, /* 2 = fork */
no_sys, /* 3 = read */
no_sys, /* 4 = write */

View file

@ -112,7 +112,7 @@ PUBLIC int do_trace()
switch (m_in.request) {
case T_EXIT: /* exit */
pm_exit(child, (int) m_in.data, TRUE /*for_trace*/);
exit_proc(child, (int) m_in.data, PM_EXIT_TR);
/* Do not reply to the caller until FS has processed the exit
* request.
*/

View file

@ -3,11 +3,9 @@
* The entry points are:
* find_param: look up a boot monitor parameter
* get_free_pid: get a free process or group id
* allowed: see if an access is permitted
* no_sys: called for invalid system call numbers
* panic: PM has run aground of a fatal error
* get_stack_ptr: get stack pointer of given process
* proc_from_pid: return process pointer from pid number
* pm_isokendpt: check the validity of an endpoint
*/
#include "pm.h"