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*51014Skarels * @(#)kern_exit.c 7.36 (Berkeley) 09/06/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); 8650200Skarels 8750200Skarels /* The next two chunks should probably be moved to vmspace_exit. */ 8845739Smckusick #ifdef SYSVSHM 8947540Skarels if (p->p_vmspace->vm_shm) 9045739Smckusick shmexit(p); 9145739Smckusick #endif 9250200Skarels /* 9350200Skarels * Release user portion of address space. 9450200Skarels * This releases references to vnodes, 9550200Skarels * which could cause I/O if the file has been unlinked. 9650200Skarels * Need to do this early enough that we can still sleep. 9750200Skarels * Can't free the entire vmspace as the kernel stack 9850200Skarels * may be mapped within that space also. 9950200Skarels */ 10050200Skarels if (p->p_vmspace->vm_refcnt == 1) 10150200Skarels (void) vm_map_remove(&p->p_vmspace->vm_map, VM_MIN_ADDRESS, 10250200Skarels VM_MAXUSER_ADDRESS); 10347540Skarels 10447540Skarels if (p->p_pid == 1) 10547540Skarels panic("init died"); 10637328Skarels if (SESS_LEADER(p)) { 10742897Smarc register struct session *sp = p->p_session; 10842897Smarc 10942897Smarc if (sp->s_ttyvp) { 11040809Smarc /* 11142897Smarc * Controlling process. 11249087Skarels * Signal foreground pgrp, 11349087Skarels * drain controlling terminal 11449087Skarels * and revoke access to controlling terminal. 11542897Smarc */ 11649087Skarels if (sp->s_ttyp->t_session == sp) { 11749087Skarels if (sp->s_ttyp->t_pgrp) 11849087Skarels pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 11949087Skarels (void) ttywait(sp->s_ttyp); 12049087Skarels vgoneall(sp->s_ttyvp); 12149087Skarels } 12242897Smarc vrele(sp->s_ttyvp); 12342897Smarc sp->s_ttyvp = NULL; 12442897Smarc /* 12540809Smarc * s_ttyp is not zero'd; we use this to indicate 12640809Smarc * that the session once had a controlling terminal. 12742897Smarc * (for logging and informational purposes) 12840809Smarc */ 12937328Skarels } 13049087Skarels sp->s_leader = NULL; 13137328Skarels } 13247540Skarels fixjobc(p, p->p_pgrp, 0); 13347540Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 13443380Smckusick (void) acct(p); 13537328Skarels #ifdef KTRACE 13637328Skarels /* 13737328Skarels * release trace file 13837328Skarels */ 13937328Skarels if (p->p_tracep) 14037728Smckusick vrele(p->p_tracep); 14137328Skarels #endif 142*51014Skarels /* 143*51014Skarels * Clear curproc after we've done all operations 144*51014Skarels * that could block, and before tearing down 145*51014Skarels * the rest of the process state. 146*51014Skarels */ 147*51014Skarels curproc = NULL; 148*51014Skarels if (--p->p_limit->p_refcnt == 0) 149*51014Skarels FREE(p->p_limit, M_SUBPROC); 15047540Skarels 15147540Skarels /* 15247540Skarels * Remove proc from allproc queue and pidhash chain. 15347540Skarels * Place onto zombproc. Unlink from parent's child list. 15447540Skarels */ 15547540Skarels if (*p->p_prev = p->p_nxt) 15616527Skarels p->p_nxt->p_prev = p->p_prev; 15747540Skarels if (p->p_nxt = zombproc) 15816527Skarels p->p_nxt->p_prev = &p->p_nxt; 15916527Skarels p->p_prev = &zombproc; 16016527Skarels zombproc = p; 16112790Ssam p->p_stat = SZOMB; 16240670Skarels for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash) 16340670Skarels if (*pp == p) { 16440670Skarels *pp = p->p_hash; 16540670Skarels goto done; 16640670Skarels } 16740670Skarels panic("exit"); 16840670Skarels done: 16947540Skarels 17016527Skarels if (p->p_cptr) /* only need this if any child is S_ZOMB */ 17147540Skarels wakeup((caddr_t) initproc); 17216527Skarels for (q = p->p_cptr; q != NULL; q = nq) { 17316527Skarels nq = q->p_osptr; 17416527Skarels if (nq != NULL) 17516527Skarels nq->p_ysptr = NULL; 17647540Skarels if (initproc->p_cptr) 17747540Skarels initproc->p_cptr->p_ysptr = q; 17847540Skarels q->p_osptr = initproc->p_cptr; 17916527Skarels q->p_ysptr = NULL; 18047540Skarels initproc->p_cptr = q; 18112790Ssam 18247540Skarels q->p_pptr = initproc; 18316527Skarels /* 18416527Skarels * Traced processes are killed 18516527Skarels * since their existence means someone is screwing up. 18616527Skarels */ 18716527Skarels if (q->p_flag&STRC) { 18816527Skarels q->p_flag &= ~STRC; 18916527Skarels psignal(q, SIGKILL); 19012790Ssam } 19116527Skarels } 19217540Skarels p->p_cptr = NULL; 19347540Skarels 19447540Skarels /* 19547540Skarels * Save exit status and final rusage info, 19647540Skarels * adding in child rusage info and self times. 19747540Skarels */ 19847540Skarels p->p_xstat = rv; 19947540Skarels *p->p_ru = p->p_stats->p_ru; 20047540Skarels p->p_ru->ru_stime = p->p_stime; 20147540Skarels p->p_ru->ru_utime = p->p_utime; 20247540Skarels ruadd(p->p_ru, &p->p_stats->p_cru); 20347540Skarels 20447540Skarels /* 20547540Skarels * Notify parent that we're gone. 20647540Skarels */ 20712790Ssam psignal(p->p_pptr, SIGCHLD); 20812790Ssam wakeup((caddr_t)p->p_pptr); 20929946Skarels #if defined(tahoe) 21049087Skarels /* move this to cpu_exit */ 21149087Skarels p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL; 21229946Skarels #endif 21347540Skarels /* 21449087Skarels * Finally, call machine-dependent code to release the remaining 21549087Skarels * resources including address space, the kernel stack and pcb. 21649087Skarels * The address space is released by "vmspace_free(p->p_vmspace)"; 21749087Skarels * This is machine-dependent, as we may have to change stacks 21849087Skarels * or ensure that the current one isn't reallocated before we 21949087Skarels * finish. cpu_exit will end with a call to swtch(), finishing 22049087Skarels * our execution (pun intended). 22147540Skarels */ 22249087Skarels cpu_exit(p); 22347540Skarels /* NOTREACHED */ 22412790Ssam } 22512790Ssam 22637328Skarels #ifdef COMPAT_43 22742927Smckusick owait(p, uap, retval) 22842927Smckusick struct proc *p; 22942927Smckusick register struct args { 23037328Skarels int pid; 23139410Skarels int *status; 23237328Skarels int options; 23337328Skarels struct rusage *rusage; 23439410Skarels int compat; 23542927Smckusick } *uap; 23642927Smckusick int *retval; 23742927Smckusick { 23812790Ssam 23947540Skarels if ((p->p_regs[PS] & PSL_ALLCC) != PSL_ALLCC) { 24038930Skarels uap->options = 0; 24137328Skarels uap->rusage = 0; 24237328Skarels } else { 24347540Skarels uap->options = p->p_regs[R0]; 24447540Skarels uap->rusage = (struct rusage *)p->p_regs[R1]; 24512790Ssam } 24637328Skarels uap->pid = WAIT_ANY; 24737328Skarels uap->status = 0; 24839410Skarels uap->compat = 1; 24944404Skarels return (wait1(p, uap, retval)); 25012790Ssam } 25112790Ssam 25242927Smckusick wait4(p, uap, retval) 25342927Smckusick struct proc *p; 25442927Smckusick struct args { 25539410Skarels int pid; 25639410Skarels int *status; 25739410Skarels int options; 25839410Skarels struct rusage *rusage; 25939410Skarels int compat; 26042927Smckusick } *uap; 26142927Smckusick int *retval; 26242927Smckusick { 26339410Skarels 26439410Skarels uap->compat = 0; 26544404Skarels return (wait1(p, uap, retval)); 26637328Skarels } 26739410Skarels #else 26839410Skarels #define wait1 wait4 26937328Skarels #endif 27037328Skarels 27112790Ssam /* 27247540Skarels * Wait: check child processes to see if any have exited, 27347540Skarels * stopped under trace, or (optionally) stopped by a signal. 27447540Skarels * Pass back status and deallocate exited child's proc structure. 27512790Ssam */ 27642927Smckusick wait1(q, uap, retval) 27742927Smckusick register struct proc *q; 27842927Smckusick register struct args { 27937328Skarels int pid; 28039410Skarels int *status; 28137328Skarels int options; 28237328Skarels struct rusage *rusage; 28339410Skarels #ifdef COMPAT_43 28439410Skarels int compat; 28539410Skarels #endif 28642927Smckusick } *uap; 28742927Smckusick int retval[]; 28842927Smckusick { 28947540Skarels register int nfound; 29042927Smckusick register struct proc *p; 29139410Skarels int status, error; 29212790Ssam 29337328Skarels if (uap->pid == 0) 29437328Skarels uap->pid = -q->p_pgid; 29538930Skarels #ifdef notyet 29639410Skarels if (uap->options &~ (WUNTRACED|WNOHANG)) 29744404Skarels return (EINVAL); 29838930Skarels #endif 29912790Ssam loop: 30047540Skarels nfound = 0; 30116527Skarels for (p = q->p_cptr; p; p = p->p_osptr) { 30237328Skarels if (uap->pid != WAIT_ANY && 30337328Skarels p->p_pid != uap->pid && p->p_pgid != -uap->pid) 30437328Skarels continue; 30547540Skarels nfound++; 30612790Ssam if (p->p_stat == SZOMB) { 30742927Smckusick retval[0] = p->p_pid; 30837328Skarels #ifdef COMPAT_43 30939410Skarels if (uap->compat) 31042927Smckusick retval[1] = p->p_xstat; 31137328Skarels else 31237328Skarels #endif 31337328Skarels if (uap->status) { 31439410Skarels status = p->p_xstat; /* convert to int */ 31539410Skarels if (error = copyout((caddr_t)&status, 31637328Skarels (caddr_t)uap->status, sizeof(status))) 31744404Skarels return (error); 31837328Skarels } 31939410Skarels if (uap->rusage && (error = copyout((caddr_t)p->p_ru, 32039410Skarels (caddr_t)uap->rusage, sizeof (struct rusage)))) 32144404Skarels return (error); 32212790Ssam p->p_xstat = 0; 32347540Skarels ruadd(&q->p_stats->p_cru, p->p_ru); 32437328Skarels FREE(p->p_ru, M_ZOMBIE); 32550200Skarels if (--p->p_cred->p_refcnt == 0) { 32650200Skarels crfree(p->p_cred->pc_ucred); 32750200Skarels FREE(p->p_cred, M_SUBPROC); 32850200Skarels } 32947540Skarels 33047540Skarels /* 33147540Skarels * Finally finished with old proc entry. 33247540Skarels * Unlink it from its process group and free it. 33347540Skarels */ 33447540Skarels leavepgrp(p); 33516527Skarels if (*p->p_prev = p->p_nxt) /* off zombproc */ 33616527Skarels p->p_nxt->p_prev = p->p_prev; 33712790Ssam if (q = p->p_ysptr) 33812790Ssam q->p_osptr = p->p_osptr; 33912790Ssam if (q = p->p_osptr) 34012790Ssam q->p_ysptr = p->p_ysptr; 34112790Ssam if ((q = p->p_pptr)->p_cptr == p) 34212790Ssam q->p_cptr = p->p_osptr; 34349690Swilliam 34450200Skarels /* 34550200Skarels * Give machine-dependent layer a chance 34650200Skarels * to free anything that cpu_exit couldn't 34750200Skarels * release while still running in process context. 34850200Skarels */ 34950200Skarels cpu_wait(p); 35047540Skarels FREE(p, M_PROC); 35147540Skarels nprocs--; 35244404Skarels return (0); 35312790Ssam } 35437328Skarels if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 && 35537328Skarels (p->p_flag & STRC || uap->options & WUNTRACED)) { 35612790Ssam p->p_flag |= SWTED; 35742927Smckusick retval[0] = p->p_pid; 35837328Skarels #ifdef COMPAT_43 35939737Smckusick if (uap->compat) { 36043895Skarels retval[1] = W_STOPCODE(p->p_xstat); 36139737Smckusick error = 0; 36239737Smckusick } else 36337328Skarels #endif 36437328Skarels if (uap->status) { 36543895Skarels status = W_STOPCODE(p->p_xstat); 36639410Skarels error = copyout((caddr_t)&status, 36737328Skarels (caddr_t)uap->status, sizeof(status)); 36839410Skarels } else 36939410Skarels error = 0; 37044404Skarels return (error); 37112790Ssam } 37212790Ssam } 37347540Skarels if (nfound == 0) 37444404Skarels return (ECHILD); 37537328Skarels if (uap->options & WNOHANG) { 37642927Smckusick retval[0] = 0; 37744404Skarels return (0); 37812790Ssam } 37942927Smckusick if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) 38044404Skarels return (error); 38112790Ssam goto loop; 38212790Ssam } 383