xref: /csrg-svn/sys/kern/kern_exit.c (revision 44433)
123369Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423369Smckusick  *
5*44433Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*44433Sbostic  *	@(#)kern_exit.c	7.26 (Berkeley) 06/28/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 
4344404Skarels 	return (exit(p, W_EXITCODE(uap->rval, 0)));
4412790Ssam }
4512790Ssam 
4612790Ssam /*
4712790Ssam  * Release resources.
4812790Ssam  * Save u. area for parent to look at.
4912790Ssam  * Enter zombie state.
5012790Ssam  * Wake up parent and init processes,
5112790Ssam  * and dispose of children.
5212790Ssam  */
5342927Smckusick exit(p, rv)
5442927Smckusick 	struct proc *p;
5538930Skarels 	int rv;
5612790Ssam {
5712790Ssam 	register int i;
5842927Smckusick 	register struct proc *q, *nq;
5940670Skarels 	register struct proc **pp;
6012790Ssam 
6112790Ssam #ifdef PGINPROF
6212790Ssam 	vmsizmon();
6312790Ssam #endif
6432018Smckusick 	MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
6532018Smckusick 		M_ZOMBIE, M_WAITOK);
6612790Ssam 	p->p_flag &= ~(STRC|SULOCK);
6712790Ssam 	p->p_flag |= SWEXIT;
6812882Ssam 	p->p_sigignore = ~0;
6939410Skarels 	p->p_sig = 0;
7012790Ssam 	p->p_cpticks = 0;
7112790Ssam 	p->p_pctcpu = 0;
7212882Ssam 	for (i = 0; i < NSIG; i++)
7312790Ssam 		u.u_signal[i] = SIG_IGN;
7412790Ssam 	untimeout(realitexpire, (caddr_t)p);
7512790Ssam 	/*
7612790Ssam 	 * Release virtual memory.  If we resulted from
7712790Ssam 	 * a vfork(), instead give the resources back to
7812790Ssam 	 * the parent.
7912790Ssam 	 */
8041569Smckusick 	if ((p->p_flag & SVFORK) == 0) {
8141569Smckusick #ifdef MAPMEM
8241569Smckusick 		if (u.u_mmap)
8342927Smckusick 			(void) mmexit(p);
8441569Smckusick #endif
8512790Ssam 		vrelvm();
8641569Smckusick 	} else {
8712790Ssam 		p->p_flag &= ~SVFORK;
8812790Ssam 		wakeup((caddr_t)p);
8912790Ssam 		while ((p->p_flag & SVFDONE) == 0)
9012790Ssam 			sleep((caddr_t)p, PZERO - 1);
9112790Ssam 		p->p_flag &= ~SVFDONE;
9212790Ssam 	}
9321105Skarels 	for (i = 0; i <= u.u_lastfile; i++) {
9412790Ssam 		struct file *f;
9512790Ssam 
9612790Ssam 		f = u.u_ofile[i];
9721105Skarels 		if (f) {
9821105Skarels 			u.u_ofile[i] = NULL;
9921105Skarels 			u.u_pofile[i] = 0;
10039351Smckusick 			(void) closef(f);
10121105Skarels 		}
10212790Ssam 	}
10337328Skarels 	if (SESS_LEADER(p)) {
10442897Smarc 		register struct session *sp = p->p_session;
10542897Smarc 
10642897Smarc 		if (sp->s_ttyvp) {
10740809Smarc 			/*
10842897Smarc 			 * Controlling process.
10942897Smarc 			 * Signal foreground pgrp and revoke access
11042897Smarc 			 * to controlling terminal.
11142897Smarc 			 */
11242897Smarc 			if (sp->s_ttyp->t_pgrp)
11342916Smarc 				pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
11442897Smarc 			vgoneall(sp->s_ttyvp);
11542897Smarc 			vrele(sp->s_ttyvp);
11642897Smarc 			sp->s_ttyvp = NULL;
11742897Smarc 			/*
11840809Smarc 			 * s_ttyp is not zero'd; we use this to indicate
11940809Smarc 			 * that the session once had a controlling terminal.
12042897Smarc 			 * (for logging and informational purposes)
12140809Smarc 			 */
12237328Skarels 		}
12342897Smarc 		sp->s_leader = 0;
12437328Skarels 	}
12537728Smckusick 	VOP_LOCK(u.u_cdir);
12637728Smckusick 	vput(u.u_cdir);
12712790Ssam 	if (u.u_rdir) {
12837728Smckusick 		VOP_LOCK(u.u_rdir);
12937728Smckusick 		vput(u.u_rdir);
13012790Ssam 	}
13112790Ssam 	u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
13243380Smckusick 	(void) acct(p);
13337728Smckusick 	crfree(u.u_cred);
13437328Skarels #ifdef KTRACE
13537328Skarels 	/*
13637328Skarels 	 * release trace file
13737328Skarels 	 */
13837328Skarels 	if (p->p_tracep)
13937728Smckusick 		vrele(p->p_tracep);
14037328Skarels #endif
14126823Skarels 	/*
14226823Skarels 	 * Freeing the user structure and kernel stack
14326823Skarels 	 * for the current process: have to run a bit longer
14426823Skarels 	 * using the pages which are about to be freed...
14526823Skarels 	 * vrelu will block memory allocation by raising ipl.
14626823Skarels 	 */
14742927Smckusick 	vrelu(p, 0);
14842927Smckusick 	vrelpt(p);
14916527Skarels 	if (*p->p_prev = p->p_nxt)		/* off allproc queue */
15016527Skarels 		p->p_nxt->p_prev = p->p_prev;
15116527Skarels 	if (p->p_nxt = zombproc)		/* onto zombproc */
15216527Skarels 		p->p_nxt->p_prev = &p->p_nxt;
15316527Skarels 	p->p_prev = &zombproc;
15416527Skarels 	zombproc = p;
15512790Ssam 	multprog--;
15612790Ssam 	p->p_stat = SZOMB;
15712790Ssam 	noproc = 1;
15840670Skarels 	for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
15940670Skarels 		if (*pp == p) {
16040670Skarels 			*pp = p->p_hash;
16140670Skarels 			goto done;
16240670Skarels 		}
16340670Skarels 	panic("exit");
16440670Skarels done:
16521105Skarels 	if (p->p_pid == 1) {
16621105Skarels 		if (p->p_dsize == 0) {
16739410Skarels 			printf("Can't exec init (errno %d)\n", WEXITSTATUS(rv));
16821105Skarels 			for (;;)
16921105Skarels 				;
17021105Skarels 		} else
17121105Skarels 			panic("init died");
17221105Skarels 	}
17312790Ssam 	p->p_xstat = rv;
17421105Skarels 	*p->p_ru = u.u_ru;
17540809Smarc 	i = splclock();
17640809Smarc 	p->p_ru->ru_stime = p->p_stime;
17740809Smarc 	p->p_ru->ru_utime = p->p_utime;
17840809Smarc 	splx(i);
17921105Skarels 	ruadd(p->p_ru, &u.u_cru);
18016527Skarels 	if (p->p_cptr)		/* only need this if any child is S_ZOMB */
18116527Skarels 		wakeup((caddr_t)&proc[1]);
18242897Smarc 	fixjobc(p, 0);
18316527Skarels 	for (q = p->p_cptr; q != NULL; q = nq) {
18416527Skarels 		nq = q->p_osptr;
18516527Skarels 		if (nq != NULL)
18616527Skarels 			nq->p_ysptr = NULL;
18716527Skarels 		if (proc[1].p_cptr)
18816527Skarels 			proc[1].p_cptr->p_ysptr = q;
18916527Skarels 		q->p_osptr = proc[1].p_cptr;
19016527Skarels 		q->p_ysptr = NULL;
19116527Skarels 		proc[1].p_cptr = q;
19212790Ssam 
19316527Skarels 		q->p_pptr = &proc[1];
19416527Skarels 		q->p_ppid = 1;
19516527Skarels 		/*
19616527Skarels 		 * Traced processes are killed
19716527Skarels 		 * since their existence means someone is screwing up.
19816527Skarels 		 */
19916527Skarels 		if (q->p_flag&STRC) {
20016527Skarels 			q->p_flag &= ~STRC;
20116527Skarels 			psignal(q, SIGKILL);
20212790Ssam 		}
20316527Skarels 	}
20417540Skarels 	p->p_cptr = NULL;
20512790Ssam 	psignal(p->p_pptr, SIGCHLD);
20612790Ssam 	wakeup((caddr_t)p->p_pptr);
20729946Skarels #if defined(tahoe)
20829946Skarels 	dkeyrelease(p->p_dkey), p->p_dkey = 0;
20929946Skarels 	ckeyrelease(p->p_ckey), p->p_ckey = 0;
21029946Skarels 	u.u_pcb.pcb_savacc.faddr = (float *)NULL;
21129946Skarels #endif
21212790Ssam 	swtch();
21312790Ssam }
21412790Ssam 
21537328Skarels #ifdef COMPAT_43
21642927Smckusick owait(p, uap, retval)
21742927Smckusick 	struct proc *p;
21842927Smckusick 	register struct args {
21937328Skarels 		int	pid;
22039410Skarels 		int	*status;
22137328Skarels 		int	options;
22237328Skarels 		struct	rusage *rusage;
22339410Skarels 		int	compat;
22442927Smckusick 	} *uap;
22542927Smckusick 	int *retval;
22642927Smckusick {
22712790Ssam 
22812790Ssam 	if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) {
22938930Skarels 		uap->options = 0;
23037328Skarels 		uap->rusage = 0;
23137328Skarels 	} else {
23238930Skarels 		uap->options = u.u_ar0[R0];
23337328Skarels 		uap->rusage = (struct rusage *)u.u_ar0[R1];
23412790Ssam 	}
23537328Skarels 	uap->pid = WAIT_ANY;
23637328Skarels 	uap->status = 0;
23739410Skarels 	uap->compat = 1;
23844404Skarels 	return (wait1(p, uap, retval));
23912790Ssam }
24012790Ssam 
24142927Smckusick wait4(p, uap, retval)
24242927Smckusick 	struct proc *p;
24342927Smckusick 	struct args {
24439410Skarels 		int	pid;
24539410Skarels 		int	*status;
24639410Skarels 		int	options;
24739410Skarels 		struct	rusage *rusage;
24839410Skarels 		int	compat;
24942927Smckusick 	} *uap;
25042927Smckusick 	int *retval;
25142927Smckusick {
25239410Skarels 
25339410Skarels 	uap->compat = 0;
25444404Skarels 	return (wait1(p, uap, retval));
25537328Skarels }
25639410Skarels #else
25739410Skarels #define	wait1	wait4
25837328Skarels #endif
25937328Skarels 
26012790Ssam /*
26112790Ssam  * Wait system call.
26212790Ssam  * Search for a terminated (zombie) child,
26312790Ssam  * finally lay it to rest, and collect its status.
26412790Ssam  * Look also for stopped (traced) children,
26512790Ssam  * and pass back status from them.
26612790Ssam  */
26742927Smckusick wait1(q, uap, retval)
26842927Smckusick 	register struct proc *q;
26942927Smckusick 	register struct args {
27037328Skarels 		int	pid;
27139410Skarels 		int	*status;
27237328Skarels 		int	options;
27337328Skarels 		struct	rusage *rusage;
27439410Skarels #ifdef COMPAT_43
27539410Skarels 		int compat;
27639410Skarels #endif
27742927Smckusick 	} *uap;
27842927Smckusick 	int retval[];
27942927Smckusick {
28042927Smckusick 	register int f;
28142927Smckusick 	register struct proc *p;
28239410Skarels 	int status, error;
28312790Ssam 
28437328Skarels 	if (uap->pid == 0)
28537328Skarels 		uap->pid = -q->p_pgid;
28638930Skarels #ifdef notyet
28739410Skarels 	if (uap->options &~ (WUNTRACED|WNOHANG))
28844404Skarels 		return (EINVAL);
28938930Skarels #endif
29012790Ssam loop:
29138930Skarels 	f = 0;
29216527Skarels 	for (p = q->p_cptr; p; p = p->p_osptr) {
29337328Skarels 		if (uap->pid != WAIT_ANY &&
29437328Skarels 		    p->p_pid != uap->pid && p->p_pgid != -uap->pid)
29537328Skarels 			continue;
29612790Ssam 		f++;
29712790Ssam 		if (p->p_stat == SZOMB) {
29842927Smckusick 			retval[0] = p->p_pid;
29937328Skarels #ifdef COMPAT_43
30039410Skarels 			if (uap->compat)
30142927Smckusick 				retval[1] = p->p_xstat;
30237328Skarels 			else
30337328Skarels #endif
30437328Skarels 			if (uap->status) {
30539410Skarels 				status = p->p_xstat;	/* convert to int */
30639410Skarels 				if (error = copyout((caddr_t)&status,
30737328Skarels 				    (caddr_t)uap->status, sizeof(status)))
30844404Skarels 					return (error);
30937328Skarels 			}
31039410Skarels 			if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
31139410Skarels 			    (caddr_t)uap->rusage, sizeof (struct rusage))))
31244404Skarels 				return (error);
31339410Skarels 			pgrm(p);			/* off pgrp */
31412790Ssam 			p->p_xstat = 0;
31537328Skarels 			ruadd(&u.u_cru, p->p_ru);
31637328Skarels 			FREE(p->p_ru, M_ZOMBIE);
31737328Skarels 			p->p_ru = 0;
31812790Ssam 			p->p_stat = NULL;
31912790Ssam 			p->p_pid = 0;
32012790Ssam 			p->p_ppid = 0;
32116527Skarels 			if (*p->p_prev = p->p_nxt)	/* off zombproc */
32216527Skarels 				p->p_nxt->p_prev = p->p_prev;
32316527Skarels 			p->p_nxt = freeproc;		/* onto freeproc */
32416527Skarels 			freeproc = p;
32512790Ssam 			if (q = p->p_ysptr)
32612790Ssam 				q->p_osptr = p->p_osptr;
32712790Ssam 			if (q = p->p_osptr)
32812790Ssam 				q->p_ysptr = p->p_ysptr;
32912790Ssam 			if ((q = p->p_pptr)->p_cptr == p)
33012790Ssam 				q->p_cptr = p->p_osptr;
33112790Ssam 			p->p_pptr = 0;
33212790Ssam 			p->p_ysptr = 0;
33312790Ssam 			p->p_osptr = 0;
33412790Ssam 			p->p_cptr = 0;
33512790Ssam 			p->p_sig = 0;
33612882Ssam 			p->p_sigcatch = 0;
33712882Ssam 			p->p_sigignore = 0;
33812882Ssam 			p->p_sigmask = 0;
33937328Skarels 			/*p->p_pgrp = 0;*/
34012790Ssam 			p->p_flag = 0;
34112790Ssam 			p->p_wchan = 0;
34244404Skarels 			return (0);
34312790Ssam 		}
34437328Skarels 		if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 &&
34537328Skarels 		    (p->p_flag & STRC || uap->options & WUNTRACED)) {
34612790Ssam 			p->p_flag |= SWTED;
34742927Smckusick 			retval[0] = p->p_pid;
34837328Skarels #ifdef COMPAT_43
34939737Smckusick 			if (uap->compat) {
35043895Skarels 				retval[1] = W_STOPCODE(p->p_xstat);
35139737Smckusick 				error = 0;
35239737Smckusick 			} else
35337328Skarels #endif
35437328Skarels 			if (uap->status) {
35543895Skarels 				status = W_STOPCODE(p->p_xstat);
35639410Skarels 				error = copyout((caddr_t)&status,
35737328Skarels 				    (caddr_t)uap->status, sizeof(status));
35839410Skarels 			} else
35939410Skarels 				error = 0;
36044404Skarels 			return (error);
36112790Ssam 		}
36212790Ssam 	}
36339410Skarels 	if (f == 0)
36444404Skarels 		return (ECHILD);
36537328Skarels 	if (uap->options & WNOHANG) {
36642927Smckusick 		retval[0] = 0;
36744404Skarels 		return (0);
36812790Ssam 	}
36942927Smckusick 	if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
37044404Skarels 		return (error);
37112790Ssam 	goto loop;
37212790Ssam }
373