xref: /csrg-svn/sys/kern/kern_exit.c (revision 44404)
123369Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423369Smckusick  *
537728Smckusick  * Redistribution and use in source and binary forms are permitted
637728Smckusick  * provided that the above copyright notice and this paragraph are
737728Smckusick  * duplicated in all such forms and that any documentation,
837728Smckusick  * advertising materials, and other materials related to such
937728Smckusick  * distribution and use acknowledge that the software was developed
1037728Smckusick  * by the University of California, Berkeley.  The name of the
1137728Smckusick  * University may not be used to endorse or promote products derived
1237728Smckusick  * from this software without specific prior written permission.
1337728Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437728Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537728Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637728Smckusick  *
17*44404Skarels  *	@(#)kern_exit.c	7.25 (Berkeley) 06/28/90
1823369Smckusick  */
1912790Ssam 
2017090Sbloom #include "param.h"
2117090Sbloom #include "systm.h"
2217090Sbloom #include "map.h"
2342927Smckusick #include "ioctl.h"
2442927Smckusick #include "tty.h"
25*44404Skarels #include "user.h"
2617090Sbloom #include "kernel.h"
2717090Sbloom #include "proc.h"
2817090Sbloom #include "buf.h"
2917090Sbloom #include "wait.h"
3017090Sbloom #include "vm.h"
3117090Sbloom #include "file.h"
3237728Smckusick #include "vnode.h"
3318638Ssam #include "syslog.h"
3432018Smckusick #include "malloc.h"
3512790Ssam 
3637520Smckusick #include "machine/reg.h"
3737328Skarels #ifdef COMPAT_43
3837520Smckusick #include "machine/psl.h"
3937328Skarels #endif
4037328Skarels 
4112790Ssam /*
4212790Ssam  * Exit system call: pass back caller's arg
4312790Ssam  */
4442927Smckusick /* ARGSUSED */
4542927Smckusick rexit(p, uap, retval)
4642927Smckusick 	struct proc *p;
4742927Smckusick 	struct args {
4812790Ssam 		int	rval;
4912790Ssam 	} *uap;
5042927Smckusick 	int *retval;
5142927Smckusick {
5212790Ssam 
53*44404Skarels 	return (exit(p, W_EXITCODE(uap->rval, 0)));
5412790Ssam }
5512790Ssam 
5612790Ssam /*
5712790Ssam  * Release resources.
5812790Ssam  * Save u. area for parent to look at.
5912790Ssam  * Enter zombie state.
6012790Ssam  * Wake up parent and init processes,
6112790Ssam  * and dispose of children.
6212790Ssam  */
6342927Smckusick exit(p, rv)
6442927Smckusick 	struct proc *p;
6538930Skarels 	int rv;
6612790Ssam {
6712790Ssam 	register int i;
6842927Smckusick 	register struct proc *q, *nq;
6940670Skarels 	register struct proc **pp;
7012790Ssam 
7112790Ssam #ifdef PGINPROF
7212790Ssam 	vmsizmon();
7312790Ssam #endif
7432018Smckusick 	MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
7532018Smckusick 		M_ZOMBIE, M_WAITOK);
7612790Ssam 	p->p_flag &= ~(STRC|SULOCK);
7712790Ssam 	p->p_flag |= SWEXIT;
7812882Ssam 	p->p_sigignore = ~0;
7939410Skarels 	p->p_sig = 0;
8012790Ssam 	p->p_cpticks = 0;
8112790Ssam 	p->p_pctcpu = 0;
8212882Ssam 	for (i = 0; i < NSIG; i++)
8312790Ssam 		u.u_signal[i] = SIG_IGN;
8412790Ssam 	untimeout(realitexpire, (caddr_t)p);
8512790Ssam 	/*
8612790Ssam 	 * Release virtual memory.  If we resulted from
8712790Ssam 	 * a vfork(), instead give the resources back to
8812790Ssam 	 * the parent.
8912790Ssam 	 */
9041569Smckusick 	if ((p->p_flag & SVFORK) == 0) {
9141569Smckusick #ifdef MAPMEM
9241569Smckusick 		if (u.u_mmap)
9342927Smckusick 			(void) mmexit(p);
9441569Smckusick #endif
9512790Ssam 		vrelvm();
9641569Smckusick 	} else {
9712790Ssam 		p->p_flag &= ~SVFORK;
9812790Ssam 		wakeup((caddr_t)p);
9912790Ssam 		while ((p->p_flag & SVFDONE) == 0)
10012790Ssam 			sleep((caddr_t)p, PZERO - 1);
10112790Ssam 		p->p_flag &= ~SVFDONE;
10212790Ssam 	}
10321105Skarels 	for (i = 0; i <= u.u_lastfile; i++) {
10412790Ssam 		struct file *f;
10512790Ssam 
10612790Ssam 		f = u.u_ofile[i];
10721105Skarels 		if (f) {
10821105Skarels 			u.u_ofile[i] = NULL;
10921105Skarels 			u.u_pofile[i] = 0;
11039351Smckusick 			(void) closef(f);
11121105Skarels 		}
11212790Ssam 	}
11337328Skarels 	if (SESS_LEADER(p)) {
11442897Smarc 		register struct session *sp = p->p_session;
11542897Smarc 
11642897Smarc 		if (sp->s_ttyvp) {
11740809Smarc 			/*
11842897Smarc 			 * Controlling process.
11942897Smarc 			 * Signal foreground pgrp and revoke access
12042897Smarc 			 * to controlling terminal.
12142897Smarc 			 */
12242897Smarc 			if (sp->s_ttyp->t_pgrp)
12342916Smarc 				pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
12442897Smarc 			vgoneall(sp->s_ttyvp);
12542897Smarc 			vrele(sp->s_ttyvp);
12642897Smarc 			sp->s_ttyvp = NULL;
12742897Smarc 			/*
12840809Smarc 			 * s_ttyp is not zero'd; we use this to indicate
12940809Smarc 			 * that the session once had a controlling terminal.
13042897Smarc 			 * (for logging and informational purposes)
13140809Smarc 			 */
13237328Skarels 		}
13342897Smarc 		sp->s_leader = 0;
13437328Skarels 	}
13537728Smckusick 	VOP_LOCK(u.u_cdir);
13637728Smckusick 	vput(u.u_cdir);
13712790Ssam 	if (u.u_rdir) {
13837728Smckusick 		VOP_LOCK(u.u_rdir);
13937728Smckusick 		vput(u.u_rdir);
14012790Ssam 	}
14112790Ssam 	u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
14243380Smckusick 	(void) acct(p);
14337728Smckusick 	crfree(u.u_cred);
14437328Skarels #ifdef KTRACE
14537328Skarels 	/*
14637328Skarels 	 * release trace file
14737328Skarels 	 */
14837328Skarels 	if (p->p_tracep)
14937728Smckusick 		vrele(p->p_tracep);
15037328Skarels #endif
15126823Skarels 	/*
15226823Skarels 	 * Freeing the user structure and kernel stack
15326823Skarels 	 * for the current process: have to run a bit longer
15426823Skarels 	 * using the pages which are about to be freed...
15526823Skarels 	 * vrelu will block memory allocation by raising ipl.
15626823Skarels 	 */
15742927Smckusick 	vrelu(p, 0);
15842927Smckusick 	vrelpt(p);
15916527Skarels 	if (*p->p_prev = p->p_nxt)		/* off allproc queue */
16016527Skarels 		p->p_nxt->p_prev = p->p_prev;
16116527Skarels 	if (p->p_nxt = zombproc)		/* onto zombproc */
16216527Skarels 		p->p_nxt->p_prev = &p->p_nxt;
16316527Skarels 	p->p_prev = &zombproc;
16416527Skarels 	zombproc = p;
16512790Ssam 	multprog--;
16612790Ssam 	p->p_stat = SZOMB;
16712790Ssam 	noproc = 1;
16840670Skarels 	for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
16940670Skarels 		if (*pp == p) {
17040670Skarels 			*pp = p->p_hash;
17140670Skarels 			goto done;
17240670Skarels 		}
17340670Skarels 	panic("exit");
17440670Skarels done:
17521105Skarels 	if (p->p_pid == 1) {
17621105Skarels 		if (p->p_dsize == 0) {
17739410Skarels 			printf("Can't exec init (errno %d)\n", WEXITSTATUS(rv));
17821105Skarels 			for (;;)
17921105Skarels 				;
18021105Skarels 		} else
18121105Skarels 			panic("init died");
18221105Skarels 	}
18312790Ssam 	p->p_xstat = rv;
18421105Skarels 	*p->p_ru = u.u_ru;
18540809Smarc 	i = splclock();
18640809Smarc 	p->p_ru->ru_stime = p->p_stime;
18740809Smarc 	p->p_ru->ru_utime = p->p_utime;
18840809Smarc 	splx(i);
18921105Skarels 	ruadd(p->p_ru, &u.u_cru);
19016527Skarels 	if (p->p_cptr)		/* only need this if any child is S_ZOMB */
19116527Skarels 		wakeup((caddr_t)&proc[1]);
19242897Smarc 	fixjobc(p, 0);
19316527Skarels 	for (q = p->p_cptr; q != NULL; q = nq) {
19416527Skarels 		nq = q->p_osptr;
19516527Skarels 		if (nq != NULL)
19616527Skarels 			nq->p_ysptr = NULL;
19716527Skarels 		if (proc[1].p_cptr)
19816527Skarels 			proc[1].p_cptr->p_ysptr = q;
19916527Skarels 		q->p_osptr = proc[1].p_cptr;
20016527Skarels 		q->p_ysptr = NULL;
20116527Skarels 		proc[1].p_cptr = q;
20212790Ssam 
20316527Skarels 		q->p_pptr = &proc[1];
20416527Skarels 		q->p_ppid = 1;
20516527Skarels 		/*
20616527Skarels 		 * Traced processes are killed
20716527Skarels 		 * since their existence means someone is screwing up.
20816527Skarels 		 */
20916527Skarels 		if (q->p_flag&STRC) {
21016527Skarels 			q->p_flag &= ~STRC;
21116527Skarels 			psignal(q, SIGKILL);
21212790Ssam 		}
21316527Skarels 	}
21417540Skarels 	p->p_cptr = NULL;
21512790Ssam 	psignal(p->p_pptr, SIGCHLD);
21612790Ssam 	wakeup((caddr_t)p->p_pptr);
21729946Skarels #if defined(tahoe)
21829946Skarels 	dkeyrelease(p->p_dkey), p->p_dkey = 0;
21929946Skarels 	ckeyrelease(p->p_ckey), p->p_ckey = 0;
22029946Skarels 	u.u_pcb.pcb_savacc.faddr = (float *)NULL;
22129946Skarels #endif
22212790Ssam 	swtch();
22312790Ssam }
22412790Ssam 
22537328Skarels #ifdef COMPAT_43
22642927Smckusick owait(p, uap, retval)
22742927Smckusick 	struct proc *p;
22842927Smckusick 	register struct args {
22937328Skarels 		int	pid;
23039410Skarels 		int	*status;
23137328Skarels 		int	options;
23237328Skarels 		struct	rusage *rusage;
23339410Skarels 		int	compat;
23442927Smckusick 	} *uap;
23542927Smckusick 	int *retval;
23642927Smckusick {
23712790Ssam 
23812790Ssam 	if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) {
23938930Skarels 		uap->options = 0;
24037328Skarels 		uap->rusage = 0;
24137328Skarels 	} else {
24238930Skarels 		uap->options = u.u_ar0[R0];
24337328Skarels 		uap->rusage = (struct rusage *)u.u_ar0[R1];
24412790Ssam 	}
24537328Skarels 	uap->pid = WAIT_ANY;
24637328Skarels 	uap->status = 0;
24739410Skarels 	uap->compat = 1;
248*44404Skarels 	return (wait1(p, uap, retval));
24912790Ssam }
25012790Ssam 
25142927Smckusick wait4(p, uap, retval)
25242927Smckusick 	struct proc *p;
25342927Smckusick 	struct args {
25439410Skarels 		int	pid;
25539410Skarels 		int	*status;
25639410Skarels 		int	options;
25739410Skarels 		struct	rusage *rusage;
25839410Skarels 		int	compat;
25942927Smckusick 	} *uap;
26042927Smckusick 	int *retval;
26142927Smckusick {
26239410Skarels 
26339410Skarels 	uap->compat = 0;
264*44404Skarels 	return (wait1(p, uap, retval));
26537328Skarels }
26639410Skarels #else
26739410Skarels #define	wait1	wait4
26837328Skarels #endif
26937328Skarels 
27012790Ssam /*
27112790Ssam  * Wait system call.
27212790Ssam  * Search for a terminated (zombie) child,
27312790Ssam  * finally lay it to rest, and collect its status.
27412790Ssam  * Look also for stopped (traced) children,
27512790Ssam  * and pass back status from them.
27612790Ssam  */
27742927Smckusick wait1(q, uap, retval)
27842927Smckusick 	register struct proc *q;
27942927Smckusick 	register struct args {
28037328Skarels 		int	pid;
28139410Skarels 		int	*status;
28237328Skarels 		int	options;
28337328Skarels 		struct	rusage *rusage;
28439410Skarels #ifdef COMPAT_43
28539410Skarels 		int compat;
28639410Skarels #endif
28742927Smckusick 	} *uap;
28842927Smckusick 	int retval[];
28942927Smckusick {
29042927Smckusick 	register int f;
29142927Smckusick 	register struct proc *p;
29239410Skarels 	int status, error;
29312790Ssam 
29437328Skarels 	if (uap->pid == 0)
29537328Skarels 		uap->pid = -q->p_pgid;
29638930Skarels #ifdef notyet
29739410Skarels 	if (uap->options &~ (WUNTRACED|WNOHANG))
298*44404Skarels 		return (EINVAL);
29938930Skarels #endif
30012790Ssam loop:
30138930Skarels 	f = 0;
30216527Skarels 	for (p = q->p_cptr; p; p = p->p_osptr) {
30337328Skarels 		if (uap->pid != WAIT_ANY &&
30437328Skarels 		    p->p_pid != uap->pid && p->p_pgid != -uap->pid)
30537328Skarels 			continue;
30612790Ssam 		f++;
30712790Ssam 		if (p->p_stat == SZOMB) {
30842927Smckusick 			retval[0] = p->p_pid;
30937328Skarels #ifdef COMPAT_43
31039410Skarels 			if (uap->compat)
31142927Smckusick 				retval[1] = p->p_xstat;
31237328Skarels 			else
31337328Skarels #endif
31437328Skarels 			if (uap->status) {
31539410Skarels 				status = p->p_xstat;	/* convert to int */
31639410Skarels 				if (error = copyout((caddr_t)&status,
31737328Skarels 				    (caddr_t)uap->status, sizeof(status)))
318*44404Skarels 					return (error);
31937328Skarels 			}
32039410Skarels 			if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
32139410Skarels 			    (caddr_t)uap->rusage, sizeof (struct rusage))))
322*44404Skarels 				return (error);
32339410Skarels 			pgrm(p);			/* off pgrp */
32412790Ssam 			p->p_xstat = 0;
32537328Skarels 			ruadd(&u.u_cru, p->p_ru);
32637328Skarels 			FREE(p->p_ru, M_ZOMBIE);
32737328Skarels 			p->p_ru = 0;
32812790Ssam 			p->p_stat = NULL;
32912790Ssam 			p->p_pid = 0;
33012790Ssam 			p->p_ppid = 0;
33116527Skarels 			if (*p->p_prev = p->p_nxt)	/* off zombproc */
33216527Skarels 				p->p_nxt->p_prev = p->p_prev;
33316527Skarels 			p->p_nxt = freeproc;		/* onto freeproc */
33416527Skarels 			freeproc = p;
33512790Ssam 			if (q = p->p_ysptr)
33612790Ssam 				q->p_osptr = p->p_osptr;
33712790Ssam 			if (q = p->p_osptr)
33812790Ssam 				q->p_ysptr = p->p_ysptr;
33912790Ssam 			if ((q = p->p_pptr)->p_cptr == p)
34012790Ssam 				q->p_cptr = p->p_osptr;
34112790Ssam 			p->p_pptr = 0;
34212790Ssam 			p->p_ysptr = 0;
34312790Ssam 			p->p_osptr = 0;
34412790Ssam 			p->p_cptr = 0;
34512790Ssam 			p->p_sig = 0;
34612882Ssam 			p->p_sigcatch = 0;
34712882Ssam 			p->p_sigignore = 0;
34812882Ssam 			p->p_sigmask = 0;
34937328Skarels 			/*p->p_pgrp = 0;*/
35012790Ssam 			p->p_flag = 0;
35112790Ssam 			p->p_wchan = 0;
352*44404Skarels 			return (0);
35312790Ssam 		}
35437328Skarels 		if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 &&
35537328Skarels 		    (p->p_flag & STRC || uap->options & WUNTRACED)) {
35612790Ssam 			p->p_flag |= SWTED;
35742927Smckusick 			retval[0] = p->p_pid;
35837328Skarels #ifdef COMPAT_43
35939737Smckusick 			if (uap->compat) {
36043895Skarels 				retval[1] = W_STOPCODE(p->p_xstat);
36139737Smckusick 				error = 0;
36239737Smckusick 			} else
36337328Skarels #endif
36437328Skarels 			if (uap->status) {
36543895Skarels 				status = W_STOPCODE(p->p_xstat);
36639410Skarels 				error = copyout((caddr_t)&status,
36737328Skarels 				    (caddr_t)uap->status, sizeof(status));
36839410Skarels 			} else
36939410Skarels 				error = 0;
370*44404Skarels 			return (error);
37112790Ssam 		}
37212790Ssam 	}
37339410Skarels 	if (f == 0)
374*44404Skarels 		return (ECHILD);
37537328Skarels 	if (uap->options & WNOHANG) {
37642927Smckusick 		retval[0] = 0;
377*44404Skarels 		return (0);
37812790Ssam 	}
37942927Smckusick 	if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
380*44404Skarels 		return (error);
38112790Ssam 	goto loop;
38212790Ssam }
383