123369Smckusick /* 247540Skarels * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 337728Smckusick * All rights reserved. 423369Smckusick * 544433Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*49690Swilliam * @(#)kern_exit.c 7.34 (Berkeley) 05/12/91 823369Smckusick */ 912790Ssam 1017090Sbloom #include "param.h" 1117090Sbloom #include "systm.h" 1217090Sbloom #include "map.h" 1342927Smckusick #include "ioctl.h" 1442927Smckusick #include "tty.h" 1547540Skarels #include "time.h" 1647540Skarels #include "resource.h" 1717090Sbloom #include "kernel.h" 1817090Sbloom #include "proc.h" 1917090Sbloom #include "buf.h" 2017090Sbloom #include "wait.h" 2117090Sbloom #include "file.h" 2237728Smckusick #include "vnode.h" 2318638Ssam #include "syslog.h" 2432018Smckusick #include "malloc.h" 2548403Skarels #include "resourcevar.h" 2612790Ssam 2749087Skarels #include "machine/cpu.h" 2847540Skarels #ifdef COMPAT_43 2937520Smckusick #include "machine/reg.h" 3037520Smckusick #include "machine/psl.h" 3137328Skarels #endif 3237328Skarels 3348403Skarels #include "vm/vm.h" 3447540Skarels #include "vm/vm_kern.h" 3545739Smckusick 3612790Ssam /* 3712790Ssam * Exit system call: pass back caller's arg 3812790Ssam */ 3942927Smckusick /* ARGSUSED */ 4042927Smckusick rexit(p, uap, retval) 4142927Smckusick struct proc *p; 4242927Smckusick struct args { 4312790Ssam int rval; 4412790Ssam } *uap; 4542927Smckusick int *retval; 4642927Smckusick { 4712790Ssam 4845157Skarels exit(p, W_EXITCODE(uap->rval, 0)); 4945157Skarels /* NOTREACHED */ 5012790Ssam } 5112790Ssam 5212790Ssam /* 5347540Skarels * Exit: deallocate address space and other resources, 5447540Skarels * change proc state to zombie, and unlink proc from allproc 5547540Skarels * and parent's lists. Save exit status and rusage for wait(). 5647540Skarels * Check for child processes and orphan them. 5712790Ssam */ 5842927Smckusick exit(p, rv) 5947540Skarels register struct proc *p; 6038930Skarels int rv; 6112790Ssam { 6242927Smckusick register struct proc *q, *nq; 6340670Skarels register struct proc **pp; 6447540Skarels int s; 6512790Ssam 6612790Ssam #ifdef PGINPROF 6712790Ssam vmsizmon(); 6812790Ssam #endif 6932018Smckusick MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), 7032018Smckusick M_ZOMBIE, M_WAITOK); 7147540Skarels /* 7247540Skarels * If parent is waiting for us to exit or exec, 7347540Skarels * SPPWAIT is set; we will wakeup the parent below. 7447540Skarels */ 7548403Skarels p->p_flag &= ~(STRC|SPPWAIT); 7612790Ssam p->p_flag |= SWEXIT; 7712882Ssam p->p_sigignore = ~0; 7839410Skarels p->p_sig = 0; 7912790Ssam untimeout(realitexpire, (caddr_t)p); 8047540Skarels 8147540Skarels /* 8247540Skarels * Close open files and release open-file table. 8347540Skarels * This may block! 8447540Skarels */ 8547540Skarels fdfree(p); 8645739Smckusick #ifdef SYSVSHM 8747540Skarels if (p->p_vmspace->vm_shm) 8845739Smckusick shmexit(p); 8945739Smckusick #endif 9047540Skarels 9147540Skarels if (p->p_pid == 1) 9247540Skarels panic("init died"); 9337328Skarels if (SESS_LEADER(p)) { 9442897Smarc register struct session *sp = p->p_session; 9542897Smarc 9642897Smarc if (sp->s_ttyvp) { 9740809Smarc /* 9842897Smarc * Controlling process. 9949087Skarels * Signal foreground pgrp, 10049087Skarels * drain controlling terminal 10149087Skarels * and revoke access to controlling terminal. 10242897Smarc */ 10349087Skarels if (sp->s_ttyp->t_session == sp) { 10449087Skarels if (sp->s_ttyp->t_pgrp) 10549087Skarels pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 10649087Skarels (void) ttywait(sp->s_ttyp); 10749087Skarels vgoneall(sp->s_ttyvp); 10849087Skarels } 10942897Smarc vrele(sp->s_ttyvp); 11042897Smarc sp->s_ttyvp = NULL; 11142897Smarc /* 11240809Smarc * s_ttyp is not zero'd; we use this to indicate 11340809Smarc * that the session once had a controlling terminal. 11442897Smarc * (for logging and informational purposes) 11540809Smarc */ 11637328Skarels } 11749087Skarels sp->s_leader = NULL; 11837328Skarels } 11947540Skarels fixjobc(p, p->p_pgrp, 0); 12047540Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 12143380Smckusick (void) acct(p); 12247540Skarels if (--p->p_limit->p_refcnt == 0) 12347540Skarels FREE(p->p_limit, M_SUBPROC); 12447540Skarels if (--p->p_cred->p_refcnt == 0) { 12547540Skarels crfree(p->p_cred->pc_ucred); 12647540Skarels FREE(p->p_cred, M_SUBPROC); 12747540Skarels } 12837328Skarels #ifdef KTRACE 12937328Skarels /* 13037328Skarels * release trace file 13137328Skarels */ 13237328Skarels if (p->p_tracep) 13337728Smckusick vrele(p->p_tracep); 13437328Skarels #endif 13547540Skarels 13647540Skarels /* 13747540Skarels * Remove proc from allproc queue and pidhash chain. 13847540Skarels * Place onto zombproc. Unlink from parent's child list. 13947540Skarels */ 14047540Skarels if (*p->p_prev = p->p_nxt) 14116527Skarels p->p_nxt->p_prev = p->p_prev; 14247540Skarels if (p->p_nxt = zombproc) 14316527Skarels p->p_nxt->p_prev = &p->p_nxt; 14416527Skarels p->p_prev = &zombproc; 14516527Skarels zombproc = p; 14612790Ssam p->p_stat = SZOMB; 14748403Skarels curproc = NULL; 14840670Skarels for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash) 14940670Skarels if (*pp == p) { 15040670Skarels *pp = p->p_hash; 15140670Skarels goto done; 15240670Skarels } 15340670Skarels panic("exit"); 15440670Skarels done: 15547540Skarels 15616527Skarels if (p->p_cptr) /* only need this if any child is S_ZOMB */ 15747540Skarels wakeup((caddr_t) initproc); 15816527Skarels for (q = p->p_cptr; q != NULL; q = nq) { 15916527Skarels nq = q->p_osptr; 16016527Skarels if (nq != NULL) 16116527Skarels nq->p_ysptr = NULL; 16247540Skarels if (initproc->p_cptr) 16347540Skarels initproc->p_cptr->p_ysptr = q; 16447540Skarels q->p_osptr = initproc->p_cptr; 16516527Skarels q->p_ysptr = NULL; 16647540Skarels initproc->p_cptr = q; 16712790Ssam 16847540Skarels q->p_pptr = initproc; 16916527Skarels /* 17016527Skarels * Traced processes are killed 17116527Skarels * since their existence means someone is screwing up. 17216527Skarels */ 17316527Skarels if (q->p_flag&STRC) { 17416527Skarels q->p_flag &= ~STRC; 17516527Skarels psignal(q, SIGKILL); 17612790Ssam } 17716527Skarels } 17817540Skarels p->p_cptr = NULL; 17947540Skarels 18047540Skarels /* 18147540Skarels * Save exit status and final rusage info, 18247540Skarels * adding in child rusage info and self times. 18347540Skarels */ 18447540Skarels p->p_xstat = rv; 18547540Skarels *p->p_ru = p->p_stats->p_ru; 18647540Skarels p->p_ru->ru_stime = p->p_stime; 18747540Skarels p->p_ru->ru_utime = p->p_utime; 18847540Skarels ruadd(p->p_ru, &p->p_stats->p_cru); 18947540Skarels 19047540Skarels /* 19147540Skarels * Notify parent that we're gone. 19247540Skarels */ 19312790Ssam psignal(p->p_pptr, SIGCHLD); 19412790Ssam wakeup((caddr_t)p->p_pptr); 19529946Skarels #if defined(tahoe) 19649087Skarels /* move this to cpu_exit */ 19749087Skarels p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; 19829946Skarels #endif 19947540Skarels /* 20049087Skarels * Finally, call machine-dependent code to release the remaining 20149087Skarels * resources including address space, the kernel stack and pcb. 20249087Skarels * The address space is released by "vmspace_free(p->p_vmspace)"; 20349087Skarels * This is machine-dependent, as we may have to change stacks 20449087Skarels * or ensure that the current one isn't reallocated before we 20549087Skarels * finish. cpu_exit will end with a call to swtch(), finishing 20649087Skarels * our execution (pun intended). 20747540Skarels */ 20849087Skarels cpu_exit(p); 20947540Skarels /* NOTREACHED */ 21012790Ssam } 21112790Ssam 21237328Skarels #ifdef COMPAT_43 21342927Smckusick owait(p, uap, retval) 21442927Smckusick struct proc *p; 21542927Smckusick register struct args { 21637328Skarels int pid; 21739410Skarels int *status; 21837328Skarels int options; 21937328Skarels struct rusage *rusage; 22039410Skarels int compat; 22142927Smckusick } *uap; 22242927Smckusick int *retval; 22342927Smckusick { 22412790Ssam 22547540Skarels if ((p->p_regs[PS] & PSL_ALLCC) != PSL_ALLCC) { 22638930Skarels uap->options = 0; 22737328Skarels uap->rusage = 0; 22837328Skarels } else { 22947540Skarels uap->options = p->p_regs[R0]; 23047540Skarels uap->rusage = (struct rusage *)p->p_regs[R1]; 23112790Ssam } 23237328Skarels uap->pid = WAIT_ANY; 23337328Skarels uap->status = 0; 23439410Skarels uap->compat = 1; 23544404Skarels return (wait1(p, uap, retval)); 23612790Ssam } 23712790Ssam 23842927Smckusick wait4(p, uap, retval) 23942927Smckusick struct proc *p; 24042927Smckusick struct args { 24139410Skarels int pid; 24239410Skarels int *status; 24339410Skarels int options; 24439410Skarels struct rusage *rusage; 24539410Skarels int compat; 24642927Smckusick } *uap; 24742927Smckusick int *retval; 24842927Smckusick { 24939410Skarels 25039410Skarels uap->compat = 0; 25144404Skarels return (wait1(p, uap, retval)); 25237328Skarels } 25339410Skarels #else 25439410Skarels #define wait1 wait4 25537328Skarels #endif 25637328Skarels 25712790Ssam /* 25847540Skarels * Wait: check child processes to see if any have exited, 25947540Skarels * stopped under trace, or (optionally) stopped by a signal. 26047540Skarels * Pass back status and deallocate exited child's proc structure. 26112790Ssam */ 26242927Smckusick wait1(q, uap, retval) 26342927Smckusick register struct proc *q; 26442927Smckusick register struct args { 26537328Skarels int pid; 26639410Skarels int *status; 26737328Skarels int options; 26837328Skarels struct rusage *rusage; 26939410Skarels #ifdef COMPAT_43 27039410Skarels int compat; 27139410Skarels #endif 27242927Smckusick } *uap; 27342927Smckusick int retval[]; 27442927Smckusick { 27547540Skarels register int nfound; 27642927Smckusick register struct proc *p; 27739410Skarels int status, error; 27812790Ssam 27937328Skarels if (uap->pid == 0) 28037328Skarels uap->pid = -q->p_pgid; 28138930Skarels #ifdef notyet 28239410Skarels if (uap->options &~ (WUNTRACED|WNOHANG)) 28344404Skarels return (EINVAL); 28438930Skarels #endif 28512790Ssam loop: 28647540Skarels nfound = 0; 28716527Skarels for (p = q->p_cptr; p; p = p->p_osptr) { 28837328Skarels if (uap->pid != WAIT_ANY && 28937328Skarels p->p_pid != uap->pid && p->p_pgid != -uap->pid) 29037328Skarels continue; 29147540Skarels nfound++; 29212790Ssam if (p->p_stat == SZOMB) { 29342927Smckusick retval[0] = p->p_pid; 29437328Skarels #ifdef COMPAT_43 29539410Skarels if (uap->compat) 29642927Smckusick retval[1] = p->p_xstat; 29737328Skarels else 29837328Skarels #endif 29937328Skarels if (uap->status) { 30039410Skarels status = p->p_xstat; /* convert to int */ 30139410Skarels if (error = copyout((caddr_t)&status, 30237328Skarels (caddr_t)uap->status, sizeof(status))) 30344404Skarels return (error); 30437328Skarels } 30539410Skarels if (uap->rusage && (error = copyout((caddr_t)p->p_ru, 30639410Skarels (caddr_t)uap->rusage, sizeof (struct rusage)))) 30744404Skarels return (error); 30812790Ssam p->p_xstat = 0; 30947540Skarels ruadd(&q->p_stats->p_cru, p->p_ru); 31037328Skarels FREE(p->p_ru, M_ZOMBIE); 31147540Skarels 31247540Skarels /* 31347540Skarels * Finally finished with old proc entry. 31447540Skarels * Unlink it from its process group and free it. 31547540Skarels */ 31647540Skarels leavepgrp(p); 31716527Skarels if (*p->p_prev = p->p_nxt) /* off zombproc */ 31816527Skarels p->p_nxt->p_prev = p->p_prev; 31912790Ssam if (q = p->p_ysptr) 32012790Ssam q->p_osptr = p->p_osptr; 32112790Ssam if (q = p->p_osptr) 32212790Ssam q->p_ysptr = p->p_ysptr; 32312790Ssam if ((q = p->p_pptr)->p_cptr == p) 32412790Ssam q->p_cptr = p->p_osptr; 325*49690Swilliam 326*49690Swilliam #ifdef i386 327*49690Swilliam cpu_wait(p); /* XXX */ 328*49690Swilliam #endif 329*49690Swilliam 33047540Skarels FREE(p, M_PROC); 33147540Skarels nprocs--; 33244404Skarels return (0); 33312790Ssam } 33437328Skarels if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 && 33537328Skarels (p->p_flag & STRC || uap->options & WUNTRACED)) { 33612790Ssam p->p_flag |= SWTED; 33742927Smckusick retval[0] = p->p_pid; 33837328Skarels #ifdef COMPAT_43 33939737Smckusick if (uap->compat) { 34043895Skarels retval[1] = W_STOPCODE(p->p_xstat); 34139737Smckusick error = 0; 34239737Smckusick } else 34337328Skarels #endif 34437328Skarels if (uap->status) { 34543895Skarels status = W_STOPCODE(p->p_xstat); 34639410Skarels error = copyout((caddr_t)&status, 34737328Skarels (caddr_t)uap->status, sizeof(status)); 34839410Skarels } else 34939410Skarels error = 0; 35044404Skarels return (error); 35112790Ssam } 35212790Ssam } 35347540Skarels if (nfound == 0) 35444404Skarels return (ECHILD); 35537328Skarels if (uap->options & WNOHANG) { 35642927Smckusick retval[0] = 0; 35744404Skarels return (0); 35812790Ssam } 35942927Smckusick if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) 36044404Skarels return (error); 36112790Ssam goto loop; 36212790Ssam } 363