xref: /minix/minix/servers/pm/forkexit.c (revision 83133719)
1 /* This file deals with creating processes (via FORK) and deleting them (via
2  * EXIT/WAITPID).  When a process forks, a new slot in the 'mproc' table is
3  * allocated for it, and a copy of the parent's core image is made for the
4  * child.  Then the kernel and file system are informed.  A process is removed
5  * from the 'mproc' table when two events have occurred: (1) it has exited or
6  * been killed by a signal, and (2) the parent has done a WAITPID.  If the
7  * process exits first, it continues to occupy a slot until the parent does a
8  * WAITPID.
9  *
10  * The entry points into this file are:
11  *   do_fork:		perform the FORK system call
12  *   do_srv_fork:	special FORK, used by RS to create sys services
13  *   do_exit:		perform the EXIT system call (by calling exit_proc())
14  *   exit_proc:		actually do the exiting, and tell VFS about it
15  *   exit_restart:	continue exiting a process after VFS has replied
16  *   do_waitpid:	perform the WAITPID system call
17  *   wait_test:		check whether a parent is waiting for a child
18  */
19 
20 #include "pm.h"
21 #include <sys/wait.h>
22 #include <assert.h>
23 #include <minix/callnr.h>
24 #include <minix/com.h>
25 #include <minix/sched.h>
26 #include <minix/vm.h>
27 #include <sys/ptrace.h>
28 #include <sys/resource.h>
29 #include <signal.h>
30 #include "mproc.h"
31 
32 #define LAST_FEW            2	/* last few slots reserved for superuser */
33 
34 static void zombify(struct mproc *rmp);
35 static void check_parent(struct mproc *child, int try_cleanup);
36 static void tell_parent(struct mproc *child);
37 static void tell_tracer(struct mproc *child);
38 static void tracer_died(struct mproc *child);
39 static void cleanup(register struct mproc *rmp);
40 
41 /*===========================================================================*
42  *				do_fork					     *
43  *===========================================================================*/
44 int do_fork()
45 {
46 /* The process pointed to by 'mp' has forked.  Create a child process. */
47   register struct mproc *rmp;	/* pointer to parent */
48   register struct mproc *rmc;	/* pointer to child */
49   pid_t new_pid;
50   static unsigned int next_child = 0;
51   int i, n = 0, s;
52   endpoint_t child_ep;
53   message m;
54 
55  /* If tables might fill up during FORK, don't even start since recovery half
56   * way through is such a nuisance.
57   */
58   rmp = mp;
59   if ((procs_in_use == NR_PROCS) ||
60   		(procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
61   {
62   	printf("PM: warning, process table is full!\n");
63   	return(EAGAIN);
64   }
65 
66   /* Find a slot in 'mproc' for the child process.  A slot must exist. */
67   do {
68         next_child = (next_child+1) % NR_PROCS;
69 	n++;
70   } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
71   if(n > NR_PROCS)
72 	panic("do_fork can't find child slot");
73   if(next_child >= NR_PROCS || (mproc[next_child].mp_flags & IN_USE))
74 	panic("do_fork finds wrong child slot: %d", next_child);
75 
76   /* Memory part of the forking. */
77   if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
78 	return s;
79   }
80 
81   /* PM may not fail fork after call to vm_fork(), as VM calls sys_fork(). */
82 
83   rmc = &mproc[next_child];
84   /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
85   procs_in_use++;
86   *rmc = *rmp;			/* copy parent's process slot to child's */
87   rmc->mp_parent = who_p;			/* record child's parent */
88   if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
89 	rmc->mp_tracer = NO_TRACER;		/* no tracer attached */
90 	rmc->mp_trace_flags = 0;
91 	(void) sigemptyset(&rmc->mp_sigtrace);
92   }
93 
94   /* Some system servers like to call regular fork, such as RS spawning
95    * recovery scripts; in this case PM will take care of their scheduling
96    * because RS cannot do so for non-system processes */
97   if (rmc->mp_flags & PRIV_PROC) {
98 	assert(rmc->mp_scheduler == NONE);
99 	rmc->mp_scheduler = SCHED_PROC_NR;
100   }
101 
102   /* Inherit only these flags. In normal fork(), PRIV_PROC is not inherited. */
103   rmc->mp_flags &= (IN_USE|DELAY_CALL|TAINTED);
104   rmc->mp_child_utime = 0;		/* reset administration */
105   rmc->mp_child_stime = 0;		/* reset administration */
106   rmc->mp_exitstatus = 0;
107   rmc->mp_sigstatus = 0;
108   rmc->mp_endpoint = child_ep;		/* passed back by VM */
109   for (i = 0; i < NR_ITIMERS; i++)
110 	rmc->mp_interval[i] = 0;	/* reset timer intervals */
111 
112   /* Find a free pid for the child and put it in the table. */
113   new_pid = get_free_pid();
114   rmc->mp_pid = new_pid;	/* assign pid to child */
115 
116   memset(&m, 0, sizeof(m));
117   m.m_type = VFS_PM_FORK;
118   m.VFS_PM_ENDPT = rmc->mp_endpoint;
119   m.VFS_PM_PENDPT = rmp->mp_endpoint;
120   m.VFS_PM_CPID = rmc->mp_pid;
121   m.VFS_PM_REUID = -1;	/* Not used by VFS_PM_FORK */
122   m.VFS_PM_REGID = -1;	/* Not used by VFS_PM_FORK */
123 
124   tell_vfs(rmc, &m);
125 
126   /* Tell the tracer, if any, about the new child */
127   if (rmc->mp_tracer != NO_TRACER)
128 	sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);
129 
130   /* Do not reply until VFS is ready to process the fork
131   * request
132   */
133   return SUSPEND;
134 }
135 
136 /*===========================================================================*
137  *				do_srv_fork				     *
138  *===========================================================================*/
139 int do_srv_fork()
140 {
141 /* The process pointed to by 'mp' has forked.  Create a child process. */
142   register struct mproc *rmp;	/* pointer to parent */
143   register struct mproc *rmc;	/* pointer to child */
144   int s;
145   pid_t new_pid;
146   static unsigned int next_child = 0;
147   int i, n = 0;
148   endpoint_t child_ep;
149   message m;
150 
151   /* Only RS is allowed to use srv_fork. */
152   if (mp->mp_endpoint != RS_PROC_NR)
153 	return EPERM;
154 
155  /* If tables might fill up during FORK, don't even start since recovery half
156   * way through is such a nuisance.
157   */
158   rmp = mp;
159   if ((procs_in_use == NR_PROCS) ||
160   		(procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
161   {
162   	printf("PM: warning, process table is full!\n");
163   	return(EAGAIN);
164   }
165 
166   /* Find a slot in 'mproc' for the child process.  A slot must exist. */
167   do {
168         next_child = (next_child+1) % NR_PROCS;
169 	n++;
170   } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
171   if(n > NR_PROCS)
172 	panic("do_fork can't find child slot");
173   if(next_child >= NR_PROCS || (mproc[next_child].mp_flags & IN_USE))
174 	panic("do_fork finds wrong child slot: %d", next_child);
175 
176   if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
177 	return s;
178   }
179 
180   rmc = &mproc[next_child];
181   /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
182   procs_in_use++;
183   *rmc = *rmp;			/* copy parent's process slot to child's */
184   rmc->mp_parent = who_p;			/* record child's parent */
185   if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
186 	rmc->mp_tracer = NO_TRACER;		/* no tracer attached */
187 	rmc->mp_trace_flags = 0;
188 	(void) sigemptyset(&rmc->mp_sigtrace);
189   }
190   /* inherit only these flags */
191   rmc->mp_flags &= (IN_USE|PRIV_PROC|DELAY_CALL);
192   rmc->mp_child_utime = 0;		/* reset administration */
193   rmc->mp_child_stime = 0;		/* reset administration */
194   rmc->mp_exitstatus = 0;
195   rmc->mp_sigstatus = 0;
196   rmc->mp_endpoint = child_ep;		/* passed back by VM */
197   rmc->mp_realuid = m_in.m_lsys_pm_srv_fork.uid;
198   rmc->mp_effuid = m_in.m_lsys_pm_srv_fork.uid;
199   rmc->mp_realgid = m_in.m_lsys_pm_srv_fork.gid;
200   rmc->mp_effgid = m_in.m_lsys_pm_srv_fork.gid;
201   for (i = 0; i < NR_ITIMERS; i++)
202 	rmc->mp_interval[i] = 0;	/* reset timer intervals */
203 
204   /* Find a free pid for the child and put it in the table. */
205   new_pid = get_free_pid();
206   rmc->mp_pid = new_pid;	/* assign pid to child */
207 
208   memset(&m, 0, sizeof(m));
209   m.m_type = VFS_PM_SRV_FORK;
210   m.VFS_PM_ENDPT = rmc->mp_endpoint;
211   m.VFS_PM_PENDPT = rmp->mp_endpoint;
212   m.VFS_PM_CPID = rmc->mp_pid;
213   m.VFS_PM_REUID = m_in.m_lsys_pm_srv_fork.uid;
214   m.VFS_PM_REGID = m_in.m_lsys_pm_srv_fork.gid;
215 
216   tell_vfs(rmc, &m);
217 
218   /* Tell the tracer, if any, about the new child */
219   if (rmc->mp_tracer != NO_TRACER)
220 	sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);
221 
222   /* Wakeup the newly created process */
223   reply(rmc-mproc, OK);
224 
225   return rmc->mp_pid;
226 }
227 
228 /*===========================================================================*
229  *				do_exit					     *
230  *===========================================================================*/
231 int do_exit()
232 {
233  /* Perform the exit(status) system call. The real work is done by exit_proc(),
234   * which is also called when a process is killed by a signal. System processes
235   * do not use PM's exit() to terminate. If they try to, we warn the user
236   * and send a SIGKILL signal to the system process.
237   */
238   if(mp->mp_flags & PRIV_PROC) {
239       printf("PM: system process %d (%s) tries to exit(), sending SIGKILL\n",
240           mp->mp_endpoint, mp->mp_name);
241       sys_kill(mp->mp_endpoint, SIGKILL);
242   }
243   else {
244       exit_proc(mp, m_in.m_lc_pm_exit.status, FALSE /*dump_core*/);
245   }
246   return(SUSPEND);		/* can't communicate from beyond the grave */
247 }
248 
249 /*===========================================================================*
250  *				exit_proc				     *
251  *===========================================================================*/
252 void exit_proc(rmp, exit_status, dump_core)
253 register struct mproc *rmp;	/* pointer to the process to be terminated */
254 int exit_status;		/* the process' exit status (for parent) */
255 int dump_core;			/* flag indicating whether to dump core */
256 {
257 /* A process is done.  Release most of the process' possessions.  If its
258  * parent is waiting, release the rest, else keep the process slot and
259  * become a zombie.
260  */
261   register int proc_nr, proc_nr_e;
262   int r;
263   pid_t procgrp;
264   struct mproc *p_mp;
265   clock_t user_time, sys_time;
266   message m;
267 
268   /* Do not create core files for set uid execution */
269   if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
270 	dump_core = FALSE;
271 
272   /* System processes are destroyed before informing VFS, meaning that VFS can
273    * not get their CPU state, so we can't generate a coredump for them either.
274    */
275   if (dump_core && (rmp->mp_flags & PRIV_PROC))
276 	dump_core = FALSE;
277 
278   proc_nr = (int) (rmp - mproc);	/* get process slot number */
279   proc_nr_e = rmp->mp_endpoint;
280 
281   /* Remember a session leader's process group. */
282   procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
283 
284   /* If the exited process has a timer pending, kill it. */
285   if (rmp->mp_flags & ALARM_ON) set_alarm(rmp, (clock_t) 0);
286 
287   /* Do accounting: fetch usage times and accumulate at parent. */
288   if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL, NULL)) != OK)
289   	panic("exit_proc: sys_times failed: %d", r);
290 
291   p_mp = &mproc[rmp->mp_parent];			/* process' parent */
292   p_mp->mp_child_utime += user_time + rmp->mp_child_utime; /* add user time */
293   p_mp->mp_child_stime += sys_time + rmp->mp_child_stime; /* add system time */
294 
295   /* Tell the kernel the process is no longer runnable to prevent it from
296    * being scheduled in between the following steps. Then tell VFS that it
297    * the process has exited and finally, clean up the process at the kernel.
298    * This order is important so that VFS can tell drivers to cancel requests
299    * such as copying to/ from the exiting process, before it is gone.
300    */
301   /* If the process is not yet stopped, we force a stop here. This means that
302    * the process may still have a delay call pending. For this reason, the main
303    * message loop discards requests from exiting processes.
304    */
305   if (!(rmp->mp_flags & PROC_STOPPED)) {
306 	if ((r = sys_stop(proc_nr_e)) != OK)		/* stop the process */
307 		panic("sys_stop failed: %d", r);
308 	rmp->mp_flags |= PROC_STOPPED;
309   }
310 
311   if((r=vm_willexit(proc_nr_e)) != OK) {
312 	panic("exit_proc: vm_willexit failed: %d", r);
313   }
314   vm_notify_sig_wrapper(rmp->mp_endpoint);
315   if (proc_nr_e == INIT_PROC_NR)
316   {
317 	printf("PM: INIT died with exit status %d; showing stacktrace\n", exit_status);
318 	sys_diagctl_stacktrace(proc_nr_e);
319 	return;
320   }
321   if (proc_nr_e == VFS_PROC_NR)
322   {
323 	panic("exit_proc: VFS died: %d", r);
324   }
325 
326   /* Tell VFS about the exiting process. */
327   memset(&m, 0, sizeof(m));
328   m.m_type = dump_core ? VFS_PM_DUMPCORE : VFS_PM_EXIT;
329   m.VFS_PM_ENDPT = rmp->mp_endpoint;
330 
331   if (dump_core) {
332 	m.VFS_PM_TERM_SIG = rmp->mp_sigstatus;
333 	m.VFS_PM_PATH = rmp->mp_name;
334   }
335 
336   tell_vfs(rmp, &m);
337 
338   if (rmp->mp_flags & PRIV_PROC)
339   {
340 	/* Destroy system processes without waiting for VFS. This is
341 	 * needed because the system process might be a block device
342 	 * driver that VFS is blocked waiting on.
343 	 */
344 	if((r= sys_clear(rmp->mp_endpoint)) != OK)
345 		panic("exit_proc: sys_clear failed: %d", r);
346   }
347 
348   /* Clean up most of the flags describing the process's state before the exit,
349    * and mark it as exiting.
350    */
351   rmp->mp_flags &= (IN_USE|VFS_CALL|PRIV_PROC|TRACE_EXIT|PROC_STOPPED);
352   rmp->mp_flags |= EXITING;
353 
354   /* Keep the process around until VFS is finished with it. */
355 
356   rmp->mp_exitstatus = (char) exit_status;
357 
358   /* For normal exits, try to notify the parent as soon as possible.
359    * For core dumps, notify the parent only once the core dump has been made.
360    */
361   if (!dump_core)
362 	zombify(rmp);
363 
364   /* If the process has children, disinherit them.  INIT is the new parent. */
365   for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
366 	if (!(rmp->mp_flags & IN_USE)) continue;
367 	if (rmp->mp_tracer == proc_nr) {
368 		/* This child's tracer died. Do something sensible. */
369 		tracer_died(rmp);
370 	}
371 	if (rmp->mp_parent == proc_nr) {
372 		/* 'rmp' now points to a child to be disinherited. */
373 		rmp->mp_parent = INIT_PROC_NR;
374 
375 		/* If the process is making a VFS call, remember that we set
376 		 * a new parent. This prevents FORK from replying to the wrong
377 		 * parent upon completion.
378 		 */
379 		if (rmp->mp_flags & VFS_CALL)
380 			rmp->mp_flags |= NEW_PARENT;
381 
382 		/* Notify new parent. */
383 		if (rmp->mp_flags & ZOMBIE)
384 			check_parent(rmp, TRUE /*try_cleanup*/);
385 	}
386   }
387 
388   /* Send a hangup to the process' process group if it was a session leader. */
389   if (procgrp != 0) check_sig(-procgrp, SIGHUP, FALSE /* ksig */);
390 }
391 
392 /*===========================================================================*
393  *				exit_restart				     *
394  *===========================================================================*/
395 void exit_restart(rmp, dump_core)
396 struct mproc *rmp;		/* pointer to the process being terminated */
397 int dump_core;			/* flag indicating whether to dump core */
398 {
399 /* VFS replied to our exit or coredump request. Perform the second half of the
400  * exit code.
401  */
402   int r;
403 
404   if((r = sched_stop(rmp->mp_scheduler, rmp->mp_endpoint)) != OK) {
405  	/* If the scheduler refuses to give up scheduling, there is
406 	 * little we can do, except report it. This may cause problems
407 	 * later on, if this scheduler is asked to schedule another proc
408 	 * that has an endpoint->schedproc mapping identical to the proc
409 	 * we just tried to stop scheduling.
410 	*/
411 	printf("PM: The scheduler did not want to give up "
412 		"scheduling %s, ret=%d.\n", rmp->mp_name, r);
413   }
414 
415   /* sched_stop is either called when the process is exiting or it is
416    * being moved between schedulers. If it is being moved between
417    * schedulers, we need to set the mp_scheduler to NONE so that PM
418    * doesn't forward messages to the process' scheduler while being moved
419    * (such as sched_nice). */
420   rmp->mp_scheduler = NONE;
421 
422   /* For core dumps, now is the right time to try to contact the parent. */
423   if (dump_core)
424 	zombify(rmp);
425 
426   if (!(rmp->mp_flags & PRIV_PROC))
427   {
428 	/* destroy the (user) process */
429 	if((r=sys_clear(rmp->mp_endpoint)) != OK)
430 		panic("exit_restart: sys_clear failed: %d", r);
431   }
432 
433   /* Release the memory occupied by the child. */
434   if((r=vm_exit(rmp->mp_endpoint)) != OK) {
435   	panic("exit_restart: vm_exit failed: %d", r);
436   }
437 
438   if (rmp->mp_flags & TRACE_EXIT)
439   {
440 	/* Wake up the tracer, completing the ptrace(T_EXIT) call */
441 	mproc[rmp->mp_tracer].mp_reply.m_pm_lc_ptrace.data = 0;
442 	reply(rmp->mp_tracer, OK);
443   }
444 
445   /* Clean up if the parent has collected the exit status */
446   if (rmp->mp_flags & TOLD_PARENT)
447 	cleanup(rmp);
448 }
449 
450 /*===========================================================================*
451  *				do_waitpid				     *
452  *===========================================================================*/
453 int do_waitpid()
454 {
455 /* A process wants to wait for a child to terminate. If a child is already
456  * waiting, go clean it up and let this WAITPID call terminate.  Otherwise,
457  * really wait.
458  * A process calling WAITPID never gets a reply in the usual way at the end
459  * of the main loop (unless WNOHANG is set or no qualifying child exists).
460  * If a child has already exited, the routine tell_parent() sends the reply
461  * to awaken the caller.
462  */
463   register struct mproc *rp;
464   int i, pidarg, options, children;
465 
466   /* Set internal variables. */
467   pidarg  = m_in.m_lc_pm_waitpid.pid;		/* 1st param */
468   options = m_in.m_lc_pm_waitpid.options;	/* 3rd param */
469   if (pidarg == 0) pidarg = -mp->mp_procgrp;	/* pidarg < 0 ==> proc grp */
470 
471   /* Is there a child waiting to be collected? At this point, pidarg != 0:
472    *	pidarg  >  0 means pidarg is pid of a specific process to wait for
473    *	pidarg == -1 means wait for any child
474    *	pidarg  < -1 means wait for any child whose process group = -pidarg
475    */
476   children = 0;
477   for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
478 	if ((rp->mp_flags & (IN_USE | TOLD_PARENT)) != IN_USE) continue;
479 	if (rp->mp_parent != who_p && rp->mp_tracer != who_p) continue;
480 	if (rp->mp_parent != who_p && (rp->mp_flags & ZOMBIE)) continue;
481 
482 	/* The value of pidarg determines which children qualify. */
483 	if (pidarg  > 0 && pidarg != rp->mp_pid) continue;
484 	if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
485 
486 	children++;			/* this child is acceptable */
487 
488 	if (rp->mp_tracer == who_p) {
489 		if (rp->mp_flags & TRACE_ZOMBIE) {
490 			/* Traced child meets the pid test and has exited. */
491 			tell_tracer(rp);
492 			check_parent(rp, TRUE /*try_cleanup*/);
493 			return(SUSPEND);
494 		}
495 		if (rp->mp_flags & TRACE_STOPPED) {
496 			/* This child meets the pid test and is being traced.
497 			 * Deliver a signal to the tracer, if any.
498 			 */
499 			for (i = 1; i < _NSIG; i++) {
500 				if (sigismember(&rp->mp_sigtrace, i)) {
501 					sigdelset(&rp->mp_sigtrace, i);
502 
503 					mp->mp_reply.m_pm_lc_waitpid.status = W_STOPCODE(i);
504 					return(rp->mp_pid);
505 				}
506 			}
507 		}
508 	}
509 
510 	if (rp->mp_parent == who_p) {
511 		if (rp->mp_flags & ZOMBIE) {
512 			/* This child meets the pid test and has exited. */
513 			tell_parent(rp); /* this child has already exited */
514 			if (!(rp->mp_flags & VFS_CALL))
515 				cleanup(rp);
516 			return(SUSPEND);
517 		}
518 	}
519   }
520 
521   /* No qualifying child has exited.  Wait for one, unless none exists. */
522   if (children > 0) {
523 	/* At least 1 child meets the pid test exists, but has not exited. */
524 	if (options & WNOHANG) {
525 		return(0);    /* parent does not want to wait */
526 	}
527 	mp->mp_flags |= WAITING;	     /* parent wants to wait */
528 	mp->mp_wpid = (pid_t) pidarg;	     /* save pid for later */
529 	return(SUSPEND);		     /* do not reply, let it wait */
530   } else {
531 	/* No child even meets the pid test.  Return error immediately. */
532 	return(ECHILD);			     /* no - parent has no children */
533   }
534 }
535 
536 /*===========================================================================*
537  *				wait_test				     *
538  *===========================================================================*/
539 int wait_test(rmp, child)
540 struct mproc *rmp;			/* process that may be waiting */
541 struct mproc *child;			/* process that may be waited for */
542 {
543 /* See if a parent or tracer process is waiting for a child process.
544  * A tracer is considered to be a pseudo-parent.
545  */
546   int parent_waiting, right_child;
547   pid_t pidarg;
548 
549   pidarg = rmp->mp_wpid;		/* who's being waited for? */
550   parent_waiting = rmp->mp_flags & WAITING;
551   right_child =				/* child meets one of the 3 tests? */
552   	(pidarg == -1 || pidarg == child->mp_pid ||
553   	 -pidarg == child->mp_procgrp);
554 
555   return (parent_waiting && right_child);
556 }
557 
558 /*===========================================================================*
559  *				zombify					     *
560  *===========================================================================*/
561 static void zombify(rmp)
562 struct mproc *rmp;
563 {
564 /* Zombify a process. First check if the exiting process is traced by a process
565  * other than its parent; if so, the tracer must be notified about the exit
566  * first. Once that is done, the real parent may be notified about the exit of
567  * its child.
568  */
569   struct mproc *t_mp;
570 
571   if (rmp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
572 	panic("zombify: process was already a zombie");
573 
574   /* See if we have to notify a tracer process first. */
575   if (rmp->mp_tracer != NO_TRACER && rmp->mp_tracer != rmp->mp_parent) {
576 	rmp->mp_flags |= TRACE_ZOMBIE;
577 
578 	t_mp = &mproc[rmp->mp_tracer];
579 
580 	/* Do not bother sending SIGCHLD signals to tracers. */
581 	if (!wait_test(t_mp, rmp))
582 		return;
583 
584 	tell_tracer(rmp);
585   }
586   else {
587 	rmp->mp_flags |= ZOMBIE;
588   }
589 
590   /* No tracer, or tracer is parent, or tracer has now been notified. */
591   check_parent(rmp, FALSE /*try_cleanup*/);
592 }
593 
594 /*===========================================================================*
595  *				check_parent				     *
596  *===========================================================================*/
597 static void check_parent(child, try_cleanup)
598 struct mproc *child;			/* tells which process is exiting */
599 int try_cleanup;			/* clean up the child when done? */
600 {
601 /* We would like to inform the parent of an exiting child about the child's
602  * death. If the parent is waiting for the child, tell it immediately;
603  * otherwise, send it a SIGCHLD signal.
604  *
605  * Note that we may call this function twice on a single child; first with
606  * its original parent, later (if the parent died) with INIT as its parent.
607  */
608   struct mproc *p_mp;
609 
610   p_mp = &mproc[child->mp_parent];
611 
612   if (p_mp->mp_flags & EXITING) {
613 	/* This may trigger if the child of a dead parent dies. The child will
614 	 * be assigned to INIT and rechecked shortly after. Do nothing.
615 	 */
616   }
617   else if (wait_test(p_mp, child)) {
618 	tell_parent(child);
619 
620 	/* The 'try_cleanup' flag merely saves us from having to be really
621 	 * careful with statement ordering in exit_proc() and exit_restart().
622 	 */
623 	if (try_cleanup && !(child->mp_flags & VFS_CALL))
624 		cleanup(child);
625   }
626   else {
627 	/* Parent is not waiting. */
628 	sig_proc(p_mp, SIGCHLD, TRUE /*trace*/, FALSE /* ksig */);
629   }
630 }
631 
632 /*===========================================================================*
633  *				tell_parent				     *
634  *===========================================================================*/
635 static void tell_parent(child)
636 register struct mproc *child;	/* tells which process is exiting */
637 {
638   int mp_parent;
639   struct mproc *parent;
640 
641   mp_parent= child->mp_parent;
642   if (mp_parent <= 0)
643 	panic("tell_parent: bad value in mp_parent: %d", mp_parent);
644   if(!(child->mp_flags & ZOMBIE))
645   	panic("tell_parent: child not a zombie");
646   if(child->mp_flags & TOLD_PARENT)
647 	panic("tell_parent: telling parent again");
648   parent = &mproc[mp_parent];
649 
650   /* Wake up the parent by sending the reply message. */
651   parent->mp_reply.m_pm_lc_waitpid.status =
652 	W_EXITCODE(child->mp_exitstatus, child->mp_sigstatus);
653   reply(child->mp_parent, child->mp_pid);
654   parent->mp_flags &= ~WAITING;		/* parent no longer waiting */
655   child->mp_flags &= ~ZOMBIE;		/* child no longer a zombie */
656   child->mp_flags |= TOLD_PARENT;	/* avoid informing parent twice */
657 }
658 
659 /*===========================================================================*
660  *				tell_tracer				     *
661  *===========================================================================*/
662 static void tell_tracer(child)
663 struct mproc *child;			/* tells which process is exiting */
664 {
665   int mp_tracer;
666   struct mproc *tracer;
667 
668   mp_tracer = child->mp_tracer;
669   if (mp_tracer <= 0)
670 	panic("tell_tracer: bad value in mp_tracer: %d", mp_tracer);
671   if(!(child->mp_flags & TRACE_ZOMBIE))
672   	panic("tell_tracer: child not a zombie");
673   tracer = &mproc[mp_tracer];
674 
675   tracer->mp_reply.m_pm_lc_waitpid.status =
676 	W_EXITCODE(child->mp_exitstatus, (child->mp_sigstatus & 0377));
677   reply(child->mp_tracer, child->mp_pid);
678   tracer->mp_flags &= ~WAITING;		/* tracer no longer waiting */
679   child->mp_flags &= ~TRACE_ZOMBIE;	/* child no longer zombie to tracer */
680   child->mp_flags |= ZOMBIE;		/* child is now zombie to parent */
681 }
682 
683 /*===========================================================================*
684  *				tracer_died				     *
685  *===========================================================================*/
686 static void tracer_died(child)
687 struct mproc *child;			/* process being traced */
688 {
689 /* The process that was tracing the given child, has died for some reason.
690  * This is really the tracer's fault, but we can't let INIT deal with this.
691  */
692 
693   child->mp_tracer = NO_TRACER;
694   child->mp_flags &= ~TRACE_EXIT;
695 
696   /* If the tracer died while the child was running or stopped, we have no
697    * idea what state the child is in. Avoid a trainwreck, by killing the child.
698    * Note that this may cause cascading exits.
699    */
700   if (!(child->mp_flags & EXITING)) {
701 	sig_proc(child, SIGKILL, TRUE /*trace*/, FALSE /* ksig */);
702 
703 	return;
704   }
705 
706   /* If the tracer died while the child was telling it about its own death,
707    * forget about the tracer and notify the real parent instead.
708    */
709   if (child->mp_flags & TRACE_ZOMBIE) {
710 	child->mp_flags &= ~TRACE_ZOMBIE;
711 	child->mp_flags |= ZOMBIE;
712 
713 	check_parent(child, TRUE /*try_cleanup*/);
714   }
715 }
716 
717 /*===========================================================================*
718  *				cleanup					     *
719  *===========================================================================*/
720 static void cleanup(rmp)
721 register struct mproc *rmp;	/* tells which process is exiting */
722 {
723   /* Release the process table entry and reinitialize some field. */
724   rmp->mp_pid = 0;
725   rmp->mp_flags = 0;
726   rmp->mp_child_utime = 0;
727   rmp->mp_child_stime = 0;
728   procs_in_use--;
729 }
730 
731