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