xref: /freebsd/sys/kern/kern_exit.c (revision 81090119afac17145653412c2217781830bd989b)
1f3f0ca60SSøren Schmidt /*-
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
3981090119SPeter Wemm  * $Id: kern_exit.c,v 1.25 1996/01/04 20:28:46 wollman Exp $
40df8bae1dSRodney W. Grimes  */
41df8bae1dSRodney W. Grimes 
42db6a20e2SGarrett Wollman #include "opt_ktrace.h"
4350c73f36SGarrett Wollman #include "opt_sysvipc.h"
44db6a20e2SGarrett Wollman 
45df8bae1dSRodney W. Grimes #include <sys/param.h>
46df8bae1dSRodney W. Grimes #include <sys/systm.h>
475fdb8324SBruce Evans #include <sys/sysproto.h>
48f3f0ca60SSøren Schmidt #include <sys/sysent.h>
49df8bae1dSRodney W. Grimes #include <sys/ioctl.h>
50df8bae1dSRodney W. Grimes #include <sys/proc.h>
51df8bae1dSRodney W. Grimes #include <sys/tty.h>
52df8bae1dSRodney W. Grimes #include <sys/time.h>
53df8bae1dSRodney W. Grimes #include <sys/resource.h>
54df8bae1dSRodney W. Grimes #include <sys/kernel.h>
55df8bae1dSRodney W. Grimes #include <sys/buf.h>
56df8bae1dSRodney W. Grimes #include <sys/wait.h>
57df8bae1dSRodney W. Grimes #include <sys/file.h>
58df8bae1dSRodney W. Grimes #include <sys/vnode.h>
59df8bae1dSRodney W. Grimes #include <sys/syslog.h>
60df8bae1dSRodney W. Grimes #include <sys/malloc.h>
61df8bae1dSRodney W. Grimes #include <sys/resourcevar.h>
62797f2d22SPoul-Henning Kamp #include <sys/signalvar.h>
63df8bae1dSRodney W. Grimes #include <sys/ptrace.h>
64797f2d22SPoul-Henning Kamp #include <sys/filedesc.h>
65780dc5a8SPeter Wemm #include <sys/shm.h>
66780dc5a8SPeter Wemm #include <sys/sem.h>
67780dc5a8SPeter Wemm 
68df8bae1dSRodney W. Grimes #include <machine/cpu.h>
69df8bae1dSRodney W. Grimes #ifdef COMPAT_43
70df8bae1dSRodney W. Grimes #include <machine/reg.h>
71df8bae1dSRodney W. Grimes #include <machine/psl.h>
72df8bae1dSRodney W. Grimes #endif
73df8bae1dSRodney W. Grimes 
74df8bae1dSRodney W. Grimes #include <vm/vm.h>
75efeaf95aSDavid Greenman #include <vm/vm_param.h>
76efeaf95aSDavid Greenman #include <vm/vm_prot.h>
77efeaf95aSDavid Greenman #include <vm/lock.h>
78efeaf95aSDavid Greenman #include <vm/pmap.h>
79efeaf95aSDavid Greenman #include <vm/vm_map.h>
80df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
81df8bae1dSRodney W. Grimes 
825fdb8324SBruce Evans static int wait1 __P((struct proc *, struct wait_args *, int [], int));
835fdb8324SBruce Evans 
84df8bae1dSRodney W. Grimes /*
85df8bae1dSRodney W. Grimes  * exit --
86df8bae1dSRodney W. Grimes  *	Death of process.
87df8bae1dSRodney W. Grimes  */
88df8bae1dSRodney W. Grimes __dead void
89df8bae1dSRodney W. Grimes exit(p, uap, retval)
90df8bae1dSRodney W. Grimes 	struct proc *p;
915fdb8324SBruce Evans 	struct rexit_args /* {
925fdb8324SBruce Evans 		int	rval;
935fdb8324SBruce Evans 	} */ *uap;
94df8bae1dSRodney W. Grimes 	int *retval;
95df8bae1dSRodney W. Grimes {
96df8bae1dSRodney W. Grimes 
97df8bae1dSRodney W. Grimes 	exit1(p, W_EXITCODE(uap->rval, 0));
98df8bae1dSRodney W. Grimes 	/* NOTREACHED */
99df8bae1dSRodney W. Grimes }
100df8bae1dSRodney W. Grimes 
101df8bae1dSRodney W. Grimes /*
102df8bae1dSRodney W. Grimes  * Exit: deallocate address space and other resources, change proc state
103df8bae1dSRodney W. Grimes  * to zombie, and unlink proc from allproc and parent's lists.  Save exit
104df8bae1dSRodney W. Grimes  * status and rusage for wait().  Check for child processes and orphan them.
105df8bae1dSRodney W. Grimes  */
106df8bae1dSRodney W. Grimes __dead void
107df8bae1dSRodney W. Grimes exit1(p, rv)
108df8bae1dSRodney W. Grimes 	register struct proc *p;
109df8bae1dSRodney W. Grimes 	int rv;
110df8bae1dSRodney W. Grimes {
111df8bae1dSRodney W. Grimes 	register struct proc *q, *nq;
112df8bae1dSRodney W. Grimes 	register struct proc **pp;
113df8bae1dSRodney W. Grimes 	register struct vmspace *vm;
114df8bae1dSRodney W. Grimes 
1155f7bd355SPoul-Henning Kamp 	if (p->p_pid == 1) {
1165f7bd355SPoul-Henning Kamp 		printf("init died (signal %d, exit %d)\n",
117df8bae1dSRodney W. Grimes 		    WTERMSIG(rv), WEXITSTATUS(rv));
1185f7bd355SPoul-Henning Kamp 		panic("Going nowhere without my init!");
1195f7bd355SPoul-Henning Kamp 	}
120df8bae1dSRodney W. Grimes #ifdef PGINPROF
121df8bae1dSRodney W. Grimes 	vmsizmon();
122df8bae1dSRodney W. Grimes #endif
123df8bae1dSRodney W. Grimes 	if (p->p_flag & P_PROFIL)
124df8bae1dSRodney W. Grimes 		stopprofclock(p);
125df8bae1dSRodney W. Grimes 	MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
126df8bae1dSRodney W. Grimes 		M_ZOMBIE, M_WAITOK);
127df8bae1dSRodney W. Grimes 	/*
128df8bae1dSRodney W. Grimes 	 * If parent is waiting for us to exit or exec,
129df8bae1dSRodney W. Grimes 	 * P_PPWAIT is set; we will wakeup the parent below.
130df8bae1dSRodney W. Grimes 	 */
131df8bae1dSRodney W. Grimes 	p->p_flag &= ~(P_TRACED | P_PPWAIT);
132df8bae1dSRodney W. Grimes 	p->p_flag |= P_WEXIT;
133df8bae1dSRodney W. Grimes 	p->p_sigignore = ~0;
134df8bae1dSRodney W. Grimes 	p->p_siglist = 0;
135df8bae1dSRodney W. Grimes 	untimeout(realitexpire, (caddr_t)p);
136df8bae1dSRodney W. Grimes 
137df8bae1dSRodney W. Grimes 	/*
138df8bae1dSRodney W. Grimes 	 * Close open files and release open-file table.
139df8bae1dSRodney W. Grimes 	 * This may block!
140df8bae1dSRodney W. Grimes 	 */
141df8bae1dSRodney W. Grimes 	fdfree(p);
142df8bae1dSRodney W. Grimes 
14381090119SPeter Wemm 	/*
14481090119SPeter Wemm 	 * XXX Shutdown SYSV semaphores
14581090119SPeter Wemm 	 */
146a353d785SJoerg Wunsch 	semexit(p);
147a353d785SJoerg Wunsch 
148df8bae1dSRodney W. Grimes 	/* The next two chunks should probably be moved to vmspace_exit. */
149df8bae1dSRodney W. Grimes 	vm = p->p_vmspace;
150df8bae1dSRodney W. Grimes 	if (vm->vm_shm)
151df8bae1dSRodney W. Grimes 		shmexit(p);
152df8bae1dSRodney W. Grimes 	/*
153df8bae1dSRodney W. Grimes 	 * Release user portion of address space.
154df8bae1dSRodney W. Grimes 	 * This releases references to vnodes,
155df8bae1dSRodney W. Grimes 	 * which could cause I/O if the file has been unlinked.
156df8bae1dSRodney W. Grimes 	 * Need to do this early enough that we can still sleep.
157df8bae1dSRodney W. Grimes 	 * Can't free the entire vmspace as the kernel stack
158df8bae1dSRodney W. Grimes 	 * may be mapped within that space also.
159df8bae1dSRodney W. Grimes 	 */
160df8bae1dSRodney W. Grimes 	if (vm->vm_refcnt == 1)
161df8bae1dSRodney W. Grimes 		(void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
162df8bae1dSRodney W. Grimes 		    VM_MAXUSER_ADDRESS);
163df8bae1dSRodney W. Grimes 
164df8bae1dSRodney W. Grimes 	if (SESS_LEADER(p)) {
165df8bae1dSRodney W. Grimes 		register struct session *sp = p->p_session;
166df8bae1dSRodney W. Grimes 
167df8bae1dSRodney W. Grimes 		if (sp->s_ttyvp) {
168df8bae1dSRodney W. Grimes 			/*
169df8bae1dSRodney W. Grimes 			 * Controlling process.
170df8bae1dSRodney W. Grimes 			 * Signal foreground pgrp,
171df8bae1dSRodney W. Grimes 			 * drain controlling terminal
172df8bae1dSRodney W. Grimes 			 * and revoke access to controlling terminal.
173df8bae1dSRodney W. Grimes 			 */
174df8bae1dSRodney W. Grimes 			if (sp->s_ttyp->t_session == sp) {
175df8bae1dSRodney W. Grimes 				if (sp->s_ttyp->t_pgrp)
176df8bae1dSRodney W. Grimes 					pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
177df8bae1dSRodney W. Grimes 				(void) ttywait(sp->s_ttyp);
178df8bae1dSRodney W. Grimes 				/*
179df8bae1dSRodney W. Grimes 				 * The tty could have been revoked
180df8bae1dSRodney W. Grimes 				 * if we blocked.
181df8bae1dSRodney W. Grimes 				 */
182df8bae1dSRodney W. Grimes 				if (sp->s_ttyvp)
183df8bae1dSRodney W. Grimes 					vgoneall(sp->s_ttyvp);
184df8bae1dSRodney W. Grimes 			}
185df8bae1dSRodney W. Grimes 			if (sp->s_ttyvp)
186df8bae1dSRodney W. Grimes 				vrele(sp->s_ttyvp);
187df8bae1dSRodney W. Grimes 			sp->s_ttyvp = NULL;
188df8bae1dSRodney W. Grimes 			/*
189df8bae1dSRodney W. Grimes 			 * s_ttyp is not zero'd; we use this to indicate
190df8bae1dSRodney W. Grimes 			 * that the session once had a controlling terminal.
191df8bae1dSRodney W. Grimes 			 * (for logging and informational purposes)
192df8bae1dSRodney W. Grimes 			 */
193df8bae1dSRodney W. Grimes 		}
194df8bae1dSRodney W. Grimes 		sp->s_leader = NULL;
195df8bae1dSRodney W. Grimes 	}
196df8bae1dSRodney W. Grimes 	fixjobc(p, p->p_pgrp, 0);
197df8bae1dSRodney W. Grimes 	p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
198df8bae1dSRodney W. Grimes 	(void)acct_process(p);
199df8bae1dSRodney W. Grimes #ifdef KTRACE
200df8bae1dSRodney W. Grimes 	/*
201df8bae1dSRodney W. Grimes 	 * release trace file
202df8bae1dSRodney W. Grimes 	 */
203df8bae1dSRodney W. Grimes 	p->p_traceflag = 0;	/* don't trace the vrele() */
204df8bae1dSRodney W. Grimes 	if (p->p_tracep)
205df8bae1dSRodney W. Grimes 		vrele(p->p_tracep);
206df8bae1dSRodney W. Grimes #endif
207df8bae1dSRodney W. Grimes 	/*
208df8bae1dSRodney W. Grimes 	 * Remove proc from allproc queue and pidhash chain.
209df8bae1dSRodney W. Grimes 	 * Place onto zombproc.  Unlink from parent's child list.
210df8bae1dSRodney W. Grimes 	 */
211bb56ec4aSPoul-Henning Kamp 	if ((*p->p_prev = p->p_next))
212df8bae1dSRodney W. Grimes 		p->p_next->p_prev = p->p_prev;
213bb56ec4aSPoul-Henning Kamp 	if ((p->p_next = zombproc))
214df8bae1dSRodney W. Grimes 		p->p_next->p_prev = &p->p_next;
215df8bae1dSRodney W. Grimes 	p->p_prev = &zombproc;
216df8bae1dSRodney W. Grimes 	zombproc = p;
217df8bae1dSRodney W. Grimes 	p->p_stat = SZOMB;
218df8bae1dSRodney W. Grimes 
219df8bae1dSRodney W. Grimes 	for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
220df8bae1dSRodney W. Grimes 		if (*pp == p) {
221df8bae1dSRodney W. Grimes 			*pp = p->p_hash;
222df8bae1dSRodney W. Grimes 			goto done;
223df8bae1dSRodney W. Grimes 		}
224df8bae1dSRodney W. Grimes 	panic("exit");
225df8bae1dSRodney W. Grimes done:
226df8bae1dSRodney W. Grimes 
227df8bae1dSRodney W. Grimes 	if (p->p_cptr)		/* only need this if any child is S_ZOMB */
228df8bae1dSRodney W. Grimes 		wakeup((caddr_t) initproc);
229df8bae1dSRodney W. Grimes 	for (q = p->p_cptr; q != NULL; q = nq) {
230df8bae1dSRodney W. Grimes 		nq = q->p_osptr;
231df8bae1dSRodney W. Grimes 		if (nq != NULL)
232df8bae1dSRodney W. Grimes 			nq->p_ysptr = NULL;
233df8bae1dSRodney W. Grimes 		if (initproc->p_cptr)
234df8bae1dSRodney W. Grimes 			initproc->p_cptr->p_ysptr = q;
235df8bae1dSRodney W. Grimes 		q->p_osptr = initproc->p_cptr;
236df8bae1dSRodney W. Grimes 		q->p_ysptr = NULL;
237df8bae1dSRodney W. Grimes 		initproc->p_cptr = q;
238df8bae1dSRodney W. Grimes 
239df8bae1dSRodney W. Grimes 		q->p_pptr = initproc;
240df8bae1dSRodney W. Grimes 		/*
241df8bae1dSRodney W. Grimes 		 * Traced processes are killed
242df8bae1dSRodney W. Grimes 		 * since their existence means someone is screwing up.
243df8bae1dSRodney W. Grimes 		 */
244df8bae1dSRodney W. Grimes 		if (q->p_flag & P_TRACED) {
245df8bae1dSRodney W. Grimes 			q->p_flag &= ~P_TRACED;
246df8bae1dSRodney W. Grimes 			psignal(q, SIGKILL);
247df8bae1dSRodney W. Grimes 		}
248df8bae1dSRodney W. Grimes 	}
249df8bae1dSRodney W. Grimes 	p->p_cptr = NULL;
250df8bae1dSRodney W. Grimes 
251df8bae1dSRodney W. Grimes 	/*
252df8bae1dSRodney W. Grimes 	 * Save exit status and final rusage info, adding in child rusage
253df8bae1dSRodney W. Grimes 	 * info and self times.
254df8bae1dSRodney W. Grimes 	 */
255df8bae1dSRodney W. Grimes 	p->p_xstat = rv;
256df8bae1dSRodney W. Grimes 	*p->p_ru = p->p_stats->p_ru;
257df8bae1dSRodney W. Grimes 	calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
258df8bae1dSRodney W. Grimes 	ruadd(p->p_ru, &p->p_stats->p_cru);
259df8bae1dSRodney W. Grimes 
260df8bae1dSRodney W. Grimes 	/*
261df8bae1dSRodney W. Grimes 	 * Notify parent that we're gone.
262df8bae1dSRodney W. Grimes 	 */
263df8bae1dSRodney W. Grimes 	psignal(p->p_pptr, SIGCHLD);
264df8bae1dSRodney W. Grimes 	wakeup((caddr_t)p->p_pptr);
265df8bae1dSRodney W. Grimes #if defined(tahoe)
266df8bae1dSRodney W. Grimes 	/* move this to cpu_exit */
267df8bae1dSRodney W. Grimes 	p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
268df8bae1dSRodney W. Grimes #endif
269df8bae1dSRodney W. Grimes 	/*
270df8bae1dSRodney W. Grimes 	 * Clear curproc after we've done all operations
271df8bae1dSRodney W. Grimes 	 * that could block, and before tearing down the rest
272df8bae1dSRodney W. Grimes 	 * of the process state that might be used from clock, etc.
273df8bae1dSRodney W. Grimes 	 * Also, can't clear curproc while we're still runnable,
274df8bae1dSRodney W. Grimes 	 * as we're not on a run queue (we are current, just not
275df8bae1dSRodney W. Grimes 	 * a proper proc any longer!).
276df8bae1dSRodney W. Grimes 	 *
277df8bae1dSRodney W. Grimes 	 * Other substructures are freed from wait().
278df8bae1dSRodney W. Grimes 	 */
279df8bae1dSRodney W. Grimes 	curproc = NULL;
280be6a1d14SDavid Greenman 	if (--p->p_limit->p_refcnt == 0) {
281df8bae1dSRodney W. Grimes 		FREE(p->p_limit, M_SUBPROC);
282be6a1d14SDavid Greenman 		p->p_limit = NULL;
283be6a1d14SDavid Greenman 	}
284df8bae1dSRodney W. Grimes 
285df8bae1dSRodney W. Grimes 	/*
286df8bae1dSRodney W. Grimes 	 * Finally, call machine-dependent code to release the remaining
287df8bae1dSRodney W. Grimes 	 * resources including address space, the kernel stack and pcb.
288df8bae1dSRodney W. Grimes 	 * The address space is released by "vmspace_free(p->p_vmspace)";
289df8bae1dSRodney W. Grimes 	 * This is machine-dependent, as we may have to change stacks
290df8bae1dSRodney W. Grimes 	 * or ensure that the current one isn't reallocated before we
291df8bae1dSRodney W. Grimes 	 * finish.  cpu_exit will end with a call to cpu_swtch(), finishing
292df8bae1dSRodney W. Grimes 	 * our execution (pun intended).
293df8bae1dSRodney W. Grimes 	 */
294df8bae1dSRodney W. Grimes 	cpu_exit(p);
295df8bae1dSRodney W. Grimes }
296df8bae1dSRodney W. Grimes 
297b2f9e8b1SBruce Evans #ifdef COMPAT_43
298df8bae1dSRodney W. Grimes #if defined(hp300) || defined(luna68k)
299df8bae1dSRodney W. Grimes #include <machine/frame.h>
300df8bae1dSRodney W. Grimes #define GETPS(rp)	((struct frame *)(rp))->f_sr
301df8bae1dSRodney W. Grimes #else
302df8bae1dSRodney W. Grimes #define GETPS(rp)	(rp)[PS]
303df8bae1dSRodney W. Grimes #endif
304df8bae1dSRodney W. Grimes 
30526f9a767SRodney W. Grimes int
306df8bae1dSRodney W. Grimes owait(p, uap, retval)
307df8bae1dSRodney W. Grimes 	struct proc *p;
3085fdb8324SBruce Evans 	register struct owait_args /* {
3095fdb8324SBruce Evans 		int     dummy;
3105fdb8324SBruce Evans 	} */ *uap;
311df8bae1dSRodney W. Grimes 	int *retval;
312df8bae1dSRodney W. Grimes {
31393c9414eSSteven Wallace 	struct wait_args w;
314df8bae1dSRodney W. Grimes 
315df8bae1dSRodney W. Grimes #ifdef PSL_ALLCC
316df8bae1dSRodney W. Grimes 	if ((GETPS(p->p_md.md_regs) & PSL_ALLCC) != PSL_ALLCC) {
31793c9414eSSteven Wallace 		w.options = 0;
31893c9414eSSteven Wallace 		w.rusage = NULL;
319df8bae1dSRodney W. Grimes 	} else {
32093c9414eSSteven Wallace 		w.options = p->p_md.md_regs[R0];
32193c9414eSSteven Wallace 		w.rusage = (struct rusage *)p->p_md.md_regs[R1];
322df8bae1dSRodney W. Grimes 	}
323df8bae1dSRodney W. Grimes #else
32493c9414eSSteven Wallace 	w.options = 0;
32593c9414eSSteven Wallace 	w.rusage = NULL;
326df8bae1dSRodney W. Grimes #endif
32793c9414eSSteven Wallace 	w.pid = WAIT_ANY;
32893c9414eSSteven Wallace 	w.status = NULL;
32993c9414eSSteven Wallace 	return (wait1(p, &w, retval, 1));
330df8bae1dSRodney W. Grimes }
331b2f9e8b1SBruce Evans #endif /* COMPAT_43 */
332df8bae1dSRodney W. Grimes 
33326f9a767SRodney W. Grimes int
334df8bae1dSRodney W. Grimes wait4(p, uap, retval)
335df8bae1dSRodney W. Grimes 	struct proc *p;
336df8bae1dSRodney W. Grimes 	struct wait_args *uap;
337df8bae1dSRodney W. Grimes 	int *retval;
338df8bae1dSRodney W. Grimes {
3395fdb8324SBruce Evans 
34093c9414eSSteven Wallace 	return (wait1(p, uap, retval, 0));
341df8bae1dSRodney W. Grimes }
342df8bae1dSRodney W. Grimes 
34393c9414eSSteven Wallace static int
34493c9414eSSteven Wallace wait1(q, uap, retval, compat)
345df8bae1dSRodney W. Grimes 	register struct proc *q;
3465fdb8324SBruce Evans 	register struct wait_args /* {
3475fdb8324SBruce Evans 		int pid;
3485fdb8324SBruce Evans 		int *status;
3495fdb8324SBruce Evans 		int options;
3505fdb8324SBruce Evans 		struct rusage *rusage;
3515fdb8324SBruce Evans 	} */ *uap;
352df8bae1dSRodney W. Grimes 	int retval[];
35393c9414eSSteven Wallace 	int compat;
354df8bae1dSRodney W. Grimes {
355df8bae1dSRodney W. Grimes 	register int nfound;
356df8bae1dSRodney W. Grimes 	register struct proc *p, *t;
357f23c6d68SSteven Wallace 	int status, error;
358df8bae1dSRodney W. Grimes 
359df8bae1dSRodney W. Grimes 	if (uap->pid == 0)
360df8bae1dSRodney W. Grimes 		uap->pid = -q->p_pgid;
361df8bae1dSRodney W. Grimes #ifdef notyet
362df8bae1dSRodney W. Grimes 	if (uap->options &~ (WUNTRACED|WNOHANG))
363df8bae1dSRodney W. Grimes 		return (EINVAL);
364df8bae1dSRodney W. Grimes #endif
365df8bae1dSRodney W. Grimes loop:
366df8bae1dSRodney W. Grimes 	nfound = 0;
367df8bae1dSRodney W. Grimes 	for (p = q->p_cptr; p; p = p->p_osptr) {
368df8bae1dSRodney W. Grimes 		if (uap->pid != WAIT_ANY &&
369df8bae1dSRodney W. Grimes 		    p->p_pid != uap->pid && p->p_pgid != -uap->pid)
370df8bae1dSRodney W. Grimes 			continue;
371df8bae1dSRodney W. Grimes 		nfound++;
372df8bae1dSRodney W. Grimes 		if (p->p_stat == SZOMB) {
3730d2afceeSDavid Greenman 			/* charge childs scheduling cpu usage to parent */
374d5c4431eSDavid Greenman 			if (curproc->p_pid != 1) {
375d5c4431eSDavid Greenman 				curproc->p_estcpu = min(curproc->p_estcpu +
376d5c4431eSDavid Greenman 				    p->p_estcpu, UCHAR_MAX);
377d5c4431eSDavid Greenman 			}
3780d2afceeSDavid Greenman 
379df8bae1dSRodney W. Grimes 			retval[0] = p->p_pid;
380b2f9e8b1SBruce Evans #ifdef COMPAT_43
38193c9414eSSteven Wallace 			if (compat)
382f23c6d68SSteven Wallace 				retval[1] = p->p_xstat;
383df8bae1dSRodney W. Grimes 			else
384df8bae1dSRodney W. Grimes #endif
385df8bae1dSRodney W. Grimes 			if (uap->status) {
386df8bae1dSRodney W. Grimes 				status = p->p_xstat;	/* convert to int */
387bb56ec4aSPoul-Henning Kamp 				if ((error = copyout((caddr_t)&status,
388bb56ec4aSPoul-Henning Kamp 				    (caddr_t)uap->status, sizeof(status))))
389df8bae1dSRodney W. Grimes 					return (error);
390df8bae1dSRodney W. Grimes 			}
391df8bae1dSRodney W. Grimes 			if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
392df8bae1dSRodney W. Grimes 			    (caddr_t)uap->rusage, sizeof (struct rusage))))
393df8bae1dSRodney W. Grimes 				return (error);
394df8bae1dSRodney W. Grimes 			/*
395df8bae1dSRodney W. Grimes 			 * If we got the child via a ptrace 'attach',
396df8bae1dSRodney W. Grimes 			 * we need to give it back to the old parent.
397df8bae1dSRodney W. Grimes 			 */
398df8bae1dSRodney W. Grimes 			if (p->p_oppid && (t = pfind(p->p_oppid))) {
399df8bae1dSRodney W. Grimes 				p->p_oppid = 0;
400df8bae1dSRodney W. Grimes 				proc_reparent(p, t);
401df8bae1dSRodney W. Grimes 				psignal(t, SIGCHLD);
402df8bae1dSRodney W. Grimes 				wakeup((caddr_t)t);
403df8bae1dSRodney W. Grimes 				return (0);
404df8bae1dSRodney W. Grimes 			}
405df8bae1dSRodney W. Grimes 			p->p_xstat = 0;
406df8bae1dSRodney W. Grimes 			ruadd(&q->p_stats->p_cru, p->p_ru);
407df8bae1dSRodney W. Grimes 			FREE(p->p_ru, M_ZOMBIE);
408be6a1d14SDavid Greenman 			p->p_ru = NULL;
409df8bae1dSRodney W. Grimes 
410df8bae1dSRodney W. Grimes 			/*
411df8bae1dSRodney W. Grimes 			 * Decrement the count of procs running with this uid.
412df8bae1dSRodney W. Grimes 			 */
413df8bae1dSRodney W. Grimes 			(void)chgproccnt(p->p_cred->p_ruid, -1);
414df8bae1dSRodney W. Grimes 
415df8bae1dSRodney W. Grimes 			/*
416df8bae1dSRodney W. Grimes 			 * Free up credentials.
417df8bae1dSRodney W. Grimes 			 */
418df8bae1dSRodney W. Grimes 			if (--p->p_cred->p_refcnt == 0) {
419df8bae1dSRodney W. Grimes 				crfree(p->p_cred->pc_ucred);
420df8bae1dSRodney W. Grimes 				FREE(p->p_cred, M_SUBPROC);
421be6a1d14SDavid Greenman 				p->p_cred = NULL;
422df8bae1dSRodney W. Grimes 			}
423df8bae1dSRodney W. Grimes 
424df8bae1dSRodney W. Grimes 			/*
425df8bae1dSRodney W. Grimes 			 * Release reference to text vnode
426df8bae1dSRodney W. Grimes 			 */
427df8bae1dSRodney W. Grimes 			if (p->p_textvp)
428df8bae1dSRodney W. Grimes 				vrele(p->p_textvp);
429df8bae1dSRodney W. Grimes 
430df8bae1dSRodney W. Grimes 			/*
431df8bae1dSRodney W. Grimes 			 * Finally finished with old proc entry.
432df8bae1dSRodney W. Grimes 			 * Unlink it from its process group and free it.
433df8bae1dSRodney W. Grimes 			 */
434df8bae1dSRodney W. Grimes 			leavepgrp(p);
435bb56ec4aSPoul-Henning Kamp 			if ((*p->p_prev = p->p_next))	/* off zombproc */
436df8bae1dSRodney W. Grimes 				p->p_next->p_prev = p->p_prev;
437bb56ec4aSPoul-Henning Kamp 			if ((q = p->p_ysptr))
438df8bae1dSRodney W. Grimes 				q->p_osptr = p->p_osptr;
439bb56ec4aSPoul-Henning Kamp 			if ((q = p->p_osptr))
440df8bae1dSRodney W. Grimes 				q->p_ysptr = p->p_ysptr;
441df8bae1dSRodney W. Grimes 			if ((q = p->p_pptr)->p_cptr == p)
442df8bae1dSRodney W. Grimes 				q->p_cptr = p->p_osptr;
443df8bae1dSRodney W. Grimes 
444df8bae1dSRodney W. Grimes 			/*
445df8bae1dSRodney W. Grimes 			 * Give machine-dependent layer a chance
446df8bae1dSRodney W. Grimes 			 * to free anything that cpu_exit couldn't
447df8bae1dSRodney W. Grimes 			 * release while still running in process context.
448df8bae1dSRodney W. Grimes 			 */
449df8bae1dSRodney W. Grimes 			cpu_wait(p);
450df8bae1dSRodney W. Grimes 			FREE(p, M_PROC);
451df8bae1dSRodney W. Grimes 			nprocs--;
452df8bae1dSRodney W. Grimes 			return (0);
453df8bae1dSRodney W. Grimes 		}
454df8bae1dSRodney W. Grimes 		if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
455df8bae1dSRodney W. Grimes 		    (p->p_flag & P_TRACED || uap->options & WUNTRACED)) {
456df8bae1dSRodney W. Grimes 			p->p_flag |= P_WAITED;
457df8bae1dSRodney W. Grimes 			retval[0] = p->p_pid;
458b2f9e8b1SBruce Evans #ifdef COMPAT_43
45993c9414eSSteven Wallace 			if (compat) {
460f23c6d68SSteven Wallace 				retval[1] = W_STOPCODE(p->p_xstat);
461df8bae1dSRodney W. Grimes 				error = 0;
462df8bae1dSRodney W. Grimes 			} else
463df8bae1dSRodney W. Grimes #endif
464df8bae1dSRodney W. Grimes 			if (uap->status) {
465df8bae1dSRodney W. Grimes 				status = W_STOPCODE(p->p_xstat);
466df8bae1dSRodney W. Grimes 				error = copyout((caddr_t)&status,
467df8bae1dSRodney W. Grimes 					(caddr_t)uap->status, sizeof(status));
468df8bae1dSRodney W. Grimes 			} else
469df8bae1dSRodney W. Grimes 				error = 0;
470df8bae1dSRodney W. Grimes 			return (error);
471df8bae1dSRodney W. Grimes 		}
472df8bae1dSRodney W. Grimes 	}
473df8bae1dSRodney W. Grimes 	if (nfound == 0)
474df8bae1dSRodney W. Grimes 		return (ECHILD);
475df8bae1dSRodney W. Grimes 	if (uap->options & WNOHANG) {
476df8bae1dSRodney W. Grimes 		retval[0] = 0;
477df8bae1dSRodney W. Grimes 		return (0);
478df8bae1dSRodney W. Grimes 	}
479bb56ec4aSPoul-Henning Kamp 	if ((error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)))
480df8bae1dSRodney W. Grimes 		return (error);
481df8bae1dSRodney W. Grimes 	goto loop;
482df8bae1dSRodney W. Grimes }
483df8bae1dSRodney W. Grimes 
484df8bae1dSRodney W. Grimes /*
485df8bae1dSRodney W. Grimes  * make process 'parent' the new parent of process 'child'.
486df8bae1dSRodney W. Grimes  */
487df8bae1dSRodney W. Grimes void
488df8bae1dSRodney W. Grimes proc_reparent(child, parent)
489df8bae1dSRodney W. Grimes 	register struct proc *child;
490df8bae1dSRodney W. Grimes 	register struct proc *parent;
491df8bae1dSRodney W. Grimes {
492df8bae1dSRodney W. Grimes 	register struct proc *o;
493df8bae1dSRodney W. Grimes 	register struct proc *y;
494df8bae1dSRodney W. Grimes 
495df8bae1dSRodney W. Grimes 	if (child->p_pptr == parent)
496df8bae1dSRodney W. Grimes 		return;
497df8bae1dSRodney W. Grimes 
498df8bae1dSRodney W. Grimes 	/* fix up the child linkage for the old parent */
499df8bae1dSRodney W. Grimes 	o = child->p_osptr;
500df8bae1dSRodney W. Grimes 	y = child->p_ysptr;
501df8bae1dSRodney W. Grimes 	if (y)
502df8bae1dSRodney W. Grimes 		y->p_osptr = o;
503df8bae1dSRodney W. Grimes 	if (o)
504df8bae1dSRodney W. Grimes 		o->p_ysptr = y;
505df8bae1dSRodney W. Grimes 	if (child->p_pptr->p_cptr == child)
506df8bae1dSRodney W. Grimes 		child->p_pptr->p_cptr = o;
507df8bae1dSRodney W. Grimes 
508df8bae1dSRodney W. Grimes 	/* fix up child linkage for new parent */
509df8bae1dSRodney W. Grimes 	o = parent->p_cptr;
510df8bae1dSRodney W. Grimes 	if (o)
511df8bae1dSRodney W. Grimes 		o->p_ysptr = child;
512df8bae1dSRodney W. Grimes 	child->p_osptr = o;
513df8bae1dSRodney W. Grimes 	child->p_ysptr = NULL;
514df8bae1dSRodney W. Grimes 	parent->p_cptr = child;
515df8bae1dSRodney W. Grimes 	child->p_pptr = parent;
516df8bae1dSRodney W. Grimes }
517