kern_exit.c revision 46155
1178172Simp/* 2178172Simp * Copyright (c) 1982, 1986, 1989, 1991, 1993 3206713Sjmallett * The Regents of the University of California. All rights reserved. 4206713Sjmallett * (c) UNIX System Laboratories, Inc. 5206713Sjmallett * All or some portions of this file are derived from material licensed 6206713Sjmallett * to the University of California by American Telephone and Telegraph 7206713Sjmallett * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8206713Sjmallett * the permission of UNIX System Laboratories, Inc. 9206713Sjmallett * 10206713Sjmallett * Redistribution and use in source and binary forms, with or without 11206713Sjmallett * modification, are permitted provided that the following conditions 12206713Sjmallett * are met: 13206713Sjmallett * 1. Redistributions of source code must retain the above copyright 14206713Sjmallett * notice, this list of conditions and the following disclaimer. 15206713Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 16206713Sjmallett * notice, this list of conditions and the following disclaimer in the 17206713Sjmallett * documentation and/or other materials provided with the distribution. 18206713Sjmallett * 3. All advertising materials mentioning features or use of this software 19206713Sjmallett * must display the following acknowledgement: 20206713Sjmallett * This product includes software developed by the University of 21206713Sjmallett * California, Berkeley and its contributors. 22206713Sjmallett * 4. Neither the name of the University nor the names of its contributors 23206713Sjmallett * may be used to endorse or promote products derived from this software 24206713Sjmallett * without specific prior written permission. 25206713Sjmallett * 26206713Sjmallett * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29178172Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36178172Simp * SUCH DAMAGE. 37178172Simp * 38178172Simp * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 39178172Simp * $Id: kern_exit.c,v 1.79 1999/04/28 01:04:26 luoqi Exp $ 40178172Simp */ 41178172Simp 42178172Simp#include "opt_compat.h" 43178172Simp#include "opt_ktrace.h" 44178172Simp 45178172Simp#include <sys/param.h> 46178172Simp#include <sys/systm.h> 47178172Simp#include <sys/sysproto.h> 48178172Simp#include <sys/kernel.h> 49178172Simp#include <sys/malloc.h> 50178172Simp#include <sys/proc.h> 51178172Simp#include <sys/pioctl.h> 52178172Simp#include <sys/tty.h> 53178172Simp#include <sys/wait.h> 54178172Simp#include <sys/vnode.h> 55178172Simp#include <sys/resourcevar.h> 56178172Simp#include <sys/signalvar.h> 57178172Simp#include <sys/ptrace.h> 58178172Simp#include <sys/acct.h> /* for acct_process() function prototype */ 59178172Simp#include <sys/filedesc.h> 60178172Simp#include <sys/shm.h> 61178172Simp#include <sys/sem.h> 62178172Simp#include <sys/aio.h> 63178172Simp#include <sys/jail.h> 64178172Simp 65178172Simp#ifdef COMPAT_43 66178172Simp#include <machine/reg.h> 67178172Simp#include <machine/psl.h> 68178172Simp#endif 69178172Simp#include <machine/limits.h> /* for UCHAR_MAX = typeof(p_priority)_MAX */ 70178172Simp 71178172Simp#include <vm/vm.h> 72227658Sjchandra#include <vm/vm_param.h> 73241374Sattilio#include <sys/lock.h> 74218383Sjmallett#include <vm/pmap.h> 75178172Simp#include <vm/vm_map.h> 76178172Simp#include <vm/vm_zone.h> 77178172Simp#include <sys/user.h> 78178172Simp 79178172Simp/* Required to be non-static for SysVR4 emulator */ 80178172SimpMALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status"); 81178172Simp 82178172Simpstatic int wait1 __P((struct proc *, struct wait_args *, int)); 83178172Simp 84178172Simp/* 85178172Simp * callout list for things to do at exit time 86218383Sjmallett */ 87178172Simptypedef struct exit_list_element { 88178172Simp struct exit_list_element *next; 89178172Simp exitlist_fn function; 90206713Sjmallett} *ele_p; 91206713Sjmallett 92206713Sjmallettstatic ele_p exit_list; 93206713Sjmallett 94206713Sjmallett/* 95206713Sjmallett * exit -- 96178172Simp * Death of process. 97178172Simp */ 98218383Sjmallettvoid 99218383Sjmallettexit(p, uap) 100218383Sjmallett struct proc *p; 101218383Sjmallett struct rexit_args /* { 102218383Sjmallett int rval; 103218383Sjmallett } */ *uap; 104178172Simp{ 105178172Simp 106218383Sjmallett exit1(p, W_EXITCODE(uap->rval, 0)); 107178172Simp /* NOTREACHED */ 108178172Simp} 109178172Simp 110216947Sjmallett/* 111216947Sjmallett * Exit: deallocate address space and other resources, change proc state 112216947Sjmallett * to zombie, and unlink proc from allproc and parent's lists. Save exit 113216947Sjmallett * status and rusage for wait(). Check for child processes and orphan them. 114216947Sjmallett */ 115206713Sjmallettvoid 116216972Sjmallettexit1(p, rv) 117178172Simp register struct proc *p; 118178172Simp int rv; 119178172Simp{ 120178172Simp register struct proc *q, *nq; 121178172Simp register struct vmspace *vm; 122178172Simp ele_p ep = exit_list; 123178172Simp 124178172Simp if (p->p_pid == 1) { 125178172Simp printf("init died (signal %d, exit %d)\n", 126178172Simp WTERMSIG(rv), WEXITSTATUS(rv)); 127178172Simp panic("Going nowhere without my init!"); 128178172Simp } 129178172Simp 130178172Simp aio_proc_rundown(p); 131178172Simp 132178172Simp /* are we a task leader? */ 133178172Simp if(p == p->p_leader) { 134178172Simp struct kill_args killArgs; 135178172Simp killArgs.signum = SIGKILL; 136178172Simp q = p->p_peers; 137178172Simp while(q) { 138218383Sjmallett killArgs.pid = q->p_pid; 139218383Sjmallett /* 140218383Sjmallett * The interface for kill is better 141218383Sjmallett * than the internal signal 142218383Sjmallett */ 143218383Sjmallett kill(p, &killArgs); 144218383Sjmallett nq = q; 145218383Sjmallett q = q->p_peers; 146218383Sjmallett /* 147218383Sjmallett * orphan the threads so we don't mess up 148218383Sjmallett * when they call exit 149218383Sjmallett */ 150218383Sjmallett nq->p_peers = 0; 151218383Sjmallett nq->p_leader = nq; 152218383Sjmallett } 153218383Sjmallett 154218383Sjmallett /* otherwise are we a peer? */ 155218383Sjmallett } else if(p->p_peers) { 156218383Sjmallett q = p->p_leader; 157218383Sjmallett while(q->p_peers != p) 158206713Sjmallett q = q->p_peers; 159216972Sjmallett q->p_peers = p->p_peers; 160216972Sjmallett } 161216972Sjmallett 162218383Sjmallett#ifdef PGINPROF 163218383Sjmallett vmsizmon(); 164218383Sjmallett#endif 165218383Sjmallett STOPEVENT(p, S_EXIT, rv); 166218383Sjmallett 167218383Sjmallett /* 168206713Sjmallett * Check if any loadable modules need anything done at process exit. 169218383Sjmallett * e.g. SYSV IPC stuff 170217354Sjchandra * XXX what if one of these generates an error? 171217354Sjchandra */ 172217354Sjchandra while (ep) { 173217354Sjchandra (*ep->function)(p); 174216972Sjmallett ep = ep->next; 175178172Simp } 176216972Sjmallett 177218383Sjmallett if (p->p_flag & P_PROFIL) 178178172Simp stopprofclock(p); 179178172Simp MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), 180216972Sjmallett M_ZOMBIE, M_WAITOK); 181178172Simp /* 182178172Simp * If parent is waiting for us to exit or exec, 183178172Simp * P_PPWAIT is set; we will wakeup the parent below. 184178172Simp */ 185178172Simp p->p_flag &= ~(P_TRACED | P_PPWAIT); 186178172Simp p->p_flag |= P_WEXIT; 187178172Simp p->p_siglist = 0; 188178172Simp if (timevalisset(&p->p_realtimer.it_value)) 189178172Simp untimeout(realitexpire, (caddr_t)p, p->p_ithandle); 190178172Simp 191178172Simp /* 192178172Simp * Reset any sigio structures pointing to us as a result of 193178172Simp * F_SETOWN with our pid. 194178172Simp */ 195178172Simp funsetownlst(&p->p_sigiolst); 196178172Simp 197178172Simp /* 198178172Simp * Close open files and release open-file table. 199178172Simp * This may block! 200178172Simp */ 201178172Simp fdfree(p); 202216972Sjmallett 203202031Simp /* 204206829Sjmallett * XXX Shutdown SYSV semaphores 205202031Simp */ 206202031Simp semexit(p); 207202031Simp 208202031Simp /* The next two chunks should probably be moved to vmspace_exit. */ 209202031Simp vm = p->p_vmspace; 210202031Simp /* 211202031Simp * Release user portion of address space. 212202031Simp * This releases references to vnodes, 213206829Sjmallett * which could cause I/O if the file has been unlinked. 214202031Simp * Need to do this early enough that we can still sleep. 215202031Simp * Can't free the entire vmspace as the kernel stack 216202031Simp * may be mapped within that space also. 217202031Simp */ 218202031Simp if (vm->vm_refcnt == 1) { 219202031Simp if (vm->vm_shm) 220202031Simp shmexit(p); 221202031Simp pmap_remove_pages(vmspace_pmap(vm), VM_MIN_ADDRESS, 222202031Simp VM_MAXUSER_ADDRESS); 223202031Simp (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS, 224210311Sjmallett VM_MAXUSER_ADDRESS); 225178172Simp } 226178172Simp 227202031Simp if (SESS_LEADER(p)) { 228202031Simp register struct session *sp = p->p_session; 229202031Simp 230202031Simp if (sp->s_ttyvp) { 231202031Simp /* 232202031Simp * Controlling process. 233202031Simp * Signal foreground pgrp, 234178172Simp * drain controlling terminal 235178172Simp * and revoke access to controlling terminal. 236178172Simp */ 237216972Sjmallett if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) { 238216972Sjmallett if (sp->s_ttyp->t_pgrp) 239216972Sjmallett pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 240216972Sjmallett (void) ttywait(sp->s_ttyp); 241216972Sjmallett /* 242218383Sjmallett * The tty could have been revoked 243218383Sjmallett * if we blocked. 244218383Sjmallett */ 245224115Sjchandra if (sp->s_ttyvp) 246224115Sjchandra VOP_REVOKE(sp->s_ttyvp, REVOKEALL); 247224115Sjchandra } 248224115Sjchandra if (sp->s_ttyvp) 249216972Sjmallett vrele(sp->s_ttyvp); 250216972Sjmallett sp->s_ttyvp = NULL; 251216972Sjmallett /* 252216972Sjmallett * s_ttyp is not zero'd; we use this to indicate 253216947Sjmallett * that the session once had a controlling terminal. 254216972Sjmallett * (for logging and informational purposes) 255216947Sjmallett */ 256216972Sjmallett } 257178172Simp sp->s_leader = NULL; 258178172Simp } 259206713Sjmallett fixjobc(p, p->p_pgrp, 0); 260216972Sjmallett (void)acct_process(p); 261216972Sjmallett#ifdef KTRACE 262206713Sjmallett /* 263227782Sjchandra * release trace file 264227782Sjchandra */ 265227782Sjchandra p->p_traceflag = 0; /* don't trace the vrele() */ 266217354Sjchandra if (p->p_tracep) 267217354Sjchandra vrele(p->p_tracep); 268217354Sjchandra#endif 269217354Sjchandra /* 270216972Sjmallett * Remove proc from allproc queue and pidhash chain. 271206713Sjmallett * Place onto zombproc. Unlink from parent's child list. 272216972Sjmallett */ 273216972Sjmallett LIST_REMOVE(p, p_list); 274216972Sjmallett LIST_INSERT_HEAD(&zombproc, p, p_list); 275216972Sjmallett p->p_stat = SZOMB; 276216972Sjmallett 277216972Sjmallett LIST_REMOVE(p, p_hash); 278216972Sjmallett 279216972Sjmallett q = p->p_children.lh_first; 280216972Sjmallett if (q) /* only need this if any child is S_ZOMB */ 281204635Sgnn wakeup((caddr_t) initproc); 282216972Sjmallett for (; q != 0; q = nq) { 283216972Sjmallett nq = q->p_sibling.le_next; 284216972Sjmallett LIST_REMOVE(q, p_sibling); 285216972Sjmallett LIST_INSERT_HEAD(&initproc->p_children, q, p_sibling); 286204635Sgnn q->p_pptr = initproc; 287216972Sjmallett q->p_sigparent = SIGCHLD; 288216972Sjmallett /* 289178172Simp * Traced processes are killed 290178172Simp * since their existence means someone is screwing up. 291178172Simp */ 292178172Simp if (q->p_flag & P_TRACED) { 293178172Simp q->p_flag &= ~P_TRACED; 294178172Simp psignal(q, SIGKILL); 295178172Simp } 296178172Simp } 297178172Simp 298206713Sjmallett /* 299178172Simp * Save exit status and final rusage info, adding in child rusage 300178172Simp * info and self times. 301178172Simp */ 302178172Simp p->p_xstat = rv; 303178172Simp *p->p_ru = p->p_stats->p_ru; 304178172Simp calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL); 305178172Simp ruadd(p->p_ru, &p->p_stats->p_cru); 306178172Simp 307178172Simp /* 308178172Simp * Pretend that an mi_switch() to the next process occurs now. We 309178172Simp * must set `switchtime' directly since we will call cpu_switch() 310178172Simp * directly. Set it now so that the rest of the exit time gets 311178172Simp * counted somewhere if possible. 312206713Sjmallett */ 313206713Sjmallett microuptime(&switchtime); 314206713Sjmallett switchticks = ticks; 315206713Sjmallett 316206713Sjmallett /* 317206713Sjmallett * Notify parent that we're gone. If parent has the P_NOCLDWAIT 318206713Sjmallett * flag set, notify process 1 instead (and hope it will handle 319178172Simp * this situation). 320212532Sjchandra */ 321212532Sjchandra if (p->p_pptr->p_procsig->ps_flag & P_NOCLDWAIT) { 322212532Sjchandra struct proc *pp = p->p_pptr; 323212532Sjchandra proc_reparent(p, initproc); 324212532Sjchandra /* 325212532Sjchandra * If this was the last child of our parent, notify 326212632Sneel * parent, so in case he was wait(2)ing, he will 327212532Sjchandra * continue. 328212532Sjchandra */ 329212532Sjchandra if (LIST_EMPTY(&pp->p_children)) 330212532Sjchandra wakeup((caddr_t)pp); 331212532Sjchandra } 332212532Sjchandra 333212532Sjchandra if (p->p_sigparent && p->p_pptr != initproc) { 334212532Sjchandra psignal(p->p_pptr, p->p_sigparent); 335212532Sjchandra } else { 336212532Sjchandra psignal(p->p_pptr, SIGCHLD); 337212532Sjchandra } 338178172Simp 339178172Simp wakeup((caddr_t)p->p_pptr); 340178172Simp#if defined(tahoe) 341178172Simp /* move this to cpu_exit */ 342178172Simp p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; 343178172Simp#endif 344205675Sneel /* 345232872Sjmallett * Clear curproc after we've done all operations 346232872Sjmallett * that could block, and before tearing down the rest 347205675Sneel * of the process state that might be used from clock, etc. 348205675Sneel * Also, can't clear curproc while we're still runnable, 349205675Sneel * as we're not on a run queue (we are current, just not 350205675Sneel * a proper proc any longer!). 351205675Sneel * 352178172Simp * Other substructures are freed from wait(). 353178172Simp */ 354178172Simp SET_CURPROC(NULL); 355178172Simp if (--p->p_limit->p_refcnt == 0) { 356178172Simp FREE(p->p_limit, M_SUBPROC); 357178172Simp p->p_limit = NULL; 358178172Simp } 359178172Simp 360178172Simp /* 361178172Simp * Finally, call machine-dependent code to release the remaining 362178172Simp * resources including address space, the kernel stack and pcb. 363 * The address space is released by "vmspace_free(p->p_vmspace)"; 364 * This is machine-dependent, as we may have to change stacks 365 * or ensure that the current one isn't reallocated before we 366 * finish. cpu_exit will end with a call to cpu_switch(), finishing 367 * our execution (pun intended). 368 */ 369 cpu_exit(p); 370} 371 372#ifdef COMPAT_43 373#if defined(hp300) || defined(luna68k) 374#include <machine/frame.h> 375#define GETPS(rp) ((struct frame *)(rp))->f_sr 376#else 377#define GETPS(rp) (rp)[PS] 378#endif 379 380int 381owait(p, uap) 382 struct proc *p; 383 register struct owait_args /* { 384 int dummy; 385 } */ *uap; 386{ 387 struct wait_args w; 388 389#ifdef PSL_ALLCC 390 if ((GETPS(p->p_md.md_regs) & PSL_ALLCC) != PSL_ALLCC) { 391 w.options = 0; 392 w.rusage = NULL; 393 } else { 394 w.options = p->p_md.md_regs[R0]; 395 w.rusage = (struct rusage *)p->p_md.md_regs[R1]; 396 } 397#else 398 w.options = 0; 399 w.rusage = NULL; 400#endif 401 w.pid = WAIT_ANY; 402 w.status = NULL; 403 return (wait1(p, &w, 1)); 404} 405#endif /* COMPAT_43 */ 406 407int 408wait4(p, uap) 409 struct proc *p; 410 struct wait_args *uap; 411{ 412 413 return (wait1(p, uap, 0)); 414} 415 416static int 417wait1(q, uap, compat) 418 register struct proc *q; 419 register struct wait_args /* { 420 int pid; 421 int *status; 422 int options; 423 struct rusage *rusage; 424 } */ *uap; 425 int compat; 426{ 427 register int nfound; 428 register struct proc *p, *t; 429 int status, error; 430 431 if (uap->pid == 0) 432 uap->pid = -q->p_pgid; 433 if (uap->options &~ (WUNTRACED|WNOHANG|WLINUXCLONE)) 434 return (EINVAL); 435loop: 436 nfound = 0; 437 for (p = q->p_children.lh_first; p != 0; p = p->p_sibling.le_next) { 438 if (uap->pid != WAIT_ANY && 439 p->p_pid != uap->pid && p->p_pgid != -uap->pid) 440 continue; 441 442 /* This special case handles a kthread spawned by linux_clone 443 * (see linux_misc.c). The linux_wait4 and linux_waitpid functions 444 * need to be able to distinguish between waiting on a process and 445 * waiting on a thread. It is a thread if p_sigparent is not SIGCHLD, 446 * and the WLINUXCLONE option signifies we want to wait for threads 447 * and not processes. 448 */ 449 if ((p->p_sigparent != SIGCHLD) ^ ((uap->options & WLINUXCLONE) != 0)) 450 continue; 451 452 nfound++; 453 if (p->p_stat == SZOMB) { 454 /* charge childs scheduling cpu usage to parent */ 455 if (curproc->p_pid != 1) { 456 curproc->p_estcpu = min(curproc->p_estcpu + 457 p->p_estcpu, UCHAR_MAX); 458 } 459 460 q->p_retval[0] = p->p_pid; 461#ifdef COMPAT_43 462 if (compat) 463 q->p_retval[1] = p->p_xstat; 464 else 465#endif 466 if (uap->status) { 467 status = p->p_xstat; /* convert to int */ 468 if ((error = copyout((caddr_t)&status, 469 (caddr_t)uap->status, sizeof(status)))) 470 return (error); 471 } 472 if (uap->rusage && (error = copyout((caddr_t)p->p_ru, 473 (caddr_t)uap->rusage, sizeof (struct rusage)))) 474 return (error); 475 /* 476 * If we got the child via a ptrace 'attach', 477 * we need to give it back to the old parent. 478 */ 479 if (p->p_oppid && (t = pfind(p->p_oppid))) { 480 p->p_oppid = 0; 481 proc_reparent(p, t); 482 psignal(t, SIGCHLD); 483 wakeup((caddr_t)t); 484 return (0); 485 } 486 p->p_xstat = 0; 487 ruadd(&q->p_stats->p_cru, p->p_ru); 488 FREE(p->p_ru, M_ZOMBIE); 489 p->p_ru = NULL; 490 491 /* 492 * Decrement the count of procs running with this uid. 493 */ 494 (void)chgproccnt(p->p_cred->p_ruid, -1); 495 496 /* 497 * Release reference to text vnode 498 */ 499 if (p->p_textvp) 500 vrele(p->p_textvp); 501 502 /* 503 * Free up credentials. 504 */ 505 if (--p->p_cred->p_refcnt == 0) { 506 crfree(p->p_cred->pc_ucred); 507 FREE(p->p_cred, M_SUBPROC); 508 p->p_cred = NULL; 509 } 510 511 /* 512 * Destroy empty prisons 513 */ 514 if (p->p_prison && !--p->p_prison->pr_ref) 515 FREE(p->p_prison, M_PRISON); 516 517 /* 518 * Finally finished with old proc entry. 519 * Unlink it from its process group and free it. 520 */ 521 leavepgrp(p); 522 LIST_REMOVE(p, p_list); /* off zombproc */ 523 LIST_REMOVE(p, p_sibling); 524 525 if (--p->p_procsig->ps_refcnt == 0) { 526 if (p->p_sigacts != &p->p_addr->u_sigacts) 527 FREE(p->p_sigacts, M_SUBPROC); 528 FREE(p->p_procsig, M_SUBPROC); 529 p->p_procsig = NULL; 530 } 531 532 /* 533 * Give machine-dependent layer a chance 534 * to free anything that cpu_exit couldn't 535 * release while still running in process context. 536 */ 537 cpu_wait(p); 538 zfree(proc_zone, p); 539 nprocs--; 540 return (0); 541 } 542 if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 && 543 (p->p_flag & P_TRACED || uap->options & WUNTRACED)) { 544 p->p_flag |= P_WAITED; 545 q->p_retval[0] = p->p_pid; 546#ifdef COMPAT_43 547 if (compat) { 548 q->p_retval[1] = W_STOPCODE(p->p_xstat); 549 error = 0; 550 } else 551#endif 552 if (uap->status) { 553 status = W_STOPCODE(p->p_xstat); 554 error = copyout((caddr_t)&status, 555 (caddr_t)uap->status, sizeof(status)); 556 } else 557 error = 0; 558 return (error); 559 } 560 } 561 if (nfound == 0) 562 return (ECHILD); 563 if (uap->options & WNOHANG) { 564 q->p_retval[0] = 0; 565 return (0); 566 } 567 if ((error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))) 568 return (error); 569 goto loop; 570} 571 572/* 573 * make process 'parent' the new parent of process 'child'. 574 */ 575void 576proc_reparent(child, parent) 577 register struct proc *child; 578 register struct proc *parent; 579{ 580 581 if (child->p_pptr == parent) 582 return; 583 584 LIST_REMOVE(child, p_sibling); 585 LIST_INSERT_HEAD(&parent->p_children, child, p_sibling); 586 child->p_pptr = parent; 587} 588 589/* 590 * The next two functions are to handle adding/deleting items on the 591 * exit callout list 592 * 593 * at_exit(): 594 * Take the arguments given and put them onto the exit callout list, 595 * However first make sure that it's not already there. 596 * returns 0 on success. 597 */ 598int 599at_exit(function) 600 exitlist_fn function; 601{ 602 ele_p ep; 603 604 /* Be noisy if the programmer has lost track of things */ 605 if (rm_at_exit(function)) 606 printf("exit callout entry already present\n"); 607 ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT); 608 if (ep == NULL) 609 return (ENOMEM); 610 ep->next = exit_list; 611 ep->function = function; 612 exit_list = ep; 613 return (0); 614} 615/* 616 * Scan the exit callout list for the given items and remove them. 617 * Returns the number of items removed. 618 * Logically this can only be 0 or 1. 619 */ 620int 621rm_at_exit(function) 622 exitlist_fn function; 623{ 624 ele_p *epp, ep; 625 int count; 626 627 count = 0; 628 epp = &exit_list; 629 ep = *epp; 630 while (ep) { 631 if (ep->function == function) { 632 *epp = ep->next; 633 free(ep, M_TEMP); 634 count++; 635 } else { 636 epp = &ep->next; 637 } 638 ep = *epp; 639 } 640 return (count); 641} 642 643void check_sigacts (void) 644{ 645 struct proc *p = curproc; 646 struct sigacts *pss; 647 int s; 648 649 if (p->p_procsig->ps_refcnt == 1 && 650 p->p_sigacts != &p->p_addr->u_sigacts) { 651 pss = p->p_sigacts; 652 s = splhigh(); 653 p->p_addr->u_sigacts = *pss; 654 p->p_sigacts = &p->p_addr->u_sigacts; 655 splx(s); 656 FREE(pss, M_SUBPROC); 657 } 658} 659 660