pm - fix sched interaction
[minix.git] / servers / pm / forkexit.c
bloba7900800f72d117c02d49a40572cf97502656ad7
1 /* This file deals with creating processes (via FORK) and deleting them (via
2 * EXIT/WAIT). 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 WAIT. If the process
7 * exits first, it continues to occupy a slot until the parent does a WAIT.
9 * The entry points into this file are:
10 * do_fork: perform the FORK system call
11 * do_srv_fork: special FORK, used by RS to create sys services
12 * do_exit: perform the EXIT system call (by calling exit_proc())
13 * exit_proc: actually do the exiting, and tell FS about it
14 * exit_restart: continue exiting a process after FS has replied
15 * do_waitpid: perform the WAITPID or WAIT system call
16 * wait_test: check whether a parent is waiting for a child
19 #include "pm.h"
20 #include <sys/wait.h>
21 #include <minix/callnr.h>
22 #include <minix/com.h>
23 #include <minix/vm.h>
24 #include <sys/ptrace.h>
25 #include <sys/resource.h>
26 #include <signal.h>
27 #include "mproc.h"
28 #include "param.h"
30 #define LAST_FEW 2 /* last few slots reserved for superuser */
32 FORWARD _PROTOTYPE (void zombify, (struct mproc *rmp) );
33 FORWARD _PROTOTYPE (void check_parent, (struct mproc *child,
34 int try_cleanup) );
35 FORWARD _PROTOTYPE (void tell_parent, (struct mproc *child) );
36 FORWARD _PROTOTYPE (void tell_tracer, (struct mproc *child) );
37 FORWARD _PROTOTYPE (void tracer_died, (struct mproc *child) );
38 FORWARD _PROTOTYPE (void cleanup, (register struct mproc *rmp) );
40 /*===========================================================================*
41 * do_fork *
42 *===========================================================================*/
43 PUBLIC int do_fork()
45 /* The process pointed to by 'mp' has forked. Create a child process. */
46 register struct mproc *rmp; /* pointer to parent */
47 register struct mproc *rmc; /* pointer to child */
48 pid_t new_pid;
49 static int next_child;
50 int i, n = 0, s;
51 endpoint_t child_ep;
52 message m;
54 /* If tables might fill up during FORK, don't even start since recovery half
55 * way through is such a nuisance.
57 rmp = mp;
58 if ((procs_in_use == NR_PROCS) ||
59 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
61 printf("PM: warning, process table is full!\n");
62 return(EAGAIN);
65 /* Find a slot in 'mproc' for the child process. A slot must exist. */
66 do {
67 next_child = (next_child+1) % NR_PROCS;
68 n++;
69 } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
70 if(n > NR_PROCS)
71 panic("do_fork can't find child slot");
72 if(next_child < 0 || next_child >= NR_PROCS
73 || (mproc[next_child].mp_flags & IN_USE))
74 panic("do_fork finds wrong child slot: %d", next_child);
76 /* Memory part of the forking. */
77 if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
78 printf("PM: vm_fork failed: %d\n", s);
79 return s;
82 /* PM may not fail fork after call to vm_fork(), as VM calls sys_fork(). */
84 rmc = &mproc[next_child];
85 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
86 procs_in_use++;
87 *rmc = *rmp; /* copy parent's process slot to child's */
88 rmc->mp_parent = who_p; /* record child's parent */
89 if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
90 rmc->mp_tracer = NO_TRACER; /* no tracer attached */
91 rmc->mp_trace_flags = 0;
92 sigemptyset(&rmc->mp_sigtrace);
94 /* Inherit only these flags. In normal fork(), PRIV_PROC is not inherited. */
95 rmc->mp_flags &= (IN_USE|DELAY_CALL);
96 rmc->mp_child_utime = 0; /* reset administration */
97 rmc->mp_child_stime = 0; /* reset administration */
98 rmc->mp_exitstatus = 0;
99 rmc->mp_sigstatus = 0;
100 rmc->mp_endpoint = child_ep; /* passed back by VM */
101 for (i = 0; i < NR_ITIMERS; i++)
102 rmc->mp_interval[i] = 0; /* reset timer intervals */
104 /* Find a free pid for the child and put it in the table. */
105 new_pid = get_free_pid();
106 rmc->mp_pid = new_pid; /* assign pid to child */
108 m.m_type = PM_FORK;
109 m.PM_PROC = rmc->mp_endpoint;
110 m.PM_PPROC = rmp->mp_endpoint;
111 m.PM_CPID = rmc->mp_pid;
113 tell_fs(rmc, &m);
115 /* Tell the tracer, if any, about the new child */
116 if (rmc->mp_tracer != NO_TRACER)
117 sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);
119 /* Do not reply until FS is ready to process the fork
120 * request
122 return SUSPEND;
125 /*===========================================================================*
126 * do_srv_fork *
127 *===========================================================================*/
128 PUBLIC int do_srv_fork()
130 /* The process pointed to by 'mp' has forked. Create a child process. */
131 register struct mproc *rmp; /* pointer to parent */
132 register struct mproc *rmc; /* pointer to child */
133 int s;
134 pid_t new_pid;
135 static int next_child;
136 int i, n = 0;
137 endpoint_t child_ep;
138 message m;
140 /* Only RS is allowed to use srv_fork. */
141 if (mp->mp_endpoint != RS_PROC_NR)
142 return EPERM;
144 /* If tables might fill up during FORK, don't even start since recovery half
145 * way through is such a nuisance.
147 rmp = mp;
148 if ((procs_in_use == NR_PROCS) ||
149 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
151 printf("PM: warning, process table is full!\n");
152 return(EAGAIN);
155 /* Find a slot in 'mproc' for the child process. A slot must exist. */
156 do {
157 next_child = (next_child+1) % NR_PROCS;
158 n++;
159 } while((mproc[next_child].mp_flags & IN_USE) && n <= NR_PROCS);
160 if(n > NR_PROCS)
161 panic("do_fork can't find child slot");
162 if(next_child < 0 || next_child >= NR_PROCS
163 || (mproc[next_child].mp_flags & IN_USE))
164 panic("do_fork finds wrong child slot: %d", next_child);
166 if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
167 printf("PM: vm_fork failed: %d\n", s);
168 return s;
171 rmc = &mproc[next_child];
172 /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
173 procs_in_use++;
174 *rmc = *rmp; /* copy parent's process slot to child's */
175 rmc->mp_parent = who_p; /* record child's parent */
176 if (!(rmc->mp_trace_flags & TO_TRACEFORK)) {
177 rmc->mp_tracer = NO_TRACER; /* no tracer attached */
178 rmc->mp_trace_flags = 0;
179 sigemptyset(&rmc->mp_sigtrace);
181 /* inherit only these flags */
182 rmc->mp_flags &= (IN_USE|PRIV_PROC|DELAY_CALL);
183 rmc->mp_child_utime = 0; /* reset administration */
184 rmc->mp_child_stime = 0; /* reset administration */
185 rmc->mp_exitstatus = 0;
186 rmc->mp_sigstatus = 0;
187 rmc->mp_endpoint = child_ep; /* passed back by VM */
188 for (i = 0; i < NR_ITIMERS; i++)
189 rmc->mp_interval[i] = 0; /* reset timer intervals */
191 /* Find a free pid for the child and put it in the table. */
192 new_pid = get_free_pid();
193 rmc->mp_pid = new_pid; /* assign pid to child */
195 m.m_type = PM_SRV_FORK;
196 m.PM_PROC = rmc->mp_endpoint;
197 m.PM_PPROC = rmp->mp_endpoint;
198 m.PM_CPID = rmc->mp_pid;
200 tell_fs(rmc, &m);
202 /* Tell the tracer, if any, about the new child */
203 if (rmc->mp_tracer != NO_TRACER)
204 sig_proc(rmc, SIGSTOP, TRUE /*trace*/, FALSE /* ksig */);
206 /* Wakeup the newly created process */
207 setreply(rmc-mproc, OK);
209 return rmc->mp_pid;
212 /*===========================================================================*
213 * do_exit *
214 *===========================================================================*/
215 PUBLIC int do_exit()
217 /* Perform the exit(status) system call. The real work is done by exit_proc(),
218 * which is also called when a process is killed by a signal. System processes
219 * do not use PM's exit() to terminate. If they try to, we warn the user
220 * and send a SIGKILL signal to the system process.
222 if(mp->mp_flags & PRIV_PROC) {
223 printf("PM: system process %d (%s) tries to exit(), sending SIGKILL\n",
224 mp->mp_endpoint, mp->mp_name);
225 sys_kill(mp->mp_endpoint, SIGKILL);
227 else {
228 exit_proc(mp, m_in.status, FALSE /*dump_core*/);
230 return(SUSPEND); /* can't communicate from beyond the grave */
233 /*===========================================================================*
234 * exit_proc *
235 *===========================================================================*/
236 PUBLIC void exit_proc(rmp, exit_status, dump_core)
237 register struct mproc *rmp; /* pointer to the process to be terminated */
238 int exit_status; /* the process' exit status (for parent) */
239 int dump_core; /* flag indicating whether to dump core */
241 /* A process is done. Release most of the process' possessions. If its
242 * parent is waiting, release the rest, else keep the process slot and
243 * become a zombie.
245 register int proc_nr, proc_nr_e;
246 int r;
247 pid_t procgrp;
248 struct mproc *p_mp;
249 clock_t user_time, sys_time;
250 message m;
252 /* Do not create core files for set uid execution */
253 if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
254 dump_core = FALSE;
256 /* System processes are destroyed before informing FS, meaning that FS can
257 * not get their CPU state, so we can't generate a coredump for them either.
259 if (dump_core && (rmp->mp_flags & PRIV_PROC))
260 dump_core = FALSE;
262 proc_nr = (int) (rmp - mproc); /* get process slot number */
263 proc_nr_e = rmp->mp_endpoint;
265 /* Remember a session leader's process group. */
266 procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
268 /* If the exited process has a timer pending, kill it. */
269 if (rmp->mp_flags & ALARM_ON) set_alarm(rmp, (clock_t) 0);
271 /* Do accounting: fetch usage times and accumulate at parent. */
272 if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL, NULL)) != OK)
273 panic("exit_proc: sys_times failed: %d", r);
275 p_mp = &mproc[rmp->mp_parent]; /* process' parent */
276 p_mp->mp_child_utime += user_time + rmp->mp_child_utime; /* add user time */
277 p_mp->mp_child_stime += sys_time + rmp->mp_child_stime; /* add system time */
279 /* Tell the kernel the process is no longer runnable to prevent it from
280 * being scheduled in between the following steps. Then tell FS that it
281 * the process has exited and finally, clean up the process at the kernel.
282 * This order is important so that FS can tell drivers to cancel requests
283 * such as copying to/ from the exiting process, before it is gone.
285 if ((r = sys_stop(proc_nr_e)) != OK) /* stop the process */
286 panic("sys_stop failed: %d", r);
288 if((r=vm_willexit(proc_nr_e)) != OK) {
289 panic("exit_proc: vm_willexit failed: %d", r);
291 vm_notify_sig_wrapper(rmp->mp_endpoint);
292 if (proc_nr_e == INIT_PROC_NR)
294 printf("PM: INIT died\n");
295 return;
297 if (proc_nr_e == FS_PROC_NR)
299 panic("exit_proc: FS died: %d", r);
302 /* Tell FS about the exiting process. */
303 m.m_type = dump_core ? PM_DUMPCORE : PM_EXIT;
304 m.PM_PROC = rmp->mp_endpoint;
306 tell_fs(rmp, &m);
308 if (rmp->mp_flags & PRIV_PROC)
310 /* Destroy system processes without waiting for FS. This is
311 * needed because the system process might be a block device
312 * driver that FS is blocked waiting on.
314 if((r= sys_clear(rmp->mp_endpoint)) != OK)
315 panic("exit_proc: sys_clear failed: %d", r);
318 /* Clean up most of the flags describing the process's state before the exit,
319 * and mark it as exiting.
321 rmp->mp_flags &= (IN_USE|FS_CALL|PRIV_PROC|TRACE_EXIT);
322 rmp->mp_flags |= EXITING;
324 /* Keep the process around until FS is finished with it. */
326 rmp->mp_exitstatus = (char) exit_status;
328 /* For normal exits, try to notify the parent as soon as possible.
329 * For core dumps, notify the parent only once the core dump has been made.
331 if (!dump_core)
332 zombify(rmp);
334 /* If the process has children, disinherit them. INIT is the new parent. */
335 for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
336 if (!(rmp->mp_flags & IN_USE)) continue;
337 if (rmp->mp_tracer == proc_nr) {
338 /* This child's tracer died. Do something sensible. */
339 tracer_died(rmp);
341 if (rmp->mp_parent == proc_nr) {
342 /* 'rmp' now points to a child to be disinherited. */
343 rmp->mp_parent = INIT_PROC_NR;
345 /* Notify new parent. */
346 if (rmp->mp_flags & ZOMBIE)
347 check_parent(rmp, TRUE /*try_cleanup*/);
351 /* Send a hangup to the process' process group if it was a session leader. */
352 if (procgrp != 0) check_sig(-procgrp, SIGHUP, FALSE /* ksig */);
355 /*===========================================================================*
356 * exit_restart *
357 *===========================================================================*/
358 PUBLIC void exit_restart(rmp, dump_core)
359 struct mproc *rmp; /* pointer to the process being terminated */
360 int dump_core; /* flag indicating whether to dump core */
362 /* FS replied to our exit or coredump request. Perform the second half of the
363 * exit code.
365 int r;
367 if((r = sched_stop(rmp)) != OK) {
368 /* If the scheduler refuses to give up scheduling, there is
369 * little we can do, except report it. This may cause problems
370 * later on, if this scheduler is asked to schedule another proc
371 * that has an endpoint->schedproc mapping identical to the proc
372 * we just tried to stop scheduling.
374 printf("PM: The scheduler did not want to give up "
375 "scheduling %s, ret=%d.\n", rmp->mp_name, r);
378 /* For core dumps, now is the right time to try to contact the parent. */
379 if (dump_core)
380 zombify(rmp);
382 if (!(rmp->mp_flags & PRIV_PROC))
384 /* destroy the (user) process */
385 if((r=sys_clear(rmp->mp_endpoint)) != OK)
386 panic("exit_restart: sys_clear failed: %d", r);
389 /* Release the memory occupied by the child. */
390 if((r=vm_exit(rmp->mp_endpoint)) != OK) {
391 panic("exit_restart: vm_exit failed: %d", r);
394 if (rmp->mp_flags & TRACE_EXIT)
396 /* Wake up the tracer, completing the ptrace(T_EXIT) call */
397 mproc[rmp->mp_tracer].mp_reply.reply_trace = 0;
398 setreply(rmp->mp_tracer, OK);
401 /* Clean up if the parent has collected the exit status */
402 if (rmp->mp_flags & TOLD_PARENT)
403 cleanup(rmp);
406 /*===========================================================================*
407 * do_waitpid *
408 *===========================================================================*/
409 PUBLIC int do_waitpid()
411 /* A process wants to wait for a child to terminate. If a child is already
412 * waiting, go clean it up and let this WAIT call terminate. Otherwise,
413 * really wait.
414 * A process calling WAIT never gets a reply in the usual way at the end
415 * of the main loop (unless WNOHANG is set or no qualifying child exists).
416 * If a child has already exited, the routine tell_parent() sends the reply
417 * to awaken the caller.
418 * Both WAIT and WAITPID are handled by this code.
420 register struct mproc *rp;
421 int i, pidarg, options, children;
423 /* Set internal variables, depending on whether this is WAIT or WAITPID. */
424 pidarg = (call_nr == WAIT ? -1 : m_in.pid); /* 1st param of waitpid */
425 options = (call_nr == WAIT ? 0 : m_in.sig_nr); /* 3rd param of waitpid */
426 if (pidarg == 0) pidarg = -mp->mp_procgrp; /* pidarg < 0 ==> proc grp */
428 /* Is there a child waiting to be collected? At this point, pidarg != 0:
429 * pidarg > 0 means pidarg is pid of a specific process to wait for
430 * pidarg == -1 means wait for any child
431 * pidarg < -1 means wait for any child whose process group = -pidarg
433 children = 0;
434 for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
435 if ((rp->mp_flags & (IN_USE | TOLD_PARENT)) != IN_USE) continue;
436 if (rp->mp_parent != who_p && rp->mp_tracer != who_p) continue;
437 if (rp->mp_parent != who_p && (rp->mp_flags & ZOMBIE)) continue;
439 /* The value of pidarg determines which children qualify. */
440 if (pidarg > 0 && pidarg != rp->mp_pid) continue;
441 if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
443 children++; /* this child is acceptable */
445 if (rp->mp_tracer == who_p) {
446 if (rp->mp_flags & TRACE_ZOMBIE) {
447 /* Traced child meets the pid test and has exited. */
448 tell_tracer(rp);
449 check_parent(rp, TRUE /*try_cleanup*/);
450 return(SUSPEND);
452 if (rp->mp_flags & STOPPED) {
453 /* This child meets the pid test and is being traced.
454 * Deliver a signal to the tracer, if any.
456 for (i = 1; i < _NSIG; i++) {
457 if (sigismember(&rp->mp_sigtrace, i)) {
458 sigdelset(&rp->mp_sigtrace, i);
460 mp->mp_reply.reply_res2 =
461 0177 | (i << 8);
462 return(rp->mp_pid);
468 if (rp->mp_parent == who_p) {
469 if (rp->mp_flags & ZOMBIE) {
470 /* This child meets the pid test and has exited. */
471 tell_parent(rp); /* this child has already exited */
472 if (!(rp->mp_flags & FS_CALL))
473 cleanup(rp);
474 return(SUSPEND);
479 /* No qualifying child has exited. Wait for one, unless none exists. */
480 if (children > 0) {
481 /* At least 1 child meets the pid test exists, but has not exited. */
482 if (options & WNOHANG) {
483 return(0); /* parent does not want to wait */
485 mp->mp_flags |= WAITING; /* parent wants to wait */
486 mp->mp_wpid = (pid_t) pidarg; /* save pid for later */
487 return(SUSPEND); /* do not reply, let it wait */
488 } else {
489 /* No child even meets the pid test. Return error immediately. */
490 return(ECHILD); /* no - parent has no children */
494 /*===========================================================================*
495 * wait_test *
496 *===========================================================================*/
497 PUBLIC int wait_test(rmp, child)
498 struct mproc *rmp; /* process that may be waiting */
499 struct mproc *child; /* process that may be waited for */
501 /* See if a parent or tracer process is waiting for a child process.
502 * A tracer is considered to be a pseudo-parent.
504 int parent_waiting, right_child;
505 pid_t pidarg;
507 pidarg = rmp->mp_wpid; /* who's being waited for? */
508 parent_waiting = rmp->mp_flags & WAITING;
509 right_child = /* child meets one of the 3 tests? */
510 (pidarg == -1 || pidarg == child->mp_pid ||
511 -pidarg == child->mp_procgrp);
513 return (parent_waiting && right_child);
516 /*===========================================================================*
517 * zombify *
518 *===========================================================================*/
519 PRIVATE void zombify(rmp)
520 struct mproc *rmp;
522 /* Zombify a process. First check if the exiting process is traced by a process
523 * other than its parent; if so, the tracer must be notified about the exit
524 * first. Once that is done, the real parent may be notified about the exit of
525 * its child.
527 struct mproc *t_mp;
529 if (rmp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
530 panic("zombify: process was already a zombie");
532 /* See if we have to notify a tracer process first. */
533 if (rmp->mp_tracer != NO_TRACER && rmp->mp_tracer != rmp->mp_parent) {
534 rmp->mp_flags |= TRACE_ZOMBIE;
536 t_mp = &mproc[rmp->mp_tracer];
538 /* Do not bother sending SIGCHLD signals to tracers. */
539 if (!wait_test(t_mp, rmp))
540 return;
542 tell_tracer(rmp);
544 else {
545 rmp->mp_flags |= ZOMBIE;
548 /* No tracer, or tracer is parent, or tracer has now been notified. */
549 check_parent(rmp, FALSE /*try_cleanup*/);
552 /*===========================================================================*
553 * check_parent *
554 *===========================================================================*/
555 PRIVATE void check_parent(child, try_cleanup)
556 struct mproc *child; /* tells which process is exiting */
557 int try_cleanup; /* clean up the child when done? */
559 /* We would like to inform the parent of an exiting child about the child's
560 * death. If the parent is waiting for the child, tell it immediately;
561 * otherwise, send it a SIGCHLD signal.
563 * Note that we may call this function twice on a single child; first with
564 * its original parent, later (if the parent died) with INIT as its parent.
566 struct mproc *p_mp;
568 p_mp = &mproc[child->mp_parent];
570 if (p_mp->mp_flags & EXITING) {
571 /* This may trigger if the child of a dead parent dies. The child will
572 * be assigned to INIT and rechecked shortly after. Do nothing.
575 else if (wait_test(p_mp, child)) {
576 tell_parent(child);
578 /* The 'try_cleanup' flag merely saves us from having to be really
579 * careful with statement ordering in exit_proc() and exit_restart().
581 if (try_cleanup && !(child->mp_flags & FS_CALL))
582 cleanup(child);
584 else {
585 /* Parent is not waiting. */
586 sig_proc(p_mp, SIGCHLD, TRUE /*trace*/, FALSE /* ksig */);
590 /*===========================================================================*
591 * tell_parent *
592 *===========================================================================*/
593 PRIVATE void tell_parent(child)
594 register struct mproc *child; /* tells which process is exiting */
596 int exitstatus, mp_parent;
597 struct mproc *parent;
599 mp_parent= child->mp_parent;
600 if (mp_parent <= 0)
601 panic("tell_parent: bad value in mp_parent: %d", mp_parent);
602 if(!(child->mp_flags & ZOMBIE))
603 panic("tell_parent: child not a zombie");
604 if(child->mp_flags & TOLD_PARENT)
605 panic("tell_parent: telling parent again");
606 parent = &mproc[mp_parent];
608 /* Wake up the parent by sending the reply message. */
609 exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
610 parent->mp_reply.reply_res2 = exitstatus;
611 setreply(child->mp_parent, child->mp_pid);
612 parent->mp_flags &= ~WAITING; /* parent no longer waiting */
613 child->mp_flags &= ~ZOMBIE; /* child no longer a zombie */
614 child->mp_flags |= TOLD_PARENT; /* avoid informing parent twice */
617 /*===========================================================================*
618 * tell_tracer *
619 *===========================================================================*/
620 PRIVATE void tell_tracer(child)
621 struct mproc *child; /* tells which process is exiting */
623 int exitstatus, mp_tracer;
624 struct mproc *tracer;
626 mp_tracer = child->mp_tracer;
627 if (mp_tracer <= 0)
628 panic("tell_tracer: bad value in mp_tracer: %d", mp_tracer);
629 if(!(child->mp_flags & TRACE_ZOMBIE))
630 panic("tell_tracer: child not a zombie");
631 tracer = &mproc[mp_tracer];
633 exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
634 tracer->mp_reply.reply_res2 = exitstatus;
635 setreply(child->mp_tracer, child->mp_pid);
636 tracer->mp_flags &= ~WAITING; /* tracer no longer waiting */
637 child->mp_flags &= ~TRACE_ZOMBIE; /* child no longer zombie to tracer */
638 child->mp_flags |= ZOMBIE; /* child is now zombie to parent */
641 /*===========================================================================*
642 * tracer_died *
643 *===========================================================================*/
644 PRIVATE void tracer_died(child)
645 struct mproc *child; /* process being traced */
647 /* The process that was tracing the given child, has died for some reason.
648 * This is really the tracer's fault, but we can't let INIT deal with this.
651 child->mp_tracer = NO_TRACER;
652 child->mp_flags &= ~TRACE_EXIT;
654 /* If the tracer died while the child was running or stopped, we have no
655 * idea what state the child is in. Avoid a trainwreck, by killing the child.
656 * Note that this may cause cascading exits.
658 if (!(child->mp_flags & EXITING)) {
659 sig_proc(child, SIGKILL, TRUE /*trace*/, FALSE /* ksig */);
661 return;
664 /* If the tracer died while the child was telling it about its own death,
665 * forget about the tracer and notify the real parent instead.
667 if (child->mp_flags & TRACE_ZOMBIE) {
668 child->mp_flags &= ~TRACE_ZOMBIE;
669 child->mp_flags |= ZOMBIE;
671 check_parent(child, TRUE /*try_cleanup*/);
675 /*===========================================================================*
676 * cleanup *
677 *===========================================================================*/
678 PRIVATE void cleanup(rmp)
679 register struct mproc *rmp; /* tells which process is exiting */
681 /* Release the process table entry and reinitialize some field. */
682 rmp->mp_pid = 0;
683 rmp->mp_flags = 0;
684 rmp->mp_child_utime = 0;
685 rmp->mp_child_stime = 0;
686 procs_in_use--;