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