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*54338Smckusick * @(#)kern_exit.c 7.45 (Berkeley) 06/23/92 823369Smckusick */ 912790Ssam 1017090Sbloom #include "param.h" 1117090Sbloom #include "systm.h" 1217090Sbloom #include "map.h" 1342927Smckusick #include "ioctl.h" 1452512Smckusick #include "proc.h" 1542927Smckusick #include "tty.h" 1647540Skarels #include "time.h" 1747540Skarels #include "resource.h" 1817090Sbloom #include "kernel.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" 26*54338Smckusick #include "ptrace.h" 2712790Ssam 2849087Skarels #include "machine/cpu.h" 2947540Skarels #ifdef COMPAT_43 3037520Smckusick #include "machine/reg.h" 3137520Smckusick #include "machine/psl.h" 3237328Skarels #endif 3337328Skarels 3448403Skarels #include "vm/vm.h" 3547540Skarels #include "vm/vm_kern.h" 3645739Smckusick 3712790Ssam /* 3812790Ssam * Exit system call: pass back caller's arg 3912790Ssam */ 4042927Smckusick /* ARGSUSED */ 4142927Smckusick rexit(p, uap, retval) 4242927Smckusick struct proc *p; 4342927Smckusick struct args { 4412790Ssam int rval; 4512790Ssam } *uap; 4642927Smckusick int *retval; 4742927Smckusick { 4812790Ssam 4945157Skarels exit(p, W_EXITCODE(uap->rval, 0)); 5045157Skarels /* NOTREACHED */ 5112790Ssam } 5212790Ssam 5312790Ssam /* 5447540Skarels * Exit: deallocate address space and other resources, 5547540Skarels * change proc state to zombie, and unlink proc from allproc 5647540Skarels * and parent's lists. Save exit status and rusage for wait(). 5747540Skarels * Check for child processes and orphan them. 5812790Ssam */ 5942927Smckusick exit(p, rv) 6047540Skarels register struct proc *p; 6138930Skarels int rv; 6212790Ssam { 6342927Smckusick register struct proc *q, *nq; 6440670Skarels register struct proc **pp; 6552491Smckusick register struct vmspace *vm; 6647540Skarels int s; 6712790Ssam 68*54338Smckusick if (p->p_pid == 1) 69*54338Smckusick panic("init died (signal %d, exit %d)", 70*54338Smckusick WTERMSIG(rv), WEXITSTATUS(rv)); 7112790Ssam #ifdef PGINPROF 7212790Ssam vmsizmon(); 7312790Ssam #endif 7454133Smckusick if (p->p_flag & SPROFIL) 7554133Smckusick stopprofclock(p); 7632018Smckusick MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), 7732018Smckusick M_ZOMBIE, M_WAITOK); 7847540Skarels /* 7947540Skarels * If parent is waiting for us to exit or exec, 8047540Skarels * SPPWAIT is set; we will wakeup the parent below. 8147540Skarels */ 8248403Skarels p->p_flag &= ~(STRC|SPPWAIT); 8312790Ssam p->p_flag |= SWEXIT; 8412882Ssam p->p_sigignore = ~0; 8539410Skarels p->p_sig = 0; 8612790Ssam untimeout(realitexpire, (caddr_t)p); 8747540Skarels 8847540Skarels /* 8947540Skarels * Close open files and release open-file table. 9047540Skarels * This may block! 9147540Skarels */ 9247540Skarels fdfree(p); 9350200Skarels 9450200Skarels /* The next two chunks should probably be moved to vmspace_exit. */ 9552491Smckusick vm = p->p_vmspace; 9645739Smckusick #ifdef SYSVSHM 9752491Smckusick if (vm->vm_shm) 9845739Smckusick shmexit(p); 9945739Smckusick #endif 10050200Skarels /* 10150200Skarels * Release user portion of address space. 10250200Skarels * This releases references to vnodes, 10350200Skarels * which could cause I/O if the file has been unlinked. 10450200Skarels * Need to do this early enough that we can still sleep. 10550200Skarels * Can't free the entire vmspace as the kernel stack 10650200Skarels * may be mapped within that space also. 10750200Skarels */ 10852491Smckusick if (vm->vm_refcnt == 1) 10952491Smckusick (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS, 11050200Skarels VM_MAXUSER_ADDRESS); 11147540Skarels 11237328Skarels if (SESS_LEADER(p)) { 11342897Smarc register struct session *sp = p->p_session; 11442897Smarc 11542897Smarc if (sp->s_ttyvp) { 11640809Smarc /* 11742897Smarc * Controlling process. 11849087Skarels * Signal foreground pgrp, 11949087Skarels * drain controlling terminal 12049087Skarels * and revoke access to controlling terminal. 12142897Smarc */ 12249087Skarels if (sp->s_ttyp->t_session == sp) { 12349087Skarels if (sp->s_ttyp->t_pgrp) 12449087Skarels pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 12549087Skarels (void) ttywait(sp->s_ttyp); 12649087Skarels vgoneall(sp->s_ttyvp); 12749087Skarels } 12842897Smarc vrele(sp->s_ttyvp); 12942897Smarc sp->s_ttyvp = NULL; 13042897Smarc /* 13140809Smarc * s_ttyp is not zero'd; we use this to indicate 13240809Smarc * that the session once had a controlling terminal. 13342897Smarc * (for logging and informational purposes) 13440809Smarc */ 13537328Skarels } 13649087Skarels sp->s_leader = NULL; 13737328Skarels } 13847540Skarels fixjobc(p, p->p_pgrp, 0); 13947540Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 14043380Smckusick (void) acct(p); 14137328Skarels #ifdef KTRACE 14237328Skarels /* 14337328Skarels * release trace file 14437328Skarels */ 14552202Smarc p->p_traceflag = 0; /* don't trace the vrele() */ 14637328Skarels if (p->p_tracep) 14737728Smckusick vrele(p->p_tracep); 14837328Skarels #endif 14951014Skarels /* 15047540Skarels * Remove proc from allproc queue and pidhash chain. 15147540Skarels * Place onto zombproc. Unlink from parent's child list. 15247540Skarels */ 15347540Skarels if (*p->p_prev = p->p_nxt) 15416527Skarels p->p_nxt->p_prev = p->p_prev; 15547540Skarels if (p->p_nxt = zombproc) 15616527Skarels p->p_nxt->p_prev = &p->p_nxt; 15716527Skarels p->p_prev = &zombproc; 15816527Skarels zombproc = p; 15912790Ssam p->p_stat = SZOMB; 16052484Smckusick 16140670Skarels for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash) 16240670Skarels if (*pp == p) { 16340670Skarels *pp = p->p_hash; 16440670Skarels goto done; 16540670Skarels } 16640670Skarels panic("exit"); 16740670Skarels done: 16847540Skarels 16916527Skarels if (p->p_cptr) /* only need this if any child is S_ZOMB */ 17047540Skarels wakeup((caddr_t) initproc); 17116527Skarels for (q = p->p_cptr; q != NULL; q = nq) { 17216527Skarels nq = q->p_osptr; 17316527Skarels if (nq != NULL) 17416527Skarels nq->p_ysptr = NULL; 17547540Skarels if (initproc->p_cptr) 17647540Skarels initproc->p_cptr->p_ysptr = q; 17747540Skarels q->p_osptr = initproc->p_cptr; 17816527Skarels q->p_ysptr = NULL; 17947540Skarels initproc->p_cptr = q; 18012790Ssam 18147540Skarels q->p_pptr = initproc; 18216527Skarels /* 18316527Skarels * Traced processes are killed 18416527Skarels * since their existence means someone is screwing up. 18516527Skarels */ 18616527Skarels if (q->p_flag&STRC) { 18716527Skarels q->p_flag &= ~STRC; 18816527Skarels psignal(q, SIGKILL); 18912790Ssam } 19016527Skarels } 19117540Skarels p->p_cptr = NULL; 19247540Skarels 19347540Skarels /* 19447540Skarels * Save exit status and final rusage info, 19547540Skarels * adding in child rusage info and self times. 19647540Skarels */ 19747540Skarels p->p_xstat = rv; 19847540Skarels *p->p_ru = p->p_stats->p_ru; 19947540Skarels p->p_ru->ru_stime = p->p_stime; 20047540Skarels p->p_ru->ru_utime = p->p_utime; 20147540Skarels ruadd(p->p_ru, &p->p_stats->p_cru); 20247540Skarels 20347540Skarels /* 20447540Skarels * Notify parent that we're gone. 20547540Skarels */ 20612790Ssam psignal(p->p_pptr, SIGCHLD); 20712790Ssam wakeup((caddr_t)p->p_pptr); 20829946Skarels #if defined(tahoe) 20949087Skarels /* move this to cpu_exit */ 21049087Skarels p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; 21129946Skarels #endif 21247540Skarels /* 21352484Smckusick * Clear curproc after we've done all operations 21452484Smckusick * that could block, and before tearing down the rest 21552484Smckusick * of the process state that might be used from clock, etc. 21652484Smckusick * Also, can't clear curproc while we're still runnable, 21752484Smckusick * as we're not on a run queue (we are current, just not 21852484Smckusick * a proper proc any longer!). 21952484Smckusick * 22052484Smckusick * Other substructures are freed from wait(). 22152484Smckusick */ 22252484Smckusick curproc = NULL; 22352484Smckusick if (--p->p_limit->p_refcnt == 0) 22452484Smckusick FREE(p->p_limit, M_SUBPROC); 22552484Smckusick 22652484Smckusick /* 22749087Skarels * Finally, call machine-dependent code to release the remaining 22849087Skarels * resources including address space, the kernel stack and pcb. 22949087Skarels * The address space is released by "vmspace_free(p->p_vmspace)"; 23049087Skarels * This is machine-dependent, as we may have to change stacks 23149087Skarels * or ensure that the current one isn't reallocated before we 23249087Skarels * finish. cpu_exit will end with a call to swtch(), finishing 23349087Skarels * our execution (pun intended). 23447540Skarels */ 23549087Skarels cpu_exit(p); 23647540Skarels /* NOTREACHED */ 23712790Ssam } 23812790Ssam 23937328Skarels #ifdef COMPAT_43 24042927Smckusick owait(p, uap, retval) 24142927Smckusick struct proc *p; 24242927Smckusick register struct args { 24337328Skarels int pid; 24439410Skarels int *status; 24537328Skarels int options; 24637328Skarels struct rusage *rusage; 24739410Skarels int compat; 24842927Smckusick } *uap; 24942927Smckusick int *retval; 25042927Smckusick { 25112790Ssam 25251015Sralph #ifdef PSL_ALLCC 25352480Smckusick if ((p->p_md.md_regs[PS] & PSL_ALLCC) != PSL_ALLCC) { 25438930Skarels uap->options = 0; 25537328Skarels uap->rusage = 0; 25637328Skarels } else { 25752480Smckusick uap->options = p->p_md.md_regs[R0]; 25852480Smckusick uap->rusage = (struct rusage *)p->p_md.md_regs[R1]; 25912790Ssam } 26051015Sralph #else 26151015Sralph uap->options = 0; 26251015Sralph uap->rusage = 0; 26351015Sralph #endif 26437328Skarels uap->pid = WAIT_ANY; 26537328Skarels uap->status = 0; 26639410Skarels uap->compat = 1; 26744404Skarels return (wait1(p, uap, retval)); 26812790Ssam } 26912790Ssam 27042927Smckusick wait4(p, uap, retval) 27142927Smckusick struct proc *p; 27242927Smckusick struct args { 27339410Skarels int pid; 27439410Skarels int *status; 27539410Skarels int options; 27639410Skarels struct rusage *rusage; 27739410Skarels int compat; 27842927Smckusick } *uap; 27942927Smckusick int *retval; 28042927Smckusick { 28139410Skarels 28239410Skarels uap->compat = 0; 28344404Skarels return (wait1(p, uap, retval)); 28437328Skarels } 28539410Skarels #else 28639410Skarels #define wait1 wait4 28737328Skarels #endif 28837328Skarels 28912790Ssam /* 29047540Skarels * Wait: check child processes to see if any have exited, 29147540Skarels * stopped under trace, or (optionally) stopped by a signal. 29247540Skarels * Pass back status and deallocate exited child's proc structure. 29312790Ssam */ 29442927Smckusick wait1(q, uap, retval) 29542927Smckusick register struct proc *q; 29642927Smckusick register struct args { 29737328Skarels int pid; 29839410Skarels int *status; 29937328Skarels int options; 30037328Skarels struct rusage *rusage; 30139410Skarels #ifdef COMPAT_43 30239410Skarels int compat; 30339410Skarels #endif 30442927Smckusick } *uap; 30542927Smckusick int retval[]; 30642927Smckusick { 30747540Skarels register int nfound; 308*54338Smckusick register struct proc *p, *t; 30939410Skarels int status, error; 31012790Ssam 31137328Skarels if (uap->pid == 0) 31237328Skarels uap->pid = -q->p_pgid; 31338930Skarels #ifdef notyet 31439410Skarels if (uap->options &~ (WUNTRACED|WNOHANG)) 31544404Skarels return (EINVAL); 31638930Skarels #endif 31712790Ssam loop: 31847540Skarels nfound = 0; 31916527Skarels for (p = q->p_cptr; p; p = p->p_osptr) { 32037328Skarels if (uap->pid != WAIT_ANY && 32137328Skarels p->p_pid != uap->pid && p->p_pgid != -uap->pid) 32237328Skarels continue; 32347540Skarels nfound++; 32412790Ssam if (p->p_stat == SZOMB) { 32542927Smckusick retval[0] = p->p_pid; 32637328Skarels #ifdef COMPAT_43 32739410Skarels if (uap->compat) 32842927Smckusick retval[1] = p->p_xstat; 32937328Skarels else 33037328Skarels #endif 33137328Skarels if (uap->status) { 33239410Skarels status = p->p_xstat; /* convert to int */ 33339410Skarels if (error = copyout((caddr_t)&status, 33437328Skarels (caddr_t)uap->status, sizeof(status))) 33544404Skarels return (error); 33637328Skarels } 33739410Skarels if (uap->rusage && (error = copyout((caddr_t)p->p_ru, 33839410Skarels (caddr_t)uap->rusage, sizeof (struct rusage)))) 33944404Skarels return (error); 340*54338Smckusick /* 341*54338Smckusick * If we got the child via a ptrace 'attach', 342*54338Smckusick * we need to give it back to the old parent. 343*54338Smckusick */ 344*54338Smckusick if (p->p_oppid && (t = pfind(p->p_oppid))) { 345*54338Smckusick p->p_oppid = 0; 346*54338Smckusick proc_reparent(p, t); 347*54338Smckusick psignal(t, SIGCHLD); 348*54338Smckusick wakeup((caddr_t)t); 349*54338Smckusick return (0); 350*54338Smckusick } 35112790Ssam p->p_xstat = 0; 35247540Skarels ruadd(&q->p_stats->p_cru, p->p_ru); 35337328Skarels FREE(p->p_ru, M_ZOMBIE); 35450200Skarels if (--p->p_cred->p_refcnt == 0) { 35550200Skarels crfree(p->p_cred->pc_ucred); 35650200Skarels FREE(p->p_cred, M_SUBPROC); 35750200Skarels } 35847540Skarels 35947540Skarels /* 36047540Skarels * Finally finished with old proc entry. 36147540Skarels * Unlink it from its process group and free it. 36247540Skarels */ 36347540Skarels leavepgrp(p); 36416527Skarels if (*p->p_prev = p->p_nxt) /* off zombproc */ 36516527Skarels p->p_nxt->p_prev = p->p_prev; 36612790Ssam if (q = p->p_ysptr) 36712790Ssam q->p_osptr = p->p_osptr; 36812790Ssam if (q = p->p_osptr) 36912790Ssam q->p_ysptr = p->p_ysptr; 37012790Ssam if ((q = p->p_pptr)->p_cptr == p) 37112790Ssam q->p_cptr = p->p_osptr; 37249690Swilliam 37350200Skarels /* 37450200Skarels * Give machine-dependent layer a chance 37550200Skarels * to free anything that cpu_exit couldn't 37650200Skarels * release while still running in process context. 37750200Skarels */ 37850200Skarels cpu_wait(p); 37947540Skarels FREE(p, M_PROC); 38047540Skarels nprocs--; 38144404Skarels return (0); 38212790Ssam } 38337328Skarels if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 && 38437328Skarels (p->p_flag & STRC || uap->options & WUNTRACED)) { 38512790Ssam p->p_flag |= SWTED; 38642927Smckusick retval[0] = p->p_pid; 38737328Skarels #ifdef COMPAT_43 38839737Smckusick if (uap->compat) { 38943895Skarels retval[1] = W_STOPCODE(p->p_xstat); 39039737Smckusick error = 0; 39139737Smckusick } else 39237328Skarels #endif 39337328Skarels if (uap->status) { 39443895Skarels status = W_STOPCODE(p->p_xstat); 39539410Skarels error = copyout((caddr_t)&status, 39651015Sralph (caddr_t)uap->status, sizeof(status)); 39739410Skarels } else 39839410Skarels error = 0; 39944404Skarels return (error); 40012790Ssam } 40112790Ssam } 40247540Skarels if (nfound == 0) 40344404Skarels return (ECHILD); 40437328Skarels if (uap->options & WNOHANG) { 40542927Smckusick retval[0] = 0; 40644404Skarels return (0); 40712790Ssam } 40842927Smckusick if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) 40944404Skarels return (error); 41012790Ssam goto loop; 41112790Ssam } 412*54338Smckusick 413*54338Smckusick /* 414*54338Smckusick * make process 'parent' the new parent of process 'child'. 415*54338Smckusick */ 416*54338Smckusick void 417*54338Smckusick proc_reparent(child, parent) 418*54338Smckusick register struct proc *child; 419*54338Smckusick register struct proc *parent; 420*54338Smckusick { 421*54338Smckusick register struct proc *o; 422*54338Smckusick register struct proc *y; 423*54338Smckusick 424*54338Smckusick if (child->p_pptr == parent) 425*54338Smckusick return; 426*54338Smckusick 427*54338Smckusick /* fix up the child linkage for the old parent */ 428*54338Smckusick o = child->p_osptr; 429*54338Smckusick y = child->p_ysptr; 430*54338Smckusick if (y) 431*54338Smckusick y->p_osptr = o; 432*54338Smckusick if (o) 433*54338Smckusick o->p_ysptr = y; 434*54338Smckusick if (child->p_pptr->p_cptr == child) 435*54338Smckusick child->p_pptr->p_cptr = o; 436*54338Smckusick 437*54338Smckusick /* fix up child linkage for new parent */ 438*54338Smckusick o = parent->p_cptr; 439*54338Smckusick if (o) 440*54338Smckusick o->p_ysptr = child; 441*54338Smckusick child->p_osptr = o; 442*54338Smckusick child->p_ysptr = NULL; 443*54338Smckusick parent->p_cptr = child; 444*54338Smckusick child->p_pptr = parent; 445*54338Smckusick } 446