* 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"
#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 *
}
/*===========================================================================*
- * 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;
/* 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 */
*/
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)
{
/* 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
/* 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++) {
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);
}
}
}
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 *
*===========================================================================*/
* 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.
*/
/* 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) {
}
/*===========================================================================*
- * 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 (rmp->mp_flags & ZOMBIE)
+ panic(__FILE__, "zombify: process was already a zombie", NO_NUM);
- if (child->mp_fs_call != PM_IDLE)
- panic(__FILE__, "cleanup: not idle", child->mp_fs_call);
+ rmp->mp_flags &= (IN_USE|PRIV_PROC|HAS_DMA);
+ rmp->mp_flags |= ZOMBIE;
- tell_parent(child);
- real_cleanup(child);
+ 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;
}
/*===========================================================================*
- * 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. */
/* 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;
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)
{
/* 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;
}
#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) );
int s;
int slot;
int sigflags;
+ int exit_type;
slot = (int) (rmp - mproc);
if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) {
}
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 */
}
/*===========================================================================*
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, ¤t_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;
-}