1996c772fSJohn Dyson /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * (c) UNIX System Laboratories, Inc. 5df8bae1dSRodney W. Grimes * All or some portions of this file are derived from material licensed 6df8bae1dSRodney W. Grimes * to the University of California by American Telephone and Telegraph 7df8bae1dSRodney W. Grimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8df8bae1dSRodney W. Grimes * the permission of UNIX System Laboratories, Inc. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 39c3aac50fSPeter Wemm * $FreeBSD$ 40df8bae1dSRodney W. Grimes */ 41df8bae1dSRodney W. Grimes 425591b823SEivind Eklund #include "opt_compat.h" 43db6a20e2SGarrett Wollman #include "opt_ktrace.h" 44db6a20e2SGarrett Wollman 45df8bae1dSRodney W. Grimes #include <sys/param.h> 46df8bae1dSRodney W. Grimes #include <sys/systm.h> 475fdb8324SBruce Evans #include <sys/sysproto.h> 481c5bb3eaSPeter Wemm #include <sys/kernel.h> 49a1c995b6SPoul-Henning Kamp #include <sys/malloc.h> 50f34fa851SJohn Baldwin #include <sys/lock.h> 5135e0e5b3SJohn Baldwin #include <sys/mutex.h> 52df8bae1dSRodney W. Grimes #include <sys/proc.h> 532a024a2bSSean Eric Fagan #include <sys/pioctl.h> 54df8bae1dSRodney W. Grimes #include <sys/tty.h> 55df8bae1dSRodney W. Grimes #include <sys/wait.h> 56eb30c1c0SPeter Wemm #include <sys/vmmeter.h> 577a6b989bSJohn Baldwin #include <sys/vnode.h> 58df8bae1dSRodney W. Grimes #include <sys/resourcevar.h> 59797f2d22SPoul-Henning Kamp #include <sys/signalvar.h> 601005a129SJohn Baldwin #include <sys/sx.h> 61df8bae1dSRodney W. Grimes #include <sys/ptrace.h> 627c409b8aSJeffrey Hsu #include <sys/acct.h> /* for acct_process() function prototype */ 63797f2d22SPoul-Henning Kamp #include <sys/filedesc.h> 64780dc5a8SPeter Wemm #include <sys/shm.h> 65780dc5a8SPeter Wemm #include <sys/sem.h> 6675c13541SPoul-Henning Kamp #include <sys/jail.h> 67780dc5a8SPeter Wemm 68df8bae1dSRodney W. Grimes #include <vm/vm.h> 69eb30c1c0SPeter Wemm #include <vm/vm_extern.h> 707a6b989bSJohn Baldwin #include <vm/vm_param.h> 71efeaf95aSDavid Greenman #include <vm/pmap.h> 72efeaf95aSDavid Greenman #include <vm/vm_map.h> 73c897b813SJeff Roberson #include <vm/uma.h> 74dc9c271aSJulian Elischer #include <sys/user.h> 75df8bae1dSRodney W. Grimes 76ba198b1cSMark Newton /* Required to be non-static for SysVR4 emulator */ 7769a6f20bSMark Newton MALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status"); 7855166637SPoul-Henning Kamp 7993efcae8SPoul-Henning Kamp static MALLOC_DEFINE(M_ATEXIT, "atexit", "atexit callback"); 8093efcae8SPoul-Henning Kamp 814d77a549SAlfred Perlstein static int wait1(struct thread *, struct wait_args *, int); 825fdb8324SBruce Evans 83df8bae1dSRodney W. Grimes /* 84fed06968SJulian Elischer * callout list for things to do at exit time 85fed06968SJulian Elischer */ 8693efcae8SPoul-Henning Kamp struct exitlist { 87fed06968SJulian Elischer exitlist_fn function; 88e3975643SJake Burkholder TAILQ_ENTRY(exitlist) next; 8993efcae8SPoul-Henning Kamp }; 90fed06968SJulian Elischer 91e3975643SJake Burkholder TAILQ_HEAD(exit_list_head, exitlist); 9293efcae8SPoul-Henning Kamp static struct exit_list_head exit_list = TAILQ_HEAD_INITIALIZER(exit_list); 93fed06968SJulian Elischer 94fed06968SJulian Elischer /* 95df8bae1dSRodney W. Grimes * exit -- 96df8bae1dSRodney W. Grimes * Death of process. 97234216efSMatthew Dillon * 98234216efSMatthew Dillon * MPSAFE 99df8bae1dSRodney W. Grimes */ 100fc0b1dbfSBruce Evans void 101b40ce416SJulian Elischer sys_exit(td, uap) 102b40ce416SJulian Elischer struct thread *td; 103ac2b067bSPeter Wemm struct sys_exit_args /* { 1045fdb8324SBruce Evans int rval; 1055fdb8324SBruce Evans } */ *uap; 106df8bae1dSRodney W. Grimes { 107b40ce416SJulian Elischer 108234216efSMatthew Dillon mtx_lock(&Giant); 109b40ce416SJulian Elischer exit1(td, W_EXITCODE(uap->rval, 0)); 110df8bae1dSRodney W. Grimes /* NOTREACHED */ 111df8bae1dSRodney W. Grimes } 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes /* 114df8bae1dSRodney W. Grimes * Exit: deallocate address space and other resources, change proc state 115df8bae1dSRodney W. Grimes * to zombie, and unlink proc from allproc and parent's lists. Save exit 116df8bae1dSRodney W. Grimes * status and rusage for wait(). Check for child processes and orphan them. 117df8bae1dSRodney W. Grimes */ 118fc0b1dbfSBruce Evans void 119b40ce416SJulian Elischer exit1(td, rv) 120b40ce416SJulian Elischer register struct thread *td; 121df8bae1dSRodney W. Grimes int rv; 122df8bae1dSRodney W. Grimes { 123276c5169SJohn Baldwin struct exitlist *ep; 124276c5169SJohn Baldwin struct proc *p, *nq, *q; 125276c5169SJohn Baldwin struct tty *tp; 126276c5169SJohn Baldwin struct vnode *ttyvp; 127df8bae1dSRodney W. Grimes register struct vmspace *vm; 12879deba82SMatthew Dillon struct vnode *vtmp; 129d7aadbf9SJohn Baldwin #ifdef KTRACE 130d7aadbf9SJohn Baldwin struct vnode *tracevp; 131d7aadbf9SJohn Baldwin #endif 132df8bae1dSRodney W. Grimes 1330cddd8f0SMatthew Dillon GIANT_REQUIRED; 1340cddd8f0SMatthew Dillon 135276c5169SJohn Baldwin p = td->td_proc; 136e746d950SJohn Baldwin if (p == initproc) { 1375f7bd355SPoul-Henning Kamp printf("init died (signal %d, exit %d)\n", 138df8bae1dSRodney W. Grimes WTERMSIG(rv), WEXITSTATUS(rv)); 1395f7bd355SPoul-Henning Kamp panic("Going nowhere without my init!"); 1405f7bd355SPoul-Henning Kamp } 1412c1011f7SJohn Dyson 1427a6b989bSJohn Baldwin /* 1437a6b989bSJohn Baldwin * XXXXKSE: MUST abort all other threads before proceeding past here. 1447a6b989bSJohn Baldwin */ 145b40ce416SJulian Elischer 1467a6b989bSJohn Baldwin /* Are we a task leader? */ 147a914fb6bSJohn Baldwin PROC_LOCK(p); 1482c1011f7SJohn Dyson if (p == p->p_leader) { 1492c1011f7SJohn Dyson q = p->p_peers; 150776e0b36SJohn Baldwin while (q != NULL) { 151776e0b36SJohn Baldwin PROC_LOCK(q); 152776e0b36SJohn Baldwin psignal(q, SIGKILL); 153776e0b36SJohn Baldwin PROC_UNLOCK(q); 1542c1011f7SJohn Dyson q = q->p_peers; 1552c1011f7SJohn Dyson } 15679fc0bf4SMike Smith while (p->p_peers) 157a914fb6bSJohn Baldwin msleep((caddr_t)p, &p->p_mtx, PWAIT, "exit1", 0); 1582c1011f7SJohn Dyson } 159a914fb6bSJohn Baldwin PROC_UNLOCK(p); 1602c1011f7SJohn Dyson 161df8bae1dSRodney W. Grimes #ifdef PGINPROF 162df8bae1dSRodney W. Grimes vmsizmon(); 163df8bae1dSRodney W. Grimes #endif 1642a024a2bSSean Eric Fagan STOPEVENT(p, S_EXIT, rv); 16589361835SSean Eric Fagan wakeup(&p->p_stype); /* Wakeup anyone in procfs' PIOCWAIT */ 1662a024a2bSSean Eric Fagan 167fed06968SJulian Elischer /* 168e9189611SPeter Wemm * Check if any loadable modules need anything done at process exit. 169fed06968SJulian Elischer * e.g. SYSV IPC stuff 170fed06968SJulian Elischer * XXX what if one of these generates an error? 171fed06968SJulian Elischer */ 17293efcae8SPoul-Henning Kamp TAILQ_FOREACH(ep, &exit_list, next) 173fed06968SJulian Elischer (*ep->function)(p); 174fed06968SJulian Elischer 175df8bae1dSRodney W. Grimes stopprofclock(p); 176a914fb6bSJohn Baldwin 177df8bae1dSRodney W. Grimes MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), 178df8bae1dSRodney W. Grimes M_ZOMBIE, M_WAITOK); 179df8bae1dSRodney W. Grimes /* 180df8bae1dSRodney W. Grimes * If parent is waiting for us to exit or exec, 181df8bae1dSRodney W. Grimes * P_PPWAIT is set; we will wakeup the parent below. 182df8bae1dSRodney W. Grimes */ 183a914fb6bSJohn Baldwin PROC_LOCK(p); 184df8bae1dSRodney W. Grimes p->p_flag &= ~(P_TRACED | P_PPWAIT); 185df8bae1dSRodney W. Grimes p->p_flag |= P_WEXIT; 1862c42a146SMarcel Moolenaar SIGEMPTYSET(p->p_siglist); 187a914fb6bSJohn Baldwin PROC_UNLOCK(p); 1884cf41af3SPoul-Henning Kamp if (timevalisset(&p->p_realtimer.it_value)) 1894f559836SJake Burkholder callout_stop(&p->p_itcallout); 190df8bae1dSRodney W. Grimes 191df8bae1dSRodney W. Grimes /* 192831d27a9SDon Lewis * Reset any sigio structures pointing to us as a result of 193831d27a9SDon Lewis * F_SETOWN with our pid. 194831d27a9SDon Lewis */ 195c8d8a686SSeigo Tanimura SIGIO_LOCK(); 196f591779bSSeigo Tanimura PROC_LOCK(p); 197831d27a9SDon Lewis funsetownlst(&p->p_sigiolst); 198f591779bSSeigo Tanimura PROC_UNLOCK(p); 199c8d8a686SSeigo Tanimura SIGIO_UNLOCK(); 200831d27a9SDon Lewis 201831d27a9SDon Lewis /* 202df8bae1dSRodney W. Grimes * Close open files and release open-file table. 203df8bae1dSRodney W. Grimes * This may block! 204df8bae1dSRodney W. Grimes */ 20548810023SJulian Elischer fdfree(td); /* XXXKSE *//* may not be the one in proc */ 206df8bae1dSRodney W. Grimes 207a914fb6bSJohn Baldwin /* 208a914fb6bSJohn Baldwin * Remove ourself from our leader's peer list and wake our leader. 209a914fb6bSJohn Baldwin */ 210776e0b36SJohn Baldwin PROC_LOCK(p->p_leader); 21179fc0bf4SMike Smith if (p->p_leader->p_peers) { 21279fc0bf4SMike Smith q = p->p_leader; 21379fc0bf4SMike Smith while (q->p_peers != p) 21479fc0bf4SMike Smith q = q->p_peers; 21579fc0bf4SMike Smith q->p_peers = p->p_peers; 21679fc0bf4SMike Smith wakeup((caddr_t)p->p_leader); 21779fc0bf4SMike Smith } 218776e0b36SJohn Baldwin PROC_UNLOCK(p->p_leader); 21979fc0bf4SMike Smith 220df8bae1dSRodney W. Grimes /* The next two chunks should probably be moved to vmspace_exit. */ 221df8bae1dSRodney W. Grimes vm = p->p_vmspace; 222df8bae1dSRodney W. Grimes /* 223df8bae1dSRodney W. Grimes * Release user portion of address space. 224df8bae1dSRodney W. Grimes * This releases references to vnodes, 225df8bae1dSRodney W. Grimes * which could cause I/O if the file has been unlinked. 226df8bae1dSRodney W. Grimes * Need to do this early enough that we can still sleep. 227df8bae1dSRodney W. Grimes * Can't free the entire vmspace as the kernel stack 228df8bae1dSRodney W. Grimes * may be mapped within that space also. 229df8bae1dSRodney W. Grimes */ 230582ec34cSAlfred Perlstein if (--vm->vm_refcnt == 0) { 231a2a1c95cSPeter Wemm if (vm->vm_shm) 232a2a1c95cSPeter Wemm shmexit(p); 233b1028ad1SLuoqi Chen pmap_remove_pages(vmspace_pmap(vm), VM_MIN_ADDRESS, 2349d3fbbb5SJohn Dyson VM_MAXUSER_ADDRESS); 23567bf6868SJohn Dyson (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS, 23667bf6868SJohn Dyson VM_MAXUSER_ADDRESS); 237582ec34cSAlfred Perlstein vm->vm_freer = p; 2389d3fbbb5SJohn Dyson } 239df8bae1dSRodney W. Grimes 240ea97757aSJohn Baldwin sx_xlock(&proctree_lock); 241df8bae1dSRodney W. Grimes if (SESS_LEADER(p)) { 242f591779bSSeigo Tanimura register struct session *sp; 243df8bae1dSRodney W. Grimes 244f591779bSSeigo Tanimura sp = p->p_session; 245df8bae1dSRodney W. Grimes if (sp->s_ttyvp) { 246df8bae1dSRodney W. Grimes /* 247df8bae1dSRodney W. Grimes * Controlling process. 248df8bae1dSRodney W. Grimes * Signal foreground pgrp, 249df8bae1dSRodney W. Grimes * drain controlling terminal 250df8bae1dSRodney W. Grimes * and revoke access to controlling terminal. 251df8bae1dSRodney W. Grimes */ 252dd45d8adSJulian Elischer if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) { 253f591779bSSeigo Tanimura tp = sp->s_ttyp; 254f591779bSSeigo Tanimura if (sp->s_ttyp->t_pgrp) { 255f591779bSSeigo Tanimura PGRP_LOCK(sp->s_ttyp->t_pgrp); 256df8bae1dSRodney W. Grimes pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 257f591779bSSeigo Tanimura PGRP_UNLOCK(sp->s_ttyp->t_pgrp); 258f591779bSSeigo Tanimura } 259f591779bSSeigo Tanimura /* XXX tp should be locked. */ 260ea97757aSJohn Baldwin sx_xunlock(&proctree_lock); 261f591779bSSeigo Tanimura (void) ttywait(tp); 262ea97757aSJohn Baldwin sx_xlock(&proctree_lock); 263df8bae1dSRodney W. Grimes /* 264df8bae1dSRodney W. Grimes * The tty could have been revoked 265df8bae1dSRodney W. Grimes * if we blocked. 266df8bae1dSRodney W. Grimes */ 267f591779bSSeigo Tanimura if (sp->s_ttyvp) { 268f591779bSSeigo Tanimura ttyvp = sp->s_ttyvp; 269f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 270df8bae1dSRodney W. Grimes sp->s_ttyvp = NULL; 271f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 272ea97757aSJohn Baldwin sx_xunlock(&proctree_lock); 273f591779bSSeigo Tanimura VOP_REVOKE(ttyvp, REVOKEALL); 274f591779bSSeigo Tanimura vrele(ttyvp); 275ea97757aSJohn Baldwin sx_xlock(&proctree_lock); 276f591779bSSeigo Tanimura } 277f591779bSSeigo Tanimura } 278f591779bSSeigo Tanimura if (sp->s_ttyvp) { 279f591779bSSeigo Tanimura ttyvp = sp->s_ttyvp; 280f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 281f591779bSSeigo Tanimura sp->s_ttyvp = NULL; 282f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 283f591779bSSeigo Tanimura vrele(ttyvp); 284f591779bSSeigo Tanimura } 285df8bae1dSRodney W. Grimes /* 286df8bae1dSRodney W. Grimes * s_ttyp is not zero'd; we use this to indicate 287df8bae1dSRodney W. Grimes * that the session once had a controlling terminal. 288df8bae1dSRodney W. Grimes * (for logging and informational purposes) 289df8bae1dSRodney W. Grimes */ 290df8bae1dSRodney W. Grimes } 291f591779bSSeigo Tanimura SESS_LOCK(p->p_session); 292df8bae1dSRodney W. Grimes sp->s_leader = NULL; 293f591779bSSeigo Tanimura SESS_UNLOCK(p->p_session); 294f591779bSSeigo Tanimura } 295df8bae1dSRodney W. Grimes fixjobc(p, p->p_pgrp, 0); 296ea97757aSJohn Baldwin sx_xunlock(&proctree_lock); 297b40ce416SJulian Elischer (void)acct_process(td); 298df8bae1dSRodney W. Grimes #ifdef KTRACE 299df8bae1dSRodney W. Grimes /* 300df8bae1dSRodney W. Grimes * release trace file 301df8bae1dSRodney W. Grimes */ 302d7aadbf9SJohn Baldwin PROC_LOCK(p); 303df8bae1dSRodney W. Grimes p->p_traceflag = 0; /* don't trace the vrele() */ 304d7aadbf9SJohn Baldwin tracevp = p->p_tracep; 30579deba82SMatthew Dillon p->p_tracep = NULL; 306d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 307d7aadbf9SJohn Baldwin if (tracevp != NULL) 308d7aadbf9SJohn Baldwin vrele(tracevp); 309df8bae1dSRodney W. Grimes #endif 310df8bae1dSRodney W. Grimes /* 311ee42d0a9SDavid Malone * Release reference to text vnode 312ee42d0a9SDavid Malone */ 313ee42d0a9SDavid Malone if ((vtmp = p->p_textvp) != NULL) { 314ee42d0a9SDavid Malone p->p_textvp = NULL; 315ee42d0a9SDavid Malone vrele(vtmp); 316ee42d0a9SDavid Malone } 317ee42d0a9SDavid Malone 318ee42d0a9SDavid Malone /* 319d7aadbf9SJohn Baldwin * Release our limits structure. 320d7aadbf9SJohn Baldwin */ 321d7aadbf9SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 322d7aadbf9SJohn Baldwin if (--p->p_limit->p_refcnt == 0) { 323d7aadbf9SJohn Baldwin FREE(p->p_limit, M_SUBPROC); 324d7aadbf9SJohn Baldwin p->p_limit = NULL; 325d7aadbf9SJohn Baldwin } 326d7aadbf9SJohn Baldwin 327d7aadbf9SJohn Baldwin /* 328d7aadbf9SJohn Baldwin * Release this thread's reference to the ucred. The actual proc 329d7aadbf9SJohn Baldwin * reference will stay around until the proc is harvested by 330d7aadbf9SJohn Baldwin * wait(). At this point the ucred is immutable (no other threads 331d7aadbf9SJohn Baldwin * from this proc are around that can change it) so we leave the 332d7aadbf9SJohn Baldwin * per-thread ucred pointer intact in case it is needed although 333d7aadbf9SJohn Baldwin * in theory nothing should be using it at this point. 334d7aadbf9SJohn Baldwin */ 335d7aadbf9SJohn Baldwin crfree(td->td_ucred); 336d7aadbf9SJohn Baldwin 337d7aadbf9SJohn Baldwin /* 338df8bae1dSRodney W. Grimes * Remove proc from allproc queue and pidhash chain. 339df8bae1dSRodney W. Grimes * Place onto zombproc. Unlink from parent's child list. 340df8bae1dSRodney W. Grimes */ 3411005a129SJohn Baldwin sx_xlock(&allproc_lock); 342b75356e1SJeffrey Hsu LIST_REMOVE(p, p_list); 343b75356e1SJeffrey Hsu LIST_INSERT_HEAD(&zombproc, p, p_list); 344b75356e1SJeffrey Hsu LIST_REMOVE(p, p_hash); 3451005a129SJohn Baldwin sx_xunlock(&allproc_lock); 346df8bae1dSRodney W. Grimes 3471005a129SJohn Baldwin sx_xlock(&proctree_lock); 3482e3c8fcbSPoul-Henning Kamp q = LIST_FIRST(&p->p_children); 349a914fb6bSJohn Baldwin if (q != NULL) /* only need this if any child is S_ZOMB */ 350df8bae1dSRodney W. Grimes wakeup((caddr_t) initproc); 351a914fb6bSJohn Baldwin for (; q != NULL; q = nq) { 3522e3c8fcbSPoul-Henning Kamp nq = LIST_NEXT(q, p_sibling); 353a914fb6bSJohn Baldwin PROC_LOCK(q); 354c65437a3SJohn Baldwin proc_reparent(q, initproc); 3554ac9ae70SJulian Elischer q->p_sigparent = SIGCHLD; 356df8bae1dSRodney W. Grimes /* 357df8bae1dSRodney W. Grimes * Traced processes are killed 358df8bae1dSRodney W. Grimes * since their existence means someone is screwing up. 359df8bae1dSRodney W. Grimes */ 360df8bae1dSRodney W. Grimes if (q->p_flag & P_TRACED) { 361df8bae1dSRodney W. Grimes q->p_flag &= ~P_TRACED; 362df8bae1dSRodney W. Grimes psignal(q, SIGKILL); 363c65437a3SJohn Baldwin } 364a914fb6bSJohn Baldwin PROC_UNLOCK(q); 365df8bae1dSRodney W. Grimes } 366df8bae1dSRodney W. Grimes 367df8bae1dSRodney W. Grimes /* 368df8bae1dSRodney W. Grimes * Save exit status and final rusage info, adding in child rusage 369df8bae1dSRodney W. Grimes * info and self times. 370df8bae1dSRodney W. Grimes */ 371d7aadbf9SJohn Baldwin PROC_LOCK(p); 372df8bae1dSRodney W. Grimes p->p_xstat = rv; 373df8bae1dSRodney W. Grimes *p->p_ru = p->p_stats->p_ru; 3749ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 375df8bae1dSRodney W. Grimes calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL); 3769ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 377df8bae1dSRodney W. Grimes ruadd(p->p_ru, &p->p_stats->p_cru); 378df8bae1dSRodney W. Grimes 379df8bae1dSRodney W. Grimes /* 3807a6b989bSJohn Baldwin * Notify interested parties of our demise. 381cb679c38SJonathan Lemon */ 382a274d19bSBrian Feldman KNOTE(&p->p_klist, NOTE_EXIT); 383cb679c38SJonathan Lemon 384cb679c38SJonathan Lemon /* 385645682fdSLuoqi Chen * Notify parent that we're gone. If parent has the PS_NOCLDWAIT 386ba1551caSIan Dowse * flag set, or if the handler is set to SIG_IGN, notify process 387ba1551caSIan Dowse * 1 instead (and hope it will handle this situation). 388df8bae1dSRodney W. Grimes */ 389d7aadbf9SJohn Baldwin PROC_LOCK(p->p_pptr); 390ba1551caSIan Dowse if (p->p_pptr->p_procsig->ps_flag & (PS_NOCLDWAIT | PS_CLDSIGIGN)) { 391276c5169SJohn Baldwin struct proc *pp; 392276c5169SJohn Baldwin 393276c5169SJohn Baldwin pp = p->p_pptr; 394f591779bSSeigo Tanimura PROC_UNLOCK(pp); 395245f17d4SJoerg Wunsch proc_reparent(p, initproc); 396f591779bSSeigo Tanimura PROC_LOCK(p->p_pptr); 397245f17d4SJoerg Wunsch /* 398245f17d4SJoerg Wunsch * If this was the last child of our parent, notify 399245f17d4SJoerg Wunsch * parent, so in case he was wait(2)ing, he will 400245f17d4SJoerg Wunsch * continue. 401245f17d4SJoerg Wunsch */ 402245f17d4SJoerg Wunsch if (LIST_EMPTY(&pp->p_children)) 403245f17d4SJoerg Wunsch wakeup((caddr_t)pp); 404245f17d4SJoerg Wunsch } 405245f17d4SJoerg Wunsch 406c65437a3SJohn Baldwin if (p->p_sigparent && p->p_pptr != initproc) 4076626c604SJulian Elischer psignal(p->p_pptr, p->p_sigparent); 408c65437a3SJohn Baldwin else 4096626c604SJulian Elischer psignal(p->p_pptr, SIGCHLD); 410c65437a3SJohn Baldwin PROC_UNLOCK(p->p_pptr); 411776e0b36SJohn Baldwin 412776e0b36SJohn Baldwin /* 413776e0b36SJohn Baldwin * If this is a kthread, then wakeup anyone waiting for it to exit. 414776e0b36SJohn Baldwin */ 415776e0b36SJohn Baldwin if (p->p_flag & P_KTHREAD) 416776e0b36SJohn Baldwin wakeup((caddr_t)p); 417c65437a3SJohn Baldwin PROC_UNLOCK(p); 4188e2e767bSJohn Baldwin 4198e2e767bSJohn Baldwin /* 420df8bae1dSRodney W. Grimes * Finally, call machine-dependent code to release the remaining 421df8bae1dSRodney W. Grimes * resources including address space, the kernel stack and pcb. 422582ec34cSAlfred Perlstein * The address space is released by "vmspace_exitfree(p)" in 423582ec34cSAlfred Perlstein * vm_waitproc(). 424df8bae1dSRodney W. Grimes */ 425b40ce416SJulian Elischer cpu_exit(td); 426eb30c1c0SPeter Wemm 427eb30c1c0SPeter Wemm PROC_LOCK(p); 428d7aadbf9SJohn Baldwin PROC_LOCK(p->p_pptr); 429d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 430eb30c1c0SPeter Wemm mtx_lock_spin(&sched_lock); 431eb30c1c0SPeter Wemm while (mtx_owned(&Giant)) 432c86b6ff5SJohn Baldwin mtx_unlock(&Giant); 433eb30c1c0SPeter Wemm 434eb30c1c0SPeter Wemm /* 435eb30c1c0SPeter Wemm * We have to wait until after releasing all locks before 436eb30c1c0SPeter Wemm * changing p_stat. If we block on a mutex then we will be 437eb30c1c0SPeter Wemm * back at SRUN when we resume and our parent will never 438eb30c1c0SPeter Wemm * harvest us. 439eb30c1c0SPeter Wemm */ 440eb30c1c0SPeter Wemm p->p_stat = SZOMB; 441eb30c1c0SPeter Wemm 442eb30c1c0SPeter Wemm wakeup(p->p_pptr); 443d7aadbf9SJohn Baldwin PROC_UNLOCK(p->p_pptr); 444c86b6ff5SJohn Baldwin PROC_UNLOCK(p); 445eb30c1c0SPeter Wemm 446eb30c1c0SPeter Wemm cnt.v_swtch++; 447d7aadbf9SJohn Baldwin binuptime(PCPU_PTR(switchtime)); 448d7aadbf9SJohn Baldwin PCPU_SET(switchticks, ticks); 449d7aadbf9SJohn Baldwin 450eb30c1c0SPeter Wemm cpu_throw(); 451eb30c1c0SPeter Wemm panic("exit1"); 452df8bae1dSRodney W. Grimes } 453df8bae1dSRodney W. Grimes 454b2f9e8b1SBruce Evans #ifdef COMPAT_43 455234216efSMatthew Dillon /* 4567a6b989bSJohn Baldwin * MPSAFE. The dirty work is handled by wait1(). 457234216efSMatthew Dillon */ 45826f9a767SRodney W. Grimes int 459b40ce416SJulian Elischer owait(td, uap) 460b40ce416SJulian Elischer struct thread *td; 4615fdb8324SBruce Evans register struct owait_args /* { 4625fdb8324SBruce Evans int dummy; 4635fdb8324SBruce Evans } */ *uap; 464df8bae1dSRodney W. Grimes { 46593c9414eSSteven Wallace struct wait_args w; 466df8bae1dSRodney W. Grimes 46793c9414eSSteven Wallace w.options = 0; 46893c9414eSSteven Wallace w.rusage = NULL; 46993c9414eSSteven Wallace w.pid = WAIT_ANY; 47093c9414eSSteven Wallace w.status = NULL; 471b40ce416SJulian Elischer return (wait1(td, &w, 1)); 472df8bae1dSRodney W. Grimes } 473b2f9e8b1SBruce Evans #endif /* COMPAT_43 */ 474df8bae1dSRodney W. Grimes 475234216efSMatthew Dillon /* 4767a6b989bSJohn Baldwin * MPSAFE. The dirty work is handled by wait1(). 477234216efSMatthew Dillon */ 47826f9a767SRodney W. Grimes int 479b40ce416SJulian Elischer wait4(td, uap) 480b40ce416SJulian Elischer struct thread *td; 481df8bae1dSRodney W. Grimes struct wait_args *uap; 482df8bae1dSRodney W. Grimes { 483b40ce416SJulian Elischer 484b40ce416SJulian Elischer return (wait1(td, uap, 0)); 485df8bae1dSRodney W. Grimes } 486df8bae1dSRodney W. Grimes 487234216efSMatthew Dillon /* 488234216efSMatthew Dillon * MPSAFE 489234216efSMatthew Dillon */ 49093c9414eSSteven Wallace static int 491b40ce416SJulian Elischer wait1(td, uap, compat) 492b40ce416SJulian Elischer register struct thread *td; 4935fdb8324SBruce Evans register struct wait_args /* { 4945fdb8324SBruce Evans int pid; 4955fdb8324SBruce Evans int *status; 4965fdb8324SBruce Evans int options; 4975fdb8324SBruce Evans struct rusage *rusage; 4985fdb8324SBruce Evans } */ *uap; 49993c9414eSSteven Wallace int compat; 500df8bae1dSRodney W. Grimes { 501276c5169SJohn Baldwin struct rusage ru; 502df8bae1dSRodney W. Grimes register int nfound; 503276c5169SJohn Baldwin register struct proc *p, *q, *t; 504f23c6d68SSteven Wallace int status, error; 505df8bae1dSRodney W. Grimes 506b40ce416SJulian Elischer q = td->td_proc; 507f591779bSSeigo Tanimura if (uap->pid == 0) { 508f591779bSSeigo Tanimura PROC_LOCK(q); 509df8bae1dSRodney W. Grimes uap->pid = -q->p_pgid; 510f591779bSSeigo Tanimura PROC_UNLOCK(q); 511f591779bSSeigo Tanimura } 5126dc958b9SJohn Baldwin if (uap->options &~ (WUNTRACED|WNOHANG|WLINUXCLONE)) 5136dc958b9SJohn Baldwin return (EINVAL); 5146dc958b9SJohn Baldwin mtx_lock(&Giant); 515df8bae1dSRodney W. Grimes loop: 516df8bae1dSRodney W. Grimes nfound = 0; 517d7aadbf9SJohn Baldwin sx_xlock(&proctree_lock); 5182e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &q->p_children, p_sibling) { 519f591779bSSeigo Tanimura PROC_LOCK(p); 520df8bae1dSRodney W. Grimes if (uap->pid != WAIT_ANY && 521f591779bSSeigo Tanimura p->p_pid != uap->pid && p->p_pgid != -uap->pid) { 522f591779bSSeigo Tanimura PROC_UNLOCK(p); 523df8bae1dSRodney W. Grimes continue; 524f591779bSSeigo Tanimura } 5254ac9ae70SJulian Elischer 5261156bc4dSJake Burkholder /* 5271156bc4dSJake Burkholder * This special case handles a kthread spawned by linux_clone 5281156bc4dSJake Burkholder * (see linux_misc.c). The linux_wait4 and linux_waitpid 5291156bc4dSJake Burkholder * functions need to be able to distinguish between waiting 5301156bc4dSJake Burkholder * on a process and waiting on a thread. It is a thread if 5311156bc4dSJake Burkholder * p_sigparent is not SIGCHLD, and the WLINUXCLONE option 5321156bc4dSJake Burkholder * signifies we want to wait for threads and not processes. 5334ac9ae70SJulian Elischer */ 5341156bc4dSJake Burkholder if ((p->p_sigparent != SIGCHLD) ^ 535a914fb6bSJohn Baldwin ((uap->options & WLINUXCLONE) != 0)) { 536a914fb6bSJohn Baldwin PROC_UNLOCK(p); 5374ac9ae70SJulian Elischer continue; 538a914fb6bSJohn Baldwin } 5394ac9ae70SJulian Elischer 540df8bae1dSRodney W. Grimes nfound++; 541df8bae1dSRodney W. Grimes if (p->p_stat == SZOMB) { 542b40ce416SJulian Elischer /* 543b40ce416SJulian Elischer * charge childs scheduling cpu usage to parent 544b40ce416SJulian Elischer * XXXKSE assume only one thread & kse & ksegrp 545b40ce416SJulian Elischer * keep estcpu in each ksegrp 546b40ce416SJulian Elischer * so charge it to the ksegrp that did the wait 547b40ce416SJulian Elischer * since process estcpu is sum of all ksegrps, 548b40ce416SJulian Elischer * this is strictly as expected. 549b40ce416SJulian Elischer * Assume that the child process aggregated all 550b40ce416SJulian Elischer * tke estcpu into the 'build-in' ksegrp. 551b40ce416SJulian Elischer * XXXKSE 552b40ce416SJulian Elischer */ 553b40ce416SJulian Elischer if (curthread->td_proc->p_pid != 1) { 554d7aadbf9SJohn Baldwin mtx_lock_spin(&sched_lock); 555b40ce416SJulian Elischer curthread->td_ksegrp->kg_estcpu = 556b40ce416SJulian Elischer ESTCPULIM(curthread->td_ksegrp->kg_estcpu + 557b40ce416SJulian Elischer p->p_ksegrp.kg_estcpu); 558c65437a3SJohn Baldwin mtx_unlock_spin(&sched_lock); 559d7aadbf9SJohn Baldwin } 560c65437a3SJohn Baldwin 561b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 562b2f9e8b1SBruce Evans #ifdef COMPAT_43 56393c9414eSSteven Wallace if (compat) 564b40ce416SJulian Elischer td->td_retval[1] = p->p_xstat; 565df8bae1dSRodney W. Grimes else 566df8bae1dSRodney W. Grimes #endif 567df8bae1dSRodney W. Grimes if (uap->status) { 568df8bae1dSRodney W. Grimes status = p->p_xstat; /* convert to int */ 569d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 570bb56ec4aSPoul-Henning Kamp if ((error = copyout((caddr_t)&status, 571234216efSMatthew Dillon (caddr_t)uap->status, sizeof(status)))) { 572d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 573d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 574d7aadbf9SJohn Baldwin return (error); 575234216efSMatthew Dillon } 576d7aadbf9SJohn Baldwin PROC_LOCK(p); 577df8bae1dSRodney W. Grimes } 578d7aadbf9SJohn Baldwin if (uap->rusage) { 579d7aadbf9SJohn Baldwin bcopy(p->p_ru, &ru, sizeof(ru)); 580d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 581d7aadbf9SJohn Baldwin if ((error = copyout((caddr_t)&ru, 582d7aadbf9SJohn Baldwin (caddr_t)uap->rusage, 583d7aadbf9SJohn Baldwin sizeof (struct rusage)))) { 584d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 585d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 586d7aadbf9SJohn Baldwin return (error); 587234216efSMatthew Dillon } 588d7aadbf9SJohn Baldwin } else 589d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 590df8bae1dSRodney W. Grimes /* 591df8bae1dSRodney W. Grimes * If we got the child via a ptrace 'attach', 592df8bae1dSRodney W. Grimes * we need to give it back to the old parent. 593df8bae1dSRodney W. Grimes */ 594d7aadbf9SJohn Baldwin if (p->p_oppid && (t = pfind(p->p_oppid)) != NULL) { 595c65437a3SJohn Baldwin PROC_LOCK(p); 596df8bae1dSRodney W. Grimes p->p_oppid = 0; 597df8bae1dSRodney W. Grimes proc_reparent(p, t); 598c65437a3SJohn Baldwin PROC_UNLOCK(p); 599df8bae1dSRodney W. Grimes psignal(t, SIGCHLD); 60033a9ed9dSJohn Baldwin wakeup((caddr_t)t); 601c65437a3SJohn Baldwin PROC_UNLOCK(t); 6021005a129SJohn Baldwin sx_xunlock(&proctree_lock); 603d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 604d7aadbf9SJohn Baldwin return (0); 605df8bae1dSRodney W. Grimes } 606df8bae1dSRodney W. Grimes /* 607d7aadbf9SJohn Baldwin * Remove other references to this process to ensure 608d7aadbf9SJohn Baldwin * we have an exclusive reference. 609df8bae1dSRodney W. Grimes */ 610ebdc3f1dSSeigo Tanimura leavepgrp(p); 611ebdc3f1dSSeigo Tanimura 612ebdc3f1dSSeigo Tanimura sx_xlock(&allproc_lock); 613ebdc3f1dSSeigo Tanimura LIST_REMOVE(p, p_list); /* off zombproc */ 614ebdc3f1dSSeigo Tanimura sx_xunlock(&allproc_lock); 615ebdc3f1dSSeigo Tanimura 616ebdc3f1dSSeigo Tanimura LIST_REMOVE(p, p_sibling); 617ebdc3f1dSSeigo Tanimura sx_xunlock(&proctree_lock); 618ebdc3f1dSSeigo Tanimura 619ebdc3f1dSSeigo Tanimura /* 620d7aadbf9SJohn Baldwin * As a side effect of this lock, we know that 621d7aadbf9SJohn Baldwin * all other writes to this proc are visible now, so 622d7aadbf9SJohn Baldwin * no more locking is needed for p. 623d7aadbf9SJohn Baldwin */ 624d7aadbf9SJohn Baldwin PROC_LOCK(p); 625d7aadbf9SJohn Baldwin p->p_xstat = 0; /* XXX: why? */ 626d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 627d7aadbf9SJohn Baldwin PROC_LOCK(q); 628d7aadbf9SJohn Baldwin ruadd(&q->p_stats->p_cru, p->p_ru); 629d7aadbf9SJohn Baldwin PROC_UNLOCK(q); 630d7aadbf9SJohn Baldwin FREE(p->p_ru, M_ZOMBIE); 631d7aadbf9SJohn Baldwin p->p_ru = NULL; 632d7aadbf9SJohn Baldwin 633d7aadbf9SJohn Baldwin /* 634d7aadbf9SJohn Baldwin * Decrement the count of procs running with this uid. 635d7aadbf9SJohn Baldwin */ 636d7aadbf9SJohn Baldwin (void)chgproccnt(p->p_ucred->cr_ruidinfo, -1, 0); 637d7aadbf9SJohn Baldwin 638d7aadbf9SJohn Baldwin /* 639df8bae1dSRodney W. Grimes * Free up credentials. 640df8bae1dSRodney W. Grimes */ 641da654d90SPoul-Henning Kamp crfree(p->p_ucred); 642d7aadbf9SJohn Baldwin p->p_ucred = NULL; /* XXX: why? */ 643df8bae1dSRodney W. Grimes 644df8bae1dSRodney W. Grimes /* 645b9df5231SPoul-Henning Kamp * Remove unused arguments 646b9df5231SPoul-Henning Kamp */ 647d7aadbf9SJohn Baldwin pargs_drop(p->p_args); 648d7aadbf9SJohn Baldwin p->p_args = NULL; 649b9df5231SPoul-Henning Kamp 6506626c604SJulian Elischer if (--p->p_procsig->ps_refcnt == 0) { 651b40ce416SJulian Elischer if (p->p_sigacts != &p->p_uarea->u_sigacts) 652dc9c271aSJulian Elischer FREE(p->p_sigacts, M_SUBPROC); 653dc9c271aSJulian Elischer FREE(p->p_procsig, M_SUBPROC); 6546626c604SJulian Elischer p->p_procsig = NULL; 6556626c604SJulian Elischer } 65688c5ea45SJulian Elischer 657df8bae1dSRodney W. Grimes /* 658eb30c1c0SPeter Wemm * Give vm and machine-dependent layer a chance 659df8bae1dSRodney W. Grimes * to free anything that cpu_exit couldn't 660df8bae1dSRodney W. Grimes * release while still running in process context. 661df8bae1dSRodney W. Grimes */ 662eb30c1c0SPeter Wemm vm_waitproc(p); 6634971f62aSJohn Baldwin mtx_destroy(&p->p_mtx); 664c897b813SJeff Roberson uma_zfree(proc_zone, p); 665d7aadbf9SJohn Baldwin sx_xlock(&allproc_lock); 666df8bae1dSRodney W. Grimes nprocs--; 667d7aadbf9SJohn Baldwin sx_xunlock(&allproc_lock); 668d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 669d7aadbf9SJohn Baldwin return (0); 670df8bae1dSRodney W. Grimes } 671df8bae1dSRodney W. Grimes if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 && 672df8bae1dSRodney W. Grimes (p->p_flag & P_TRACED || uap->options & WUNTRACED)) { 673df8bae1dSRodney W. Grimes p->p_flag |= P_WAITED; 674d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 675b40ce416SJulian Elischer td->td_retval[0] = p->p_pid; 676b2f9e8b1SBruce Evans #ifdef COMPAT_43 67793c9414eSSteven Wallace if (compat) { 678b40ce416SJulian Elischer td->td_retval[1] = W_STOPCODE(p->p_xstat); 679d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 680df8bae1dSRodney W. Grimes error = 0; 681df8bae1dSRodney W. Grimes } else 682df8bae1dSRodney W. Grimes #endif 683df8bae1dSRodney W. Grimes if (uap->status) { 684df8bae1dSRodney W. Grimes status = W_STOPCODE(p->p_xstat); 685d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 686df8bae1dSRodney W. Grimes error = copyout((caddr_t)&status, 687df8bae1dSRodney W. Grimes (caddr_t)uap->status, sizeof(status)); 688d7aadbf9SJohn Baldwin } else { 689a914fb6bSJohn Baldwin PROC_UNLOCK(p); 690234216efSMatthew Dillon error = 0; 691df8bae1dSRodney W. Grimes } 692234216efSMatthew Dillon mtx_unlock(&Giant); 693234216efSMatthew Dillon return (error); 694df8bae1dSRodney W. Grimes } 695d7aadbf9SJohn Baldwin PROC_UNLOCK(p); 696d7aadbf9SJohn Baldwin } 697d7aadbf9SJohn Baldwin if (nfound == 0) { 698d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 699d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 700d7aadbf9SJohn Baldwin return (ECHILD); 701d7aadbf9SJohn Baldwin } 702d7aadbf9SJohn Baldwin if (uap->options & WNOHANG) { 703d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 704d7aadbf9SJohn Baldwin td->td_retval[0] = 0; 705d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 706d7aadbf9SJohn Baldwin return (0); 707d7aadbf9SJohn Baldwin } 708d7aadbf9SJohn Baldwin PROC_LOCK(q); 709d7aadbf9SJohn Baldwin sx_xunlock(&proctree_lock); 710d7aadbf9SJohn Baldwin error = msleep((caddr_t)q, &q->p_mtx, PWAIT | PCATCH, "wait", 0); 711d7aadbf9SJohn Baldwin PROC_UNLOCK(q); 712d7aadbf9SJohn Baldwin if (error) { 713d7aadbf9SJohn Baldwin mtx_unlock(&Giant); 714d7aadbf9SJohn Baldwin return (error); 715d7aadbf9SJohn Baldwin } 716d7aadbf9SJohn Baldwin goto loop; 717d7aadbf9SJohn Baldwin } 718df8bae1dSRodney W. Grimes 719df8bae1dSRodney W. Grimes /* 72098f03f90SJake Burkholder * Make process 'parent' the new parent of process 'child'. 72198f03f90SJake Burkholder * Must be called with an exclusive hold of proctree lock. 722df8bae1dSRodney W. Grimes */ 723df8bae1dSRodney W. Grimes void 724df8bae1dSRodney W. Grimes proc_reparent(child, parent) 725df8bae1dSRodney W. Grimes register struct proc *child; 726df8bae1dSRodney W. Grimes register struct proc *parent; 727df8bae1dSRodney W. Grimes { 728df8bae1dSRodney W. Grimes 7294e5e677bSJohn Baldwin sx_assert(&proctree_lock, SX_XLOCKED); 730c65437a3SJohn Baldwin PROC_LOCK_ASSERT(child, MA_OWNED); 731df8bae1dSRodney W. Grimes if (child->p_pptr == parent) 732df8bae1dSRodney W. Grimes return; 733df8bae1dSRodney W. Grimes 734b75356e1SJeffrey Hsu LIST_REMOVE(child, p_sibling); 735b75356e1SJeffrey Hsu LIST_INSERT_HEAD(&parent->p_children, child, p_sibling); 736df8bae1dSRodney W. Grimes child->p_pptr = parent; 737df8bae1dSRodney W. Grimes } 738fed06968SJulian Elischer 739e0d898b4SJulian Elischer /* 740e0d898b4SJulian Elischer * The next two functions are to handle adding/deleting items on the 741fed06968SJulian Elischer * exit callout list 742e0d898b4SJulian Elischer * 743e0d898b4SJulian Elischer * at_exit(): 744e0d898b4SJulian Elischer * Take the arguments given and put them onto the exit callout list, 745fed06968SJulian Elischer * However first make sure that it's not already there. 746fed06968SJulian Elischer * returns 0 on success. 747fed06968SJulian Elischer */ 74893efcae8SPoul-Henning Kamp 749fed06968SJulian Elischer int 750eb776aeaSBruce Evans at_exit(function) 751eb776aeaSBruce Evans exitlist_fn function; 752fed06968SJulian Elischer { 75393efcae8SPoul-Henning Kamp struct exitlist *ep; 754e0d898b4SJulian Elischer 75593efcae8SPoul-Henning Kamp #ifdef INVARIANTS 756e0d898b4SJulian Elischer /* Be noisy if the programmer has lost track of things */ 757e0d898b4SJulian Elischer if (rm_at_exit(function)) 75893efcae8SPoul-Henning Kamp printf("WARNING: exit callout entry (%p) already present\n", 75993efcae8SPoul-Henning Kamp function); 76093efcae8SPoul-Henning Kamp #endif 76193efcae8SPoul-Henning Kamp ep = malloc(sizeof(*ep), M_ATEXIT, M_NOWAIT); 762e0d898b4SJulian Elischer if (ep == NULL) 763e0d898b4SJulian Elischer return (ENOMEM); 764fed06968SJulian Elischer ep->function = function; 76593efcae8SPoul-Henning Kamp TAILQ_INSERT_TAIL(&exit_list, ep, next); 766e0d898b4SJulian Elischer return (0); 767fed06968SJulian Elischer } 76893efcae8SPoul-Henning Kamp 769fed06968SJulian Elischer /* 77093efcae8SPoul-Henning Kamp * Scan the exit callout list for the given item and remove it. 77193efcae8SPoul-Henning Kamp * Returns the number of items removed (0 or 1) 772fed06968SJulian Elischer */ 773fed06968SJulian Elischer int 774eb776aeaSBruce Evans rm_at_exit(function) 775eb776aeaSBruce Evans exitlist_fn function; 776fed06968SJulian Elischer { 77793efcae8SPoul-Henning Kamp struct exitlist *ep; 778fed06968SJulian Elischer 77993efcae8SPoul-Henning Kamp TAILQ_FOREACH(ep, &exit_list, next) { 780fed06968SJulian Elischer if (ep->function == function) { 78193efcae8SPoul-Henning Kamp TAILQ_REMOVE(&exit_list, ep, next); 78293efcae8SPoul-Henning Kamp free(ep, M_ATEXIT); 78393efcae8SPoul-Henning Kamp return (1); 784fed06968SJulian Elischer } 785fed06968SJulian Elischer } 78693efcae8SPoul-Henning Kamp return (0); 787fed06968SJulian Elischer } 788