xref: /csrg-svn/sys/kern/kern_exit.c (revision 45673)
123369Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423369Smckusick  *
544433Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*45673Skarels  *	@(#)kern_exit.c	7.28 (Berkeley) 12/01/90
823369Smckusick  */
912790Ssam 
1017090Sbloom #include "param.h"
1117090Sbloom #include "systm.h"
1217090Sbloom #include "map.h"
1342927Smckusick #include "ioctl.h"
1442927Smckusick #include "tty.h"
1544404Skarels #include "user.h"
1617090Sbloom #include "kernel.h"
1717090Sbloom #include "proc.h"
1817090Sbloom #include "buf.h"
1917090Sbloom #include "wait.h"
2017090Sbloom #include "vm.h"
2117090Sbloom #include "file.h"
2237728Smckusick #include "vnode.h"
2318638Ssam #include "syslog.h"
2432018Smckusick #include "malloc.h"
2512790Ssam 
2637520Smckusick #include "machine/reg.h"
2737328Skarels #ifdef COMPAT_43
2837520Smckusick #include "machine/psl.h"
2937328Skarels #endif
3037328Skarels 
3112790Ssam /*
3212790Ssam  * Exit system call: pass back caller's arg
3312790Ssam  */
3442927Smckusick /* ARGSUSED */
3542927Smckusick rexit(p, uap, retval)
3642927Smckusick 	struct proc *p;
3742927Smckusick 	struct args {
3812790Ssam 		int	rval;
3912790Ssam 	} *uap;
4042927Smckusick 	int *retval;
4142927Smckusick {
4212790Ssam 
4345157Skarels 	exit(p, W_EXITCODE(uap->rval, 0));
4445157Skarels 	/* NOTREACHED */
4512790Ssam }
4612790Ssam 
4712790Ssam /*
4812790Ssam  * Release resources.
4912790Ssam  * Save u. area for parent to look at.
5012790Ssam  * Enter zombie state.
5112790Ssam  * Wake up parent and init processes,
5212790Ssam  * and dispose of children.
5312790Ssam  */
5442927Smckusick exit(p, rv)
5542927Smckusick 	struct proc *p;
5638930Skarels 	int rv;
5712790Ssam {
5812790Ssam 	register int i;
5942927Smckusick 	register struct proc *q, *nq;
6040670Skarels 	register struct proc **pp;
6112790Ssam 
6212790Ssam #ifdef PGINPROF
6312790Ssam 	vmsizmon();
6412790Ssam #endif
6532018Smckusick 	MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
6632018Smckusick 		M_ZOMBIE, M_WAITOK);
6712790Ssam 	p->p_flag &= ~(STRC|SULOCK);
6812790Ssam 	p->p_flag |= SWEXIT;
6912882Ssam 	p->p_sigignore = ~0;
7039410Skarels 	p->p_sig = 0;
7112790Ssam 	p->p_cpticks = 0;
7212790Ssam 	p->p_pctcpu = 0;
7312882Ssam 	for (i = 0; i < NSIG; i++)
7412790Ssam 		u.u_signal[i] = SIG_IGN;
7512790Ssam 	untimeout(realitexpire, (caddr_t)p);
7612790Ssam 	/*
7712790Ssam 	 * Release virtual memory.  If we resulted from
7812790Ssam 	 * a vfork(), instead give the resources back to
7912790Ssam 	 * the parent.
8012790Ssam 	 */
8141569Smckusick 	if ((p->p_flag & SVFORK) == 0) {
8241569Smckusick #ifdef MAPMEM
8341569Smckusick 		if (u.u_mmap)
8442927Smckusick 			(void) mmexit(p);
8541569Smckusick #endif
8612790Ssam 		vrelvm();
8741569Smckusick 	} else {
8812790Ssam 		p->p_flag &= ~SVFORK;
8912790Ssam 		wakeup((caddr_t)p);
9012790Ssam 		while ((p->p_flag & SVFDONE) == 0)
9112790Ssam 			sleep((caddr_t)p, PZERO - 1);
9212790Ssam 		p->p_flag &= ~SVFDONE;
9312790Ssam 	}
9421105Skarels 	for (i = 0; i <= u.u_lastfile; i++) {
9512790Ssam 		struct file *f;
9612790Ssam 
9712790Ssam 		f = u.u_ofile[i];
9821105Skarels 		if (f) {
9921105Skarels 			u.u_ofile[i] = NULL;
10021105Skarels 			u.u_pofile[i] = 0;
10139351Smckusick 			(void) closef(f);
10221105Skarels 		}
10312790Ssam 	}
10437328Skarels 	if (SESS_LEADER(p)) {
10542897Smarc 		register struct session *sp = p->p_session;
10642897Smarc 
10742897Smarc 		if (sp->s_ttyvp) {
10840809Smarc 			/*
10942897Smarc 			 * Controlling process.
11042897Smarc 			 * Signal foreground pgrp and revoke access
11142897Smarc 			 * to controlling terminal.
11242897Smarc 			 */
11342897Smarc 			if (sp->s_ttyp->t_pgrp)
11442916Smarc 				pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
11542897Smarc 			vgoneall(sp->s_ttyvp);
11642897Smarc 			vrele(sp->s_ttyvp);
11742897Smarc 			sp->s_ttyvp = NULL;
11842897Smarc 			/*
11940809Smarc 			 * s_ttyp is not zero'd; we use this to indicate
12040809Smarc 			 * that the session once had a controlling terminal.
12142897Smarc 			 * (for logging and informational purposes)
12240809Smarc 			 */
12337328Skarels 		}
12442897Smarc 		sp->s_leader = 0;
12537328Skarels 	}
12637728Smckusick 	VOP_LOCK(u.u_cdir);
12737728Smckusick 	vput(u.u_cdir);
12812790Ssam 	if (u.u_rdir) {
12937728Smckusick 		VOP_LOCK(u.u_rdir);
13037728Smckusick 		vput(u.u_rdir);
13112790Ssam 	}
13212790Ssam 	u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
13343380Smckusick 	(void) acct(p);
13437728Smckusick 	crfree(u.u_cred);
13537328Skarels #ifdef KTRACE
13637328Skarels 	/*
13737328Skarels 	 * release trace file
13837328Skarels 	 */
13937328Skarels 	if (p->p_tracep)
14037728Smckusick 		vrele(p->p_tracep);
14137328Skarels #endif
14226823Skarels 	/*
14326823Skarels 	 * Freeing the user structure and kernel stack
14426823Skarels 	 * for the current process: have to run a bit longer
14526823Skarels 	 * using the pages which are about to be freed...
14626823Skarels 	 * vrelu will block memory allocation by raising ipl.
14726823Skarels 	 */
14842927Smckusick 	vrelu(p, 0);
14942927Smckusick 	vrelpt(p);
15016527Skarels 	if (*p->p_prev = p->p_nxt)		/* off allproc queue */
15116527Skarels 		p->p_nxt->p_prev = p->p_prev;
15216527Skarels 	if (p->p_nxt = zombproc)		/* onto zombproc */
15316527Skarels 		p->p_nxt->p_prev = &p->p_nxt;
15416527Skarels 	p->p_prev = &zombproc;
15516527Skarels 	zombproc = p;
15612790Ssam 	multprog--;
15712790Ssam 	p->p_stat = SZOMB;
15812790Ssam 	noproc = 1;
15940670Skarels 	for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
16040670Skarels 		if (*pp == p) {
16140670Skarels 			*pp = p->p_hash;
16240670Skarels 			goto done;
16340670Skarels 		}
16440670Skarels 	panic("exit");
16540670Skarels done:
16621105Skarels 	if (p->p_pid == 1) {
16721105Skarels 		if (p->p_dsize == 0) {
16839410Skarels 			printf("Can't exec init (errno %d)\n", WEXITSTATUS(rv));
16921105Skarels 			for (;;)
17021105Skarels 				;
17121105Skarels 		} else
17221105Skarels 			panic("init died");
17321105Skarels 	}
17412790Ssam 	p->p_xstat = rv;
17521105Skarels 	*p->p_ru = u.u_ru;
17640809Smarc 	i = splclock();
17740809Smarc 	p->p_ru->ru_stime = p->p_stime;
17840809Smarc 	p->p_ru->ru_utime = p->p_utime;
17940809Smarc 	splx(i);
18021105Skarels 	ruadd(p->p_ru, &u.u_cru);
18116527Skarels 	if (p->p_cptr)		/* only need this if any child is S_ZOMB */
18216527Skarels 		wakeup((caddr_t)&proc[1]);
183*45673Skarels 	fixjobc(p, p->p_pgrp, 0);
18416527Skarels 	for (q = p->p_cptr; q != NULL; q = nq) {
18516527Skarels 		nq = q->p_osptr;
18616527Skarels 		if (nq != NULL)
18716527Skarels 			nq->p_ysptr = NULL;
18816527Skarels 		if (proc[1].p_cptr)
18916527Skarels 			proc[1].p_cptr->p_ysptr = q;
19016527Skarels 		q->p_osptr = proc[1].p_cptr;
19116527Skarels 		q->p_ysptr = NULL;
19216527Skarels 		proc[1].p_cptr = q;
19312790Ssam 
19416527Skarels 		q->p_pptr = &proc[1];
19516527Skarels 		q->p_ppid = 1;
19616527Skarels 		/*
19716527Skarels 		 * Traced processes are killed
19816527Skarels 		 * since their existence means someone is screwing up.
19916527Skarels 		 */
20016527Skarels 		if (q->p_flag&STRC) {
20116527Skarels 			q->p_flag &= ~STRC;
20216527Skarels 			psignal(q, SIGKILL);
20312790Ssam 		}
20416527Skarels 	}
20517540Skarels 	p->p_cptr = NULL;
20612790Ssam 	psignal(p->p_pptr, SIGCHLD);
20712790Ssam 	wakeup((caddr_t)p->p_pptr);
20829946Skarels #if defined(tahoe)
20929946Skarels 	dkeyrelease(p->p_dkey), p->p_dkey = 0;
21029946Skarels 	ckeyrelease(p->p_ckey), p->p_ckey = 0;
21129946Skarels 	u.u_pcb.pcb_savacc.faddr = (float *)NULL;
21229946Skarels #endif
21312790Ssam 	swtch();
21412790Ssam }
21512790Ssam 
21637328Skarels #ifdef COMPAT_43
21742927Smckusick owait(p, uap, retval)
21842927Smckusick 	struct proc *p;
21942927Smckusick 	register struct args {
22037328Skarels 		int	pid;
22139410Skarels 		int	*status;
22237328Skarels 		int	options;
22337328Skarels 		struct	rusage *rusage;
22439410Skarels 		int	compat;
22542927Smckusick 	} *uap;
22642927Smckusick 	int *retval;
22742927Smckusick {
22812790Ssam 
22912790Ssam 	if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) {
23038930Skarels 		uap->options = 0;
23137328Skarels 		uap->rusage = 0;
23237328Skarels 	} else {
23338930Skarels 		uap->options = u.u_ar0[R0];
23437328Skarels 		uap->rusage = (struct rusage *)u.u_ar0[R1];
23512790Ssam 	}
23637328Skarels 	uap->pid = WAIT_ANY;
23737328Skarels 	uap->status = 0;
23839410Skarels 	uap->compat = 1;
23944404Skarels 	return (wait1(p, uap, retval));
24012790Ssam }
24112790Ssam 
24242927Smckusick wait4(p, uap, retval)
24342927Smckusick 	struct proc *p;
24442927Smckusick 	struct args {
24539410Skarels 		int	pid;
24639410Skarels 		int	*status;
24739410Skarels 		int	options;
24839410Skarels 		struct	rusage *rusage;
24939410Skarels 		int	compat;
25042927Smckusick 	} *uap;
25142927Smckusick 	int *retval;
25242927Smckusick {
25339410Skarels 
25439410Skarels 	uap->compat = 0;
25544404Skarels 	return (wait1(p, uap, retval));
25637328Skarels }
25739410Skarels #else
25839410Skarels #define	wait1	wait4
25937328Skarels #endif
26037328Skarels 
26112790Ssam /*
26212790Ssam  * Wait system call.
26312790Ssam  * Search for a terminated (zombie) child,
26412790Ssam  * finally lay it to rest, and collect its status.
26512790Ssam  * Look also for stopped (traced) children,
26612790Ssam  * and pass back status from them.
26712790Ssam  */
26842927Smckusick wait1(q, uap, retval)
26942927Smckusick 	register struct proc *q;
27042927Smckusick 	register struct args {
27137328Skarels 		int	pid;
27239410Skarels 		int	*status;
27337328Skarels 		int	options;
27437328Skarels 		struct	rusage *rusage;
27539410Skarels #ifdef COMPAT_43
27639410Skarels 		int compat;
27739410Skarels #endif
27842927Smckusick 	} *uap;
27942927Smckusick 	int retval[];
28042927Smckusick {
28142927Smckusick 	register int f;
28242927Smckusick 	register struct proc *p;
28339410Skarels 	int status, error;
28412790Ssam 
28537328Skarels 	if (uap->pid == 0)
28637328Skarels 		uap->pid = -q->p_pgid;
28738930Skarels #ifdef notyet
28839410Skarels 	if (uap->options &~ (WUNTRACED|WNOHANG))
28944404Skarels 		return (EINVAL);
29038930Skarels #endif
29112790Ssam loop:
29238930Skarels 	f = 0;
29316527Skarels 	for (p = q->p_cptr; p; p = p->p_osptr) {
29437328Skarels 		if (uap->pid != WAIT_ANY &&
29537328Skarels 		    p->p_pid != uap->pid && p->p_pgid != -uap->pid)
29637328Skarels 			continue;
29712790Ssam 		f++;
29812790Ssam 		if (p->p_stat == SZOMB) {
29942927Smckusick 			retval[0] = p->p_pid;
30037328Skarels #ifdef COMPAT_43
30139410Skarels 			if (uap->compat)
30242927Smckusick 				retval[1] = p->p_xstat;
30337328Skarels 			else
30437328Skarels #endif
30537328Skarels 			if (uap->status) {
30639410Skarels 				status = p->p_xstat;	/* convert to int */
30739410Skarels 				if (error = copyout((caddr_t)&status,
30837328Skarels 				    (caddr_t)uap->status, sizeof(status)))
30944404Skarels 					return (error);
31037328Skarels 			}
31139410Skarels 			if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
31239410Skarels 			    (caddr_t)uap->rusage, sizeof (struct rusage))))
31344404Skarels 				return (error);
31439410Skarels 			pgrm(p);			/* off pgrp */
31512790Ssam 			p->p_xstat = 0;
31637328Skarels 			ruadd(&u.u_cru, p->p_ru);
31737328Skarels 			FREE(p->p_ru, M_ZOMBIE);
31837328Skarels 			p->p_ru = 0;
31912790Ssam 			p->p_stat = NULL;
32012790Ssam 			p->p_pid = 0;
32112790Ssam 			p->p_ppid = 0;
32216527Skarels 			if (*p->p_prev = p->p_nxt)	/* off zombproc */
32316527Skarels 				p->p_nxt->p_prev = p->p_prev;
32416527Skarels 			p->p_nxt = freeproc;		/* onto freeproc */
32516527Skarels 			freeproc = p;
32612790Ssam 			if (q = p->p_ysptr)
32712790Ssam 				q->p_osptr = p->p_osptr;
32812790Ssam 			if (q = p->p_osptr)
32912790Ssam 				q->p_ysptr = p->p_ysptr;
33012790Ssam 			if ((q = p->p_pptr)->p_cptr == p)
33112790Ssam 				q->p_cptr = p->p_osptr;
33212790Ssam 			p->p_pptr = 0;
33312790Ssam 			p->p_ysptr = 0;
33412790Ssam 			p->p_osptr = 0;
33512790Ssam 			p->p_cptr = 0;
33612790Ssam 			p->p_sig = 0;
33712882Ssam 			p->p_sigcatch = 0;
33812882Ssam 			p->p_sigignore = 0;
33912882Ssam 			p->p_sigmask = 0;
34037328Skarels 			/*p->p_pgrp = 0;*/
34112790Ssam 			p->p_flag = 0;
34212790Ssam 			p->p_wchan = 0;
34344404Skarels 			return (0);
34412790Ssam 		}
34537328Skarels 		if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 &&
34637328Skarels 		    (p->p_flag & STRC || uap->options & WUNTRACED)) {
34712790Ssam 			p->p_flag |= SWTED;
34842927Smckusick 			retval[0] = p->p_pid;
34937328Skarels #ifdef COMPAT_43
35039737Smckusick 			if (uap->compat) {
35143895Skarels 				retval[1] = W_STOPCODE(p->p_xstat);
35239737Smckusick 				error = 0;
35339737Smckusick 			} else
35437328Skarels #endif
35537328Skarels 			if (uap->status) {
35643895Skarels 				status = W_STOPCODE(p->p_xstat);
35739410Skarels 				error = copyout((caddr_t)&status,
35837328Skarels 				    (caddr_t)uap->status, sizeof(status));
35939410Skarels 			} else
36039410Skarels 				error = 0;
36144404Skarels 			return (error);
36212790Ssam 		}
36312790Ssam 	}
36439410Skarels 	if (f == 0)
36544404Skarels 		return (ECHILD);
36637328Skarels 	if (uap->options & WNOHANG) {
36742927Smckusick 		retval[0] = 0;
36844404Skarels 		return (0);
36912790Ssam 	}
37042927Smckusick 	if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
37144404Skarels 		return (error);
37212790Ssam 	goto loop;
37312790Ssam }
374