386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / kern_exit.c
CommitLineData
83a70f80
WJ
1/*
2 * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)kern_exit.c 7.35 (Berkeley) 6/27/91
34 */
35
36#include "param.h"
37#include "systm.h"
38#include "ioctl.h"
39#include "tty.h"
40#include "time.h"
41#include "resource.h"
42#include "kernel.h"
43#include "proc.h"
44#include "buf.h"
45#include "wait.h"
46#include "file.h"
47#include "vnode.h"
48#include "syslog.h"
49#include "malloc.h"
50#include "resourcevar.h"
51
52#include "machine/cpu.h"
53#ifdef COMPAT_43
54#include "machine/reg.h"
55#include "machine/psl.h"
56#endif
57
58#include "vm/vm.h"
59#include "vm/vm_kern.h"
60
61/*
62 * Exit system call: pass back caller's arg
63 */
64/* ARGSUSED */
65rexit(p, uap, retval)
66 struct proc *p;
67 struct args {
68 int rval;
69 } *uap;
70 int *retval;
71{
72
73 exit(p, W_EXITCODE(uap->rval, 0));
74 /* NOTREACHED */
75}
76
77/*
78 * Exit: deallocate address space and other resources,
79 * change proc state to zombie, and unlink proc from allproc
80 * and parent's lists. Save exit status and rusage for wait().
81 * Check for child processes and orphan them.
82 */
83exit(p, rv)
84 register struct proc *p;
85 int rv;
86{
87 register struct proc *q, *nq;
88 register struct proc **pp;
89 int s;
90
91#ifdef PGINPROF
92 vmsizmon();
93#endif
94 MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
95 M_ZOMBIE, M_WAITOK);
96 /*
97 * If parent is waiting for us to exit or exec,
98 * SPPWAIT is set; we will wakeup the parent below.
99 */
100 p->p_flag &= ~(STRC|SPPWAIT);
101 p->p_flag |= SWEXIT;
102 p->p_sigignore = ~0;
103 p->p_sig = 0;
104 untimeout(realitexpire, (caddr_t)p);
105
106 /*
107 * Close open files and release open-file table.
108 * This may block!
109 */
110 fdfree(p);
111
112 /* The next two chunks should probably be moved to vmspace_exit. */
113#ifdef SYSVSHM
114 if (p->p_vmspace->vm_shm)
115 shmexit(p);
116#endif
117 /*
118 * Release user portion of address space.
119 * This releases references to vnodes,
120 * which could cause I/O if the file has been unlinked.
121 * Need to do this early enough that we can still sleep.
122 * Can't free the entire vmspace as the kernel stack
123 * may be mapped within that space also.
124 */
125 if (p->p_vmspace->vm_refcnt == 1)
126 (void) vm_map_remove(&p->p_vmspace->vm_map, VM_MIN_ADDRESS,
127 VM_MAXUSER_ADDRESS);
128
129 if (p->p_pid == 1)
130 panic("init died");
131
132 if (SESS_LEADER(p)) {
133 register struct session *sp = p->p_session;
134
135 if (sp->s_ttyvp) {
136 /*
137 * Controlling process.
138 * Signal foreground pgrp,
139 * drain controlling terminal
140 * and revoke access to controlling terminal.
141 */
142 if (sp->s_ttyp->t_session == sp) {
143 if (sp->s_ttyp->t_pgrp)
144 pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
145 (void) ttywait(sp->s_ttyp);
146 vgoneall(sp->s_ttyvp);
147 }
148 vrele(sp->s_ttyvp);
149 sp->s_ttyvp = NULL;
150 /*
151 * s_ttyp is not zero'd; we use this to indicate
152 * that the session once had a controlling terminal.
153 * (for logging and informational purposes)
154 */
155 }
156 sp->s_leader = NULL;
157 }
158 fixjobc(p, p->p_pgrp, 0);
159 p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
160#ifdef KTRACE
161 /*
162 * release trace file
163 */
164 if (p->p_tracep)
165 vrele(p->p_tracep);
166#endif
167
168 /* current process does not exist, as far as other parts of the
169 * system (clock) is concerned, since parts of it might not be
170 * there anymore */
171 curproc = NULL;
172
173 if (--p->p_limit->p_refcnt == 0) {
174 FREE(p->p_limit, M_SUBPROC);
175 p->p_limit = (struct plimit *) -1;
176 }
177
178 /*
179 * Remove proc from allproc queue and pidhash chain.
180 * Place onto zombproc. Unlink from parent's child list.
181 */
182 if (*p->p_prev = p->p_nxt)
183 p->p_nxt->p_prev = p->p_prev;
184 if (p->p_nxt = zombproc)
185 p->p_nxt->p_prev = &p->p_nxt;
186 p->p_prev = &zombproc;
187 zombproc = p;
188 p->p_stat = SZOMB;
189 for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
190 if (*pp == p) {
191 *pp = p->p_hash;
192 goto done;
193 }
194 panic("exit");
195done:
196
197 if (p->p_cptr) /* only need this if any child is S_ZOMB */
198 wakeup((caddr_t) initproc);
199 for (q = p->p_cptr; q != NULL; q = nq) {
200 nq = q->p_osptr;
201 if (nq != NULL)
202 nq->p_ysptr = NULL;
203 if (initproc->p_cptr)
204 initproc->p_cptr->p_ysptr = q;
205 q->p_osptr = initproc->p_cptr;
206 q->p_ysptr = NULL;
207 initproc->p_cptr = q;
208
209 q->p_pptr = initproc;
210 /*
211 * Traced processes are killed
212 * since their existence means someone is screwing up.
213 */
214 if (q->p_flag&STRC) {
215 q->p_flag &= ~STRC;
216 psignal(q, SIGKILL);
217 }
218 }
219 p->p_cptr = NULL;
220
221 /*
222 * Save exit status and final rusage info,
223 * adding in child rusage info and self times.
224 */
225 p->p_xstat = rv;
226 *p->p_ru = p->p_stats->p_ru;
227 p->p_ru->ru_stime = p->p_stime;
228 p->p_ru->ru_utime = p->p_utime;
229 ruadd(p->p_ru, &p->p_stats->p_cru);
230
231 /*
232 * Notify parent that we're gone.
233 */
234 psignal(p->p_pptr, SIGCHLD);
235 wakeup((caddr_t)p->p_pptr);
236#if defined(tahoe)
237 /* move this to cpu_exit */
238 p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
239#endif
240 /*
241 * Finally, call machine-dependent code to release the remaining
242 * resources including address space, the kernel stack and pcb.
243 * The address space is released by "vmspace_free(p->p_vmspace)";
244 * This is machine-dependent, as we may have to change stacks
245 * or ensure that the current one isn't reallocated before we
246 * finish. cpu_exit will end with a call to swtch(), finishing
247 * our execution (pun intended).
248 */
249 cpu_exit(p);
250 /* NOTREACHED */
251}
252
253#ifdef COMPAT_43
254owait(p, uap, retval)
255 struct proc *p;
256 register struct args {
257 int pid;
258 int *status;
259 int options;
260 struct rusage *rusage;
261 int compat;
262 } *uap;
263 int *retval;
264{
265
266 uap->options = 0;
267 uap->rusage = 0;
268 uap->pid = WAIT_ANY;
269 uap->status = 0;
270 uap->compat = 1;
271 return (wait1(p, uap, retval));
272}
273
274wait4(p, uap, retval)
275 struct proc *p;
276 struct args {
277 int pid;
278 int *status;
279 int options;
280 struct rusage *rusage;
281 int compat;
282 } *uap;
283 int *retval;
284{
285
286 uap->compat = 0;
287 return (wait1(p, uap, retval));
288}
289#else
290#define wait1 wait4
291#endif
292
293/*
294 * Wait: check child processes to see if any have exited,
295 * stopped under trace, or (optionally) stopped by a signal.
296 * Pass back status and deallocate exited child's proc structure.
297 */
298wait1(q, uap, retval)
299 register struct proc *q;
300 register struct args {
301 int pid;
302 int *status;
303 int options;
304 struct rusage *rusage;
305#ifdef COMPAT_43
306 int compat;
307#endif
308 } *uap;
309 int retval[];
310{
311 register int nfound;
312 register struct proc *p;
313 int status, error;
314
315 if (uap->pid == 0)
316 uap->pid = -q->p_pgid;
317#ifdef notyet
318 if (uap->options &~ (WUNTRACED|WNOHANG))
319 return (EINVAL);
320#endif
321loop:
322 nfound = 0;
323 for (p = q->p_cptr; p; p = p->p_osptr) {
324 if (uap->pid != WAIT_ANY &&
325 p->p_pid != uap->pid && p->p_pgid != -uap->pid)
326 continue;
327 nfound++;
328 if (p->p_stat == SZOMB) {
329 retval[0] = p->p_pid;
330#ifdef COMPAT_43
331 if (uap->compat)
332 retval[1] = p->p_xstat;
333 else
334#endif
335 if (uap->status) {
336 status = p->p_xstat; /* convert to int */
337 if (error = copyout((caddr_t)&status,
338 (caddr_t)uap->status, sizeof(status)))
339 return (error);
340 }
341 if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
342 (caddr_t)uap->rusage, sizeof (struct rusage))))
343 return (error);
344 p->p_xstat = 0;
345 ruadd(&q->p_stats->p_cru, p->p_ru);
346 FREE(p->p_ru, M_ZOMBIE);
347 if (--p->p_cred->p_refcnt == 0) {
348 crfree(p->p_cred->pc_ucred);
349 FREE(p->p_cred, M_SUBPROC);
350 p->p_cred = (struct pcred *) -1;
351 }
352
353 /*
354 * Finally finished with old proc entry.
355 * Unlink it from its process group and free it.
356 */
357 leavepgrp(p);
358 if (*p->p_prev = p->p_nxt) /* off zombproc */
359 p->p_nxt->p_prev = p->p_prev;
360 if (q = p->p_ysptr)
361 q->p_osptr = p->p_osptr;
362 if (q = p->p_osptr)
363 q->p_ysptr = p->p_ysptr;
364 if ((q = p->p_pptr)->p_cptr == p)
365 q->p_cptr = p->p_osptr;
366
367 /*
368 * Give machine-dependent layer a chance
369 * to free anything that cpu_exit couldn't
370 * release while still running in process context.
371 */
372 cpu_wait(p);
373 FREE(p, M_PROC);
374 nprocs--;
375 return (0);
376 }
377 if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 &&
378 (p->p_flag & STRC || uap->options & WUNTRACED)) {
379 p->p_flag |= SWTED;
380 retval[0] = p->p_pid;
381#ifdef COMPAT_43
382 if (uap->compat) {
383 retval[1] = W_STOPCODE(p->p_xstat);
384 error = 0;
385 } else
386#endif
387 if (uap->status) {
388 status = W_STOPCODE(p->p_xstat);
389 error = copyout((caddr_t)&status,
390 (caddr_t)uap->status, sizeof(status));
391 } else
392 error = 0;
393 return (error);
394 }
395 }
396 if (nfound == 0)
397 return (ECHILD);
398 if (uap->options & WNOHANG) {
399 retval[0] = 0;
400 return (0);
401 }
402 if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
403 return (error);
404 goto loop;
405}