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*54133Smckusick * @(#)kern_exit.c 7.44 (Berkeley) 06/20/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" 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; 6452491Smckusick register struct vmspace *vm; 6547540Skarels int s; 6612790Ssam 6712790Ssam #ifdef PGINPROF 6812790Ssam vmsizmon(); 6912790Ssam #endif 70*54133Smckusick if (p->p_flag & SPROFIL) 71*54133Smckusick stopprofclock(p); 7232018Smckusick MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), 7332018Smckusick M_ZOMBIE, M_WAITOK); 7447540Skarels /* 7547540Skarels * If parent is waiting for us to exit or exec, 7647540Skarels * SPPWAIT is set; we will wakeup the parent below. 7747540Skarels */ 7848403Skarels p->p_flag &= ~(STRC|SPPWAIT); 7912790Ssam p->p_flag |= SWEXIT; 8012882Ssam p->p_sigignore = ~0; 8139410Skarels p->p_sig = 0; 8212790Ssam untimeout(realitexpire, (caddr_t)p); 8347540Skarels 8447540Skarels /* 8547540Skarels * Close open files and release open-file table. 8647540Skarels * This may block! 8747540Skarels */ 8847540Skarels fdfree(p); 8950200Skarels 9050200Skarels /* The next two chunks should probably be moved to vmspace_exit. */ 9152491Smckusick vm = p->p_vmspace; 9245739Smckusick #ifdef SYSVSHM 9352491Smckusick if (vm->vm_shm) 9445739Smckusick shmexit(p); 9545739Smckusick #endif 9650200Skarels /* 9750200Skarels * Release user portion of address space. 9850200Skarels * This releases references to vnodes, 9950200Skarels * which could cause I/O if the file has been unlinked. 10050200Skarels * Need to do this early enough that we can still sleep. 10150200Skarels * Can't free the entire vmspace as the kernel stack 10250200Skarels * may be mapped within that space also. 10350200Skarels */ 10452491Smckusick if (vm->vm_refcnt == 1) 10552491Smckusick (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS, 10650200Skarels VM_MAXUSER_ADDRESS); 10747540Skarels 10847540Skarels if (p->p_pid == 1) 10947540Skarels panic("init died"); 11037328Skarels if (SESS_LEADER(p)) { 11142897Smarc register struct session *sp = p->p_session; 11242897Smarc 11342897Smarc if (sp->s_ttyvp) { 11440809Smarc /* 11542897Smarc * Controlling process. 11649087Skarels * Signal foreground pgrp, 11749087Skarels * drain controlling terminal 11849087Skarels * and revoke access to controlling terminal. 11942897Smarc */ 12049087Skarels if (sp->s_ttyp->t_session == sp) { 12149087Skarels if (sp->s_ttyp->t_pgrp) 12249087Skarels pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 12349087Skarels (void) ttywait(sp->s_ttyp); 12449087Skarels vgoneall(sp->s_ttyvp); 12549087Skarels } 12642897Smarc vrele(sp->s_ttyvp); 12742897Smarc sp->s_ttyvp = NULL; 12842897Smarc /* 12940809Smarc * s_ttyp is not zero'd; we use this to indicate 13040809Smarc * that the session once had a controlling terminal. 13142897Smarc * (for logging and informational purposes) 13240809Smarc */ 13337328Skarels } 13449087Skarels sp->s_leader = NULL; 13537328Skarels } 13647540Skarels fixjobc(p, p->p_pgrp, 0); 13747540Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 13843380Smckusick (void) acct(p); 13937328Skarels #ifdef KTRACE 14037328Skarels /* 14137328Skarels * release trace file 14237328Skarels */ 14352202Smarc p->p_traceflag = 0; /* don't trace the vrele() */ 14437328Skarels if (p->p_tracep) 14537728Smckusick vrele(p->p_tracep); 14637328Skarels #endif 14751014Skarels /* 14847540Skarels * Remove proc from allproc queue and pidhash chain. 14947540Skarels * Place onto zombproc. Unlink from parent's child list. 15047540Skarels */ 15147540Skarels if (*p->p_prev = p->p_nxt) 15216527Skarels p->p_nxt->p_prev = p->p_prev; 15347540Skarels if (p->p_nxt = zombproc) 15416527Skarels p->p_nxt->p_prev = &p->p_nxt; 15516527Skarels p->p_prev = &zombproc; 15616527Skarels zombproc = p; 15712790Ssam p->p_stat = SZOMB; 15852484Smckusick 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: 16647540Skarels 16716527Skarels if (p->p_cptr) /* only need this if any child is S_ZOMB */ 16847540Skarels wakeup((caddr_t) initproc); 16916527Skarels for (q = p->p_cptr; q != NULL; q = nq) { 17016527Skarels nq = q->p_osptr; 17116527Skarels if (nq != NULL) 17216527Skarels nq->p_ysptr = NULL; 17347540Skarels if (initproc->p_cptr) 17447540Skarels initproc->p_cptr->p_ysptr = q; 17547540Skarels q->p_osptr = initproc->p_cptr; 17616527Skarels q->p_ysptr = NULL; 17747540Skarels initproc->p_cptr = q; 17812790Ssam 17947540Skarels q->p_pptr = initproc; 18016527Skarels /* 18116527Skarels * Traced processes are killed 18216527Skarels * since their existence means someone is screwing up. 18316527Skarels */ 18416527Skarels if (q->p_flag&STRC) { 18516527Skarels q->p_flag &= ~STRC; 18616527Skarels psignal(q, SIGKILL); 18712790Ssam } 18816527Skarels } 18917540Skarels p->p_cptr = NULL; 19047540Skarels 19147540Skarels /* 19247540Skarels * Save exit status and final rusage info, 19347540Skarels * adding in child rusage info and self times. 19447540Skarels */ 19547540Skarels p->p_xstat = rv; 19647540Skarels *p->p_ru = p->p_stats->p_ru; 19747540Skarels p->p_ru->ru_stime = p->p_stime; 19847540Skarels p->p_ru->ru_utime = p->p_utime; 19947540Skarels ruadd(p->p_ru, &p->p_stats->p_cru); 20047540Skarels 20147540Skarels /* 20247540Skarels * Notify parent that we're gone. 20347540Skarels */ 20412790Ssam psignal(p->p_pptr, SIGCHLD); 20512790Ssam wakeup((caddr_t)p->p_pptr); 20629946Skarels #if defined(tahoe) 20749087Skarels /* move this to cpu_exit */ 20849087Skarels p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; 20929946Skarels #endif 21047540Skarels /* 21152484Smckusick * Clear curproc after we've done all operations 21252484Smckusick * that could block, and before tearing down the rest 21352484Smckusick * of the process state that might be used from clock, etc. 21452484Smckusick * Also, can't clear curproc while we're still runnable, 21552484Smckusick * as we're not on a run queue (we are current, just not 21652484Smckusick * a proper proc any longer!). 21752484Smckusick * 21852484Smckusick * Other substructures are freed from wait(). 21952484Smckusick */ 22052484Smckusick curproc = NULL; 22152484Smckusick if (--p->p_limit->p_refcnt == 0) 22252484Smckusick FREE(p->p_limit, M_SUBPROC); 22352484Smckusick 22452484Smckusick /* 22549087Skarels * Finally, call machine-dependent code to release the remaining 22649087Skarels * resources including address space, the kernel stack and pcb. 22749087Skarels * The address space is released by "vmspace_free(p->p_vmspace)"; 22849087Skarels * This is machine-dependent, as we may have to change stacks 22949087Skarels * or ensure that the current one isn't reallocated before we 23049087Skarels * finish. cpu_exit will end with a call to swtch(), finishing 23149087Skarels * our execution (pun intended). 23247540Skarels */ 23349087Skarels cpu_exit(p); 23447540Skarels /* NOTREACHED */ 23512790Ssam } 23612790Ssam 23737328Skarels #ifdef COMPAT_43 23842927Smckusick owait(p, uap, retval) 23942927Smckusick struct proc *p; 24042927Smckusick register struct args { 24137328Skarels int pid; 24239410Skarels int *status; 24337328Skarels int options; 24437328Skarels struct rusage *rusage; 24539410Skarels int compat; 24642927Smckusick } *uap; 24742927Smckusick int *retval; 24842927Smckusick { 24912790Ssam 25051015Sralph #ifdef PSL_ALLCC 25152480Smckusick if ((p->p_md.md_regs[PS] & PSL_ALLCC) != PSL_ALLCC) { 25238930Skarels uap->options = 0; 25337328Skarels uap->rusage = 0; 25437328Skarels } else { 25552480Smckusick uap->options = p->p_md.md_regs[R0]; 25652480Smckusick uap->rusage = (struct rusage *)p->p_md.md_regs[R1]; 25712790Ssam } 25851015Sralph #else 25951015Sralph uap->options = 0; 26051015Sralph uap->rusage = 0; 26151015Sralph #endif 26237328Skarels uap->pid = WAIT_ANY; 26337328Skarels uap->status = 0; 26439410Skarels uap->compat = 1; 26544404Skarels return (wait1(p, uap, retval)); 26612790Ssam } 26712790Ssam 26842927Smckusick wait4(p, uap, retval) 26942927Smckusick struct proc *p; 27042927Smckusick struct args { 27139410Skarels int pid; 27239410Skarels int *status; 27339410Skarels int options; 27439410Skarels struct rusage *rusage; 27539410Skarels int compat; 27642927Smckusick } *uap; 27742927Smckusick int *retval; 27842927Smckusick { 27939410Skarels 28039410Skarels uap->compat = 0; 28144404Skarels return (wait1(p, uap, retval)); 28237328Skarels } 28339410Skarels #else 28439410Skarels #define wait1 wait4 28537328Skarels #endif 28637328Skarels 28712790Ssam /* 28847540Skarels * Wait: check child processes to see if any have exited, 28947540Skarels * stopped under trace, or (optionally) stopped by a signal. 29047540Skarels * Pass back status and deallocate exited child's proc structure. 29112790Ssam */ 29242927Smckusick wait1(q, uap, retval) 29342927Smckusick register struct proc *q; 29442927Smckusick register struct args { 29537328Skarels int pid; 29639410Skarels int *status; 29737328Skarels int options; 29837328Skarels struct rusage *rusage; 29939410Skarels #ifdef COMPAT_43 30039410Skarels int compat; 30139410Skarels #endif 30242927Smckusick } *uap; 30342927Smckusick int retval[]; 30442927Smckusick { 30547540Skarels register int nfound; 30642927Smckusick register struct proc *p; 30739410Skarels int status, error; 30812790Ssam 30937328Skarels if (uap->pid == 0) 31037328Skarels uap->pid = -q->p_pgid; 31138930Skarels #ifdef notyet 31239410Skarels if (uap->options &~ (WUNTRACED|WNOHANG)) 31344404Skarels return (EINVAL); 31438930Skarels #endif 31512790Ssam loop: 31647540Skarels nfound = 0; 31716527Skarels for (p = q->p_cptr; p; p = p->p_osptr) { 31837328Skarels if (uap->pid != WAIT_ANY && 31937328Skarels p->p_pid != uap->pid && p->p_pgid != -uap->pid) 32037328Skarels continue; 32147540Skarels nfound++; 32212790Ssam if (p->p_stat == SZOMB) { 32342927Smckusick retval[0] = p->p_pid; 32437328Skarels #ifdef COMPAT_43 32539410Skarels if (uap->compat) 32642927Smckusick retval[1] = p->p_xstat; 32737328Skarels else 32837328Skarels #endif 32937328Skarels if (uap->status) { 33039410Skarels status = p->p_xstat; /* convert to int */ 33139410Skarels if (error = copyout((caddr_t)&status, 33237328Skarels (caddr_t)uap->status, sizeof(status))) 33344404Skarels return (error); 33437328Skarels } 33539410Skarels if (uap->rusage && (error = copyout((caddr_t)p->p_ru, 33639410Skarels (caddr_t)uap->rusage, sizeof (struct rusage)))) 33744404Skarels return (error); 33812790Ssam p->p_xstat = 0; 33947540Skarels ruadd(&q->p_stats->p_cru, p->p_ru); 34037328Skarels FREE(p->p_ru, M_ZOMBIE); 34150200Skarels if (--p->p_cred->p_refcnt == 0) { 34250200Skarels crfree(p->p_cred->pc_ucred); 34350200Skarels FREE(p->p_cred, M_SUBPROC); 34450200Skarels } 34547540Skarels 34647540Skarels /* 34747540Skarels * Finally finished with old proc entry. 34847540Skarels * Unlink it from its process group and free it. 34947540Skarels */ 35047540Skarels leavepgrp(p); 35116527Skarels if (*p->p_prev = p->p_nxt) /* off zombproc */ 35216527Skarels p->p_nxt->p_prev = p->p_prev; 35312790Ssam if (q = p->p_ysptr) 35412790Ssam q->p_osptr = p->p_osptr; 35512790Ssam if (q = p->p_osptr) 35612790Ssam q->p_ysptr = p->p_ysptr; 35712790Ssam if ((q = p->p_pptr)->p_cptr == p) 35812790Ssam q->p_cptr = p->p_osptr; 35949690Swilliam 36050200Skarels /* 36150200Skarels * Give machine-dependent layer a chance 36250200Skarels * to free anything that cpu_exit couldn't 36350200Skarels * release while still running in process context. 36450200Skarels */ 36550200Skarels cpu_wait(p); 36647540Skarels FREE(p, M_PROC); 36747540Skarels nprocs--; 36844404Skarels return (0); 36912790Ssam } 37037328Skarels if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 && 37137328Skarels (p->p_flag & STRC || uap->options & WUNTRACED)) { 37212790Ssam p->p_flag |= SWTED; 37342927Smckusick retval[0] = p->p_pid; 37437328Skarels #ifdef COMPAT_43 37539737Smckusick if (uap->compat) { 37643895Skarels retval[1] = W_STOPCODE(p->p_xstat); 37739737Smckusick error = 0; 37839737Smckusick } else 37937328Skarels #endif 38037328Skarels if (uap->status) { 38143895Skarels status = W_STOPCODE(p->p_xstat); 38239410Skarels error = copyout((caddr_t)&status, 38351015Sralph (caddr_t)uap->status, sizeof(status)); 38439410Skarels } else 38539410Skarels error = 0; 38644404Skarels return (error); 38712790Ssam } 38812790Ssam } 38947540Skarels if (nfound == 0) 39044404Skarels return (ECHILD); 39137328Skarels if (uap->options & WNOHANG) { 39242927Smckusick retval[0] = 0; 39344404Skarels return (0); 39412790Ssam } 39542927Smckusick if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) 39644404Skarels return (error); 39712790Ssam goto loop; 39812790Ssam } 399