tools/llvm: Do not build with symbols
[minix3.git] / minix / servers / pm / forkexit.c
blob218fff5e0ea73f2e101dc8e2089e8054f63e9606
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.
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
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"
32 #define LAST_FEW 2 /* last few slots reserved for superuser */
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);
41 /*===========================================================================*
42 * do_fork *
43 *===========================================================================*/
44 int do_fork()
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;
55 /* If tables might fill up during FORK, don't even start since recovery half
56 * way through is such a nuisance.
58 rmp = mp;
59 if ((procs_in_use == NR_PROCS) ||
60 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
62 printf("PM: warning, process table is full!\n");
63 return(EAGAIN);
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);
76 /* Memory part of the forking. */
77 if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
78 return s;
81 /* PM may not fail fork after call to vm_fork(), as VM calls sys_fork(). */
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);
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;
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 */
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 */
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 */
124 tell_vfs(rmc, &m);
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 */);
130 /* Do not reply until VFS is ready to process the fork
131 * request
133 return SUSPEND;
136 /*===========================================================================*
137 * do_srv_fork *
138 *===========================================================================*/
139 int do_srv_fork()
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;
151 /* Only RS is allowed to use srv_fork. */
152 if (mp->mp_endpoint != RS_PROC_NR)
153 return EPERM;
155 /* If tables might fill up during FORK, don't even start since recovery half
156 * way through is such a nuisance.
158 rmp = mp;
159 if ((procs_in_use == NR_PROCS) ||
160 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
162 printf("PM: warning, process table is full!\n");
163 return(EAGAIN);
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);
176 if((s=vm_fork(rmp->mp_endpoint, next_child, &child_ep)) != OK) {
177 return s;
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);
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 */
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 */
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;
216 tell_vfs(rmc, &m);
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 */);
222 /* Wakeup the newly created process */
223 reply(rmc-mproc, OK);
225 return rmc->mp_pid;
228 /*===========================================================================*
229 * do_exit *
230 *===========================================================================*/
231 int do_exit()
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.
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);
243 else {
244 exit_proc(mp, m_in.m_lc_pm_exit.status, FALSE /*dump_core*/);
246 return(SUSPEND); /* can't communicate from beyond the grave */
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 */
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.
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;
268 /* Do not create core files for set uid execution */
269 if (dump_core && rmp->mp_realuid != rmp->mp_effuid)
270 dump_core = FALSE;
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.
275 if (dump_core && (rmp->mp_flags & PRIV_PROC))
276 dump_core = FALSE;
278 proc_nr = (int) (rmp - mproc); /* get process slot number */
279 proc_nr_e = rmp->mp_endpoint;
281 /* Remember a session leader's process group. */
282 procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
284 /* If the exited process has a timer pending, kill it. */
285 if (rmp->mp_flags & ALARM_ON) set_alarm(rmp, (clock_t) 0);
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);
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 */
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.
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.
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;
311 if((r=vm_willexit(proc_nr_e)) != OK) {
312 panic("exit_proc: vm_willexit failed: %d", r);
314 vm_notify_sig_wrapper(rmp->mp_endpoint);
315 if (proc_nr_e == INIT_PROC_NR)
317 printf("PM: INIT died with exit status %d; showing stacktrace\n", exit_status);
318 sys_diagctl_stacktrace(proc_nr_e);
319 return;
321 if (proc_nr_e == VFS_PROC_NR)
323 panic("exit_proc: VFS died: %d", r);
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;
331 if (dump_core) {
332 m.VFS_PM_TERM_SIG = rmp->mp_sigstatus;
333 m.VFS_PM_PATH = rmp->mp_name;
336 tell_vfs(rmp, &m);
338 if (rmp->mp_flags & PRIV_PROC)
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.
344 if((r= sys_clear(rmp->mp_endpoint)) != OK)
345 panic("exit_proc: sys_clear failed: %d", r);
348 /* Clean up most of the flags describing the process's state before the exit,
349 * and mark it as exiting.
351 rmp->mp_flags &= (IN_USE|VFS_CALL|PRIV_PROC|TRACE_EXIT|PROC_STOPPED);
352 rmp->mp_flags |= EXITING;
354 /* Keep the process around until VFS is finished with it. */
356 rmp->mp_exitstatus = (char) exit_status;
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.
361 if (!dump_core)
362 zombify(rmp);
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);
371 if (rmp->mp_parent == proc_nr) {
372 /* 'rmp' now points to a child to be disinherited. */
373 rmp->mp_parent = INIT_PROC_NR;
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.
379 if (rmp->mp_flags & VFS_CALL)
380 rmp->mp_flags |= NEW_PARENT;
382 /* Notify new parent. */
383 if (rmp->mp_flags & ZOMBIE)
384 check_parent(rmp, TRUE /*try_cleanup*/);
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 */);
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 */
399 /* VFS replied to our exit or coredump request. Perform the second half of the
400 * exit code.
402 int r;
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.
411 printf("PM: The scheduler did not want to give up "
412 "scheduling %s, ret=%d.\n", rmp->mp_name, r);
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;
422 /* For core dumps, now is the right time to try to contact the parent. */
423 if (dump_core)
424 zombify(rmp);
426 if (!(rmp->mp_flags & PRIV_PROC))
428 /* destroy the (user) process */
429 if((r=sys_clear(rmp->mp_endpoint)) != OK)
430 panic("exit_restart: sys_clear failed: %d", r);
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);
438 if (rmp->mp_flags & TRACE_EXIT)
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);
445 /* Clean up if the parent has collected the exit status */
446 if (rmp->mp_flags & TOLD_PARENT)
447 cleanup(rmp);
450 /*===========================================================================*
451 * do_waitpid *
452 *===========================================================================*/
453 int do_waitpid()
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.
463 register struct mproc *rp;
464 int i, pidarg, options, children;
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 */
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
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;
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;
486 children++; /* this child is acceptable */
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);
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.
499 for (i = 1; i < _NSIG; i++) {
500 if (sigismember(&rp->mp_sigtrace, i)) {
501 sigdelset(&rp->mp_sigtrace, i);
503 mp->mp_reply.m_pm_lc_waitpid.status = W_STOPCODE(i);
504 return(rp->mp_pid);
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);
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 */
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 */
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 */
543 /* See if a parent or tracer process is waiting for a child process.
544 * A tracer is considered to be a pseudo-parent.
546 int parent_waiting, right_child;
547 pid_t pidarg;
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);
555 return (parent_waiting && right_child);
558 /*===========================================================================*
559 * zombify *
560 *===========================================================================*/
561 static void zombify(rmp)
562 struct mproc *rmp;
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.
569 struct mproc *t_mp;
571 if (rmp->mp_flags & (TRACE_ZOMBIE | ZOMBIE))
572 panic("zombify: process was already a zombie");
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;
578 t_mp = &mproc[rmp->mp_tracer];
580 /* Do not bother sending SIGCHLD signals to tracers. */
581 if (!wait_test(t_mp, rmp))
582 return;
584 tell_tracer(rmp);
586 else {
587 rmp->mp_flags |= ZOMBIE;
590 /* No tracer, or tracer is parent, or tracer has now been notified. */
591 check_parent(rmp, FALSE /*try_cleanup*/);
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? */
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.
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.
608 struct mproc *p_mp;
610 p_mp = &mproc[child->mp_parent];
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.
617 else if (wait_test(p_mp, child)) {
618 tell_parent(child);
620 /* The 'try_cleanup' flag merely saves us from having to be really
621 * careful with statement ordering in exit_proc() and exit_restart().
623 if (try_cleanup && !(child->mp_flags & VFS_CALL))
624 cleanup(child);
626 else {
627 /* Parent is not waiting. */
628 sig_proc(p_mp, SIGCHLD, TRUE /*trace*/, FALSE /* ksig */);
632 /*===========================================================================*
633 * tell_parent *
634 *===========================================================================*/
635 static void tell_parent(child)
636 register struct mproc *child; /* tells which process is exiting */
638 int mp_parent;
639 struct mproc *parent;
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];
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 */
659 /*===========================================================================*
660 * tell_tracer *
661 *===========================================================================*/
662 static void tell_tracer(child)
663 struct mproc *child; /* tells which process is exiting */
665 int mp_tracer;
666 struct mproc *tracer;
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];
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 */
683 /*===========================================================================*
684 * tracer_died *
685 *===========================================================================*/
686 static void tracer_died(child)
687 struct mproc *child; /* process being traced */
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.
693 child->mp_tracer = NO_TRACER;
694 child->mp_flags &= ~TRACE_EXIT;
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.
700 if (!(child->mp_flags & EXITING)) {
701 sig_proc(child, SIGKILL, TRUE /*trace*/, FALSE /* ksig */);
703 return;
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.
709 if (child->mp_flags & TRACE_ZOMBIE) {
710 child->mp_flags &= ~TRACE_ZOMBIE;
711 child->mp_flags |= ZOMBIE;
713 check_parent(child, TRUE /*try_cleanup*/);
717 /*===========================================================================*
718 * cleanup *
719 *===========================================================================*/
720 static void cleanup(rmp)
721 register struct mproc *rmp; /* tells which process is exiting */
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--;