diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 08bbc3193..f5e531794 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -271,6 +271,11 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */ return; } + /* The process is now officially exiting. The ZOMBIE flag is not enough, as + * it is not set here for core dumps - introducing potential race conditions. + */ + rmp->mp_flags |= EXITING; + /* Pending reply messages for the dead process cannot be delivered. */ rmp->mp_flags &= ~REPLY; @@ -290,8 +295,7 @@ int exit_type; /* one of PM_EXIT, PM_EXIT_TR, PM_DUMPCORE */ /* '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) && - !(rmp->mp_flags & TOLD_PARENT)) { + if (parent_waiting && (rmp->mp_flags & ZOMBIE)) { tell_parent(rmp); if (rmp->mp_fs_call == PM_IDLE) @@ -427,7 +431,7 @@ struct mproc *rmp; if (rmp->mp_flags & ZOMBIE) panic(__FILE__, "zombify: process was already a zombie", NO_NUM); - rmp->mp_flags &= (IN_USE|PRIV_PROC); + rmp->mp_flags &= (IN_USE|PRIV_PROC|EXITING); rmp->mp_flags |= ZOMBIE; p_mp = &mproc[rmp->mp_parent]; @@ -454,6 +458,8 @@ register struct mproc *child; /* tells which process is exiting */ mp_parent= child->mp_parent; if (mp_parent <= 0) panic(__FILE__, "tell_parent: bad value in mp_parent", mp_parent); + if(!(child->mp_flags & ZOMBIE)) + panic(__FILE__, "tell_parent: child not a zombie", NO_NUM); if(child->mp_flags & TOLD_PARENT) panic(__FILE__, "tell_parent: telling parent again", NO_NUM); parent = &mproc[mp_parent]; @@ -463,6 +469,7 @@ register struct mproc *child; /* tells which process is exiting */ parent->mp_reply.reply_res2 = exitstatus; setreply(child->mp_parent, child->mp_pid); parent->mp_flags &= ~WAITING; /* parent no longer waiting */ + child->mp_flags &= ~ZOMBIE; /* child no longer a zombie */ child->mp_flags |= TOLD_PARENT; /* avoid informing parent twice */ } diff --git a/servers/pm/main.c b/servers/pm/main.c index 130e06837..bd083e532 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -148,9 +148,9 @@ PUBLIC int main() /* In the meantime, the process may have been killed by a * signal (e.g. if a lethal pending signal was unblocked) * without the PM realizing it. If the slot is no longer in - * use or just a zombie, don't try to reply. + * use or the process is exiting, don't try to reply. */ - if ((rmp->mp_flags & (REPLY | IN_USE | ZOMBIE)) == + if ((rmp->mp_flags & (REPLY | IN_USE | EXITING)) == (REPLY | IN_USE)) { s=sendnb(rmp->mp_endpoint, &rmp->mp_reply); if (s != OK) { @@ -365,7 +365,7 @@ void checkme(char *str, int line) int boned = 0; int proc_nr; for (proc_nr=0, trmp=mproc; proc_nr < NR_PROCS; proc_nr++, trmp++) { - if ((trmp->mp_flags & (REPLY | IN_USE | ZOMBIE)) == + if ((trmp->mp_flags & (REPLY | IN_USE | EXITING)) == (REPLY | IN_USE)) { int tp; if(pm_isokendpt(trmp->mp_endpoint, &tp) != OK) { diff --git a/servers/pm/misc.c b/servers/pm/misc.c index 551cac882..cc04c1904 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -343,7 +343,7 @@ PUBLIC int do_getprocnr() return(s); search_key[key_len] = '\0'; /* terminate for safety */ for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { - if (((rmp->mp_flags & (IN_USE | ZOMBIE)) == IN_USE) && + if (((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE) && strncmp(rmp->mp_name, search_key, key_len)==0) { mp->mp_reply.endpt = rmp->mp_endpoint; printf("PM: name %s result: %d\n", search_key, diff --git a/servers/pm/mproc.h b/servers/pm/mproc.h index a0e961345..2dce02e02 100644 --- a/servers/pm/mproc.h +++ b/servers/pm/mproc.h @@ -65,7 +65,7 @@ EXTERN struct mproc { /* Flag values */ #define IN_USE 0x001 /* set when 'mproc' slot in use */ #define WAITING 0x002 /* set by WAIT system call */ -#define ZOMBIE 0x004 /* set by EXIT, cleared by WAIT */ +#define ZOMBIE 0x004 /* waiting for parent to issue WAIT call */ #define PAUSED 0x008 /* set by PAUSE system call */ #define ALARM_ON 0x010 /* set when SIGALRM timer started */ #define TRACED 0x040 /* set if process is to be traced */ @@ -76,6 +76,7 @@ EXTERN struct mproc { #define PM_SIG_PENDING 0x4000 /* process got a signal while waiting for FS */ #define PARTIAL_EXEC 0x8000 /* Process got a new map but no content */ #define TOLD_PARENT 0x10000 /* Parent wait() completed, ZOMBIE off */ +#define EXITING 0x20000 /* set by EXIT, process is now exiting */ #define NIL_MPROC ((struct mproc *) 0) diff --git a/servers/pm/signal.c b/servers/pm/signal.c index f43e33830..21d8d31c6 100644 --- a/servers/pm/signal.c +++ b/servers/pm/signal.c @@ -230,7 +230,7 @@ PUBLIC int ksig_pending() /* If the process still exists to the kernel after the signal * has been handled ... */ - if ((mproc[proc_nr_p].mp_flags & (IN_USE | ZOMBIE)) == IN_USE) + if ((mproc[proc_nr_p].mp_flags & (IN_USE | EXITING)) == IN_USE) { if((r=sys_endksig(proc_nr_e)) != OK) /* ... tell kernel it's done */ panic(__FILE__,"sys_endksig failed", r); @@ -256,8 +256,8 @@ sigset_t sig_map; return; } rmp = &mproc[proc_nr]; - if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) { - printf("PM: handle_ksig: %d?? zombie / not in use\n", proc_nr_e); + if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) { + printf("PM: handle_ksig: %d?? exiting / not in use\n", proc_nr_e); return; } proc_id = rmp->mp_pid; @@ -379,7 +379,7 @@ struct timer *tp; rmp = &mproc[proc_nr_n]; - if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return; + if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) return; if ((rmp->mp_flags & ALARM_ON) == 0) return; rmp->mp_flags &= ~ALARM_ON; check_sig(rmp->mp_pid, SIGALRM); @@ -424,9 +424,8 @@ int signo; /* signal to send to process (1 to _NSIG) */ int exit_type; slot = (int) (rmp - mproc); - if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) { - printf("PM: signal %d sent to %s process %d\n", - signo, (rmp->mp_flags & ZOMBIE) ? "zombie" : "dead", slot); + if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) { + printf("PM: signal %d sent to exiting process %d\n", signo, slot); panic(__FILE__,"", NO_NUM); } if (rmp->mp_fs_call != PM_IDLE || rmp->mp_fs_call2 != PM_IDLE) @@ -551,13 +550,12 @@ int signo; /* signal to send to process (0 to _NSIG) */ if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL); /* Search the proc table for processes to signal. - * (See forkexit.c aboutpid magic.) + * (See forkexit.c about pid magic.) */ count = 0; error_code = ESRCH; for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { if (!(rmp->mp_flags & IN_USE)) continue; - if ((rmp->mp_flags & ZOMBIE) && signo != 0) continue; /* Check for selection. */ if (proc_id > 0 && proc_id != rmp->mp_pid) continue; @@ -580,7 +578,7 @@ int signo; /* signal to send to process (0 to _NSIG) */ } count++; - if (signo == 0) continue; + if (signo == 0 || (rmp->mp_flags & EXITING)) continue; /* 'sig_proc' will handle the disposition of the signal. The * signal may be caught, blocked, ignored, or cause process @@ -592,7 +590,7 @@ int signo; /* signal to send to process (0 to _NSIG) */ } /* If the calling process has killed itself, don't reply. */ - if ((mp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return(SUSPEND); + if ((mp->mp_flags & (IN_USE | EXITING)) != IN_USE) return(SUSPEND); return(count > 0 ? OK : error_code); } diff --git a/servers/pm/trace.c b/servers/pm/trace.c index 8e8622c95..3a0e1c7a2 100644 --- a/servers/pm/trace.c +++ b/servers/pm/trace.c @@ -144,7 +144,7 @@ pid_t lpid; register struct mproc *rmp; for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) - if ((rmp->mp_flags & (IN_USE | ZOMBIE)) == IN_USE && + if ((rmp->mp_flags & (IN_USE | EXITING)) == IN_USE && rmp->mp_pid == lpid) { return(rmp); }