Fix from Yuval Yurom:
[unix-history] / sys / kern / kern_exit.c
CommitLineData
15637ed4
RG
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 *
600f7f07 33 * from: @(#)kern_exit.c 7.35 (Berkeley) 6/27/91
749a84ff 34 * $Id: kern_exit.c,v 1.8 1993/10/16 15:24:15 rgrimes Exp $
15637ed4
RG
35 */
36
37#include "param.h"
38#include "systm.h"
39#include "ioctl.h"
40#include "tty.h"
41#include "time.h"
42#include "resource.h"
43#include "kernel.h"
44#include "proc.h"
45#include "buf.h"
46#include "wait.h"
47#include "file.h"
48#include "vnode.h"
49#include "syslog.h"
50#include "malloc.h"
51#include "resourcevar.h"
52
53#include "machine/cpu.h"
54#ifdef COMPAT_43
55#include "machine/reg.h"
56#include "machine/psl.h"
57#endif
58
59#include "vm/vm.h"
60#include "vm/vm_kern.h"
61
62/*
63 * Exit system call: pass back caller's arg
64 */
3c7eb27c
DG
65
66struct rexit_args {
67 int rval;
68};
15637ed4 69/* ARGSUSED */
603809a1 70void
15637ed4
RG
71rexit(p, uap, retval)
72 struct proc *p;
3c7eb27c 73 struct rexit_args *uap;
15637ed4
RG
74 int *retval;
75{
76
e5b1af89 77 kexit(p, W_EXITCODE(uap->rval, 0));
15637ed4
RG
78 /* NOTREACHED */
79}
80
81/*
82 * Exit: deallocate address space and other resources,
83 * change proc state to zombie, and unlink proc from allproc
84 * and parent's lists. Save exit status and rusage for wait().
85 * Check for child processes and orphan them.
86 */
603809a1 87void
e5b1af89 88kexit(p, rv)
15637ed4
RG
89 register struct proc *p;
90 int rv;
91{
92 register struct proc *q, *nq;
93 register struct proc **pp;
94 int s;
95
749a84ff 96 acct(p); /* MT - do process accounting -- must be done before
603809a1
NW
97 address space is released */
98
15637ed4
RG
99#ifdef PGINPROF
100 vmsizmon();
101#endif
102 MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
103 M_ZOMBIE, M_WAITOK);
104 /*
105 * If parent is waiting for us to exit or exec,
106 * SPPWAIT is set; we will wakeup the parent below.
107 */
108 p->p_flag &= ~(STRC|SPPWAIT);
109 p->p_flag |= SWEXIT;
110 p->p_sigignore = ~0;
111 p->p_sig = 0;
112 untimeout(realitexpire, (caddr_t)p);
113
114 /*
115 * Close open files and release open-file table.
116 * This may block!
117 */
118 fdfree(p);
119
120 /* The next two chunks should probably be moved to vmspace_exit. */
121#ifdef SYSVSHM
122 if (p->p_vmspace->vm_shm)
123 shmexit(p);
124#endif
125 /*
126 * Release user portion of address space.
127 * This releases references to vnodes,
128 * which could cause I/O if the file has been unlinked.
129 * Need to do this early enough that we can still sleep.
130 * Can't free the entire vmspace as the kernel stack
131 * may be mapped within that space also.
132 */
133 if (p->p_vmspace->vm_refcnt == 1)
134 (void) vm_map_remove(&p->p_vmspace->vm_map, VM_MIN_ADDRESS,
135 VM_MAXUSER_ADDRESS);
136
137 if (p->p_pid == 1)
138 panic("init died");
139
140 if (SESS_LEADER(p)) {
141 register struct session *sp = p->p_session;
142
143 if (sp->s_ttyvp) {
144 /*
145 * Controlling process.
146 * Signal foreground pgrp,
147 * drain controlling terminal
148 * and revoke access to controlling terminal.
149 */
150 if (sp->s_ttyp->t_session == sp) {
151 if (sp->s_ttyp->t_pgrp)
152 pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
153 (void) ttywait(sp->s_ttyp);
154 vgoneall(sp->s_ttyvp);
155 }
156 vrele(sp->s_ttyvp);
157 sp->s_ttyvp = NULL;
158 /*
159 * s_ttyp is not zero'd; we use this to indicate
160 * that the session once had a controlling terminal.
161 * (for logging and informational purposes)
162 */
163 }
164 sp->s_leader = NULL;
165 }
166 fixjobc(p, p->p_pgrp, 0);
167 p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
168#ifdef KTRACE
169 /*
170 * release trace file
171 */
172 if (p->p_tracep)
173 vrele(p->p_tracep);
174#endif
175
176 /* current process does not exist, as far as other parts of the
177 * system (clock) is concerned, since parts of it might not be
178 * there anymore */
179 curproc = NULL;
180
181 if (--p->p_limit->p_refcnt == 0) {
182 FREE(p->p_limit, M_SUBPROC);
183 p->p_limit = (struct plimit *) -1;
184 }
185
186 /*
187 * Remove proc from allproc queue and pidhash chain.
188 * Place onto zombproc. Unlink from parent's child list.
189 */
190 if (*p->p_prev = p->p_nxt)
191 p->p_nxt->p_prev = p->p_prev;
192 if (p->p_nxt = zombproc)
193 p->p_nxt->p_prev = &p->p_nxt;
194 p->p_prev = &zombproc;
195 zombproc = p;
196 p->p_stat = SZOMB;
197 for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
198 if (*pp == p) {
199 *pp = p->p_hash;
200 goto done;
201 }
202 panic("exit");
203done:
204
205 if (p->p_cptr) /* only need this if any child is S_ZOMB */
206 wakeup((caddr_t) initproc);
207 for (q = p->p_cptr; q != NULL; q = nq) {
208 nq = q->p_osptr;
209 if (nq != NULL)
210 nq->p_ysptr = NULL;
211 if (initproc->p_cptr)
212 initproc->p_cptr->p_ysptr = q;
213 q->p_osptr = initproc->p_cptr;
214 q->p_ysptr = NULL;
215 initproc->p_cptr = q;
216
217 q->p_pptr = initproc;
218 /*
219 * Traced processes are killed
220 * since their existence means someone is screwing up.
221 */
222 if (q->p_flag&STRC) {
223 q->p_flag &= ~STRC;
224 psignal(q, SIGKILL);
225 }
226 }
227 p->p_cptr = NULL;
228
229 /*
230 * Save exit status and final rusage info,
231 * adding in child rusage info and self times.
232 */
233 p->p_xstat = rv;
234 *p->p_ru = p->p_stats->p_ru;
235 p->p_ru->ru_stime = p->p_stime;
236 p->p_ru->ru_utime = p->p_utime;
237 ruadd(p->p_ru, &p->p_stats->p_cru);
238
239 /*
240 * Notify parent that we're gone.
241 */
242 psignal(p->p_pptr, SIGCHLD);
243 wakeup((caddr_t)p->p_pptr);
244#if defined(tahoe)
245 /* move this to cpu_exit */
246 p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
247#endif
248 /*
249 * Finally, call machine-dependent code to release the remaining
250 * resources including address space, the kernel stack and pcb.
251 * The address space is released by "vmspace_free(p->p_vmspace)";
252 * This is machine-dependent, as we may have to change stacks
253 * or ensure that the current one isn't reallocated before we
254 * finish. cpu_exit will end with a call to swtch(), finishing
255 * our execution (pun intended).
256 */
257 cpu_exit(p);
258 /* NOTREACHED */
259}
260
261#ifdef COMPAT_43
3c7eb27c
DG
262
263struct owait_args {
264 int pid;
265 int *status;
266 int options;
267 struct rusage *rusage;
268 int compat;
269};
270
15637ed4
RG
271owait(p, uap, retval)
272 struct proc *p;
3c7eb27c 273 register struct owait_args *uap;
15637ed4
RG
274 int *retval;
275{
276
277 uap->options = 0;
278 uap->rusage = 0;
279 uap->pid = WAIT_ANY;
280 uap->status = 0;
281 uap->compat = 1;
282 return (wait1(p, uap, retval));
283}
284
3c7eb27c
DG
285struct wait4_args {
286 int pid;
287 int *status;
288 int options;
289 struct rusage *rusage;
290 int compat;
291};
292
15637ed4
RG
293wait4(p, uap, retval)
294 struct proc *p;
3c7eb27c 295 struct wait4_args *uap;
15637ed4
RG
296 int *retval;
297{
298
299 uap->compat = 0;
300 return (wait1(p, uap, retval));
301}
302#else
303#define wait1 wait4
304#endif
305
306/*
307 * Wait: check child processes to see if any have exited,
308 * stopped under trace, or (optionally) stopped by a signal.
309 * Pass back status and deallocate exited child's proc structure.
310 */
3c7eb27c
DG
311
312struct wait1_args {
313 int pid;
314 int *status;
315 int options;
316 struct rusage *rusage;
15637ed4 317#ifdef COMPAT_43
3c7eb27c 318 int compat;
15637ed4 319#endif
3c7eb27c
DG
320};
321
322wait1(q, uap, retval)
323 register struct proc *q;
324 register struct wait1_args *uap;
15637ed4
RG
325 int retval[];
326{
327 register int nfound;
328 register struct proc *p;
329 int status, error;
330
331 if (uap->pid == 0)
332 uap->pid = -q->p_pgid;
333#ifdef notyet
334 if (uap->options &~ (WUNTRACED|WNOHANG))
335 return (EINVAL);
336#endif
337loop:
338 nfound = 0;
339 for (p = q->p_cptr; p; p = p->p_osptr) {
340 if (uap->pid != WAIT_ANY &&
341 p->p_pid != uap->pid && p->p_pgid != -uap->pid)
342 continue;
343 nfound++;
344 if (p->p_stat == SZOMB) {
345 retval[0] = p->p_pid;
346#ifdef COMPAT_43
347 if (uap->compat)
348 retval[1] = p->p_xstat;
349 else
350#endif
351 if (uap->status) {
352 status = p->p_xstat; /* convert to int */
353 if (error = copyout((caddr_t)&status,
354 (caddr_t)uap->status, sizeof(status)))
355 return (error);
356 }
357 if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
358 (caddr_t)uap->rusage, sizeof (struct rusage))))
359 return (error);
360 p->p_xstat = 0;
361 ruadd(&q->p_stats->p_cru, p->p_ru);
362 FREE(p->p_ru, M_ZOMBIE);
363 if (--p->p_cred->p_refcnt == 0) {
364 crfree(p->p_cred->pc_ucred);
365 FREE(p->p_cred, M_SUBPROC);
366 p->p_cred = (struct pcred *) -1;
367 }
368
369 /*
370 * Finally finished with old proc entry.
371 * Unlink it from its process group and free it.
372 */
373 leavepgrp(p);
374 if (*p->p_prev = p->p_nxt) /* off zombproc */
375 p->p_nxt->p_prev = p->p_prev;
376 if (q = p->p_ysptr)
377 q->p_osptr = p->p_osptr;
378 if (q = p->p_osptr)
379 q->p_ysptr = p->p_ysptr;
380 if ((q = p->p_pptr)->p_cptr == p)
381 q->p_cptr = p->p_osptr;
382
383 /*
384 * Give machine-dependent layer a chance
385 * to free anything that cpu_exit couldn't
386 * release while still running in process context.
387 */
388 cpu_wait(p);
389 FREE(p, M_PROC);
390 nprocs--;
391 return (0);
392 }
393 if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 &&
394 (p->p_flag & STRC || uap->options & WUNTRACED)) {
395 p->p_flag |= SWTED;
396 retval[0] = p->p_pid;
397#ifdef COMPAT_43
398 if (uap->compat) {
399 retval[1] = W_STOPCODE(p->p_xstat);
400 error = 0;
401 } else
402#endif
403 if (uap->status) {
404 status = W_STOPCODE(p->p_xstat);
405 error = copyout((caddr_t)&status,
406 (caddr_t)uap->status, sizeof(status));
407 } else
408 error = 0;
409 return (error);
410 }
411 }
412 if (nfound == 0)
413 return (ECHILD);
414 if (uap->options & WNOHANG) {
415 retval[0] = 0;
416 return (0);
417 }
418 if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
419 return (error);
420 goto loop;
421}