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*48403Skarels * @(#)kern_exit.c 7.32 (Berkeley) 04/20/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" 25*48403Skarels #include "resourcevar.h" 2612790Ssam 2747540Skarels #ifdef COMPAT_43 2837520Smckusick #include "machine/reg.h" 2937520Smckusick #include "machine/psl.h" 3037328Skarels #endif 3137328Skarels 32*48403Skarels #include "vm/vm.h" 3347540Skarels #include "vm/vm_kern.h" 3445739Smckusick 3512790Ssam /* 3612790Ssam * Exit system call: pass back caller's arg 3712790Ssam */ 3842927Smckusick /* ARGSUSED */ 3942927Smckusick rexit(p, uap, retval) 4042927Smckusick struct proc *p; 4142927Smckusick struct args { 4212790Ssam int rval; 4312790Ssam } *uap; 4442927Smckusick int *retval; 4542927Smckusick { 4612790Ssam 4745157Skarels exit(p, W_EXITCODE(uap->rval, 0)); 4845157Skarels /* NOTREACHED */ 4912790Ssam } 5012790Ssam 5112790Ssam /* 5247540Skarels * Exit: deallocate address space and other resources, 5347540Skarels * change proc state to zombie, and unlink proc from allproc 5447540Skarels * and parent's lists. Save exit status and rusage for wait(). 5547540Skarels * Check for child processes and orphan them. 5612790Ssam */ 5742927Smckusick exit(p, rv) 5847540Skarels register struct proc *p; 5938930Skarels int rv; 6012790Ssam { 6142927Smckusick register struct proc *q, *nq; 6240670Skarels register struct proc **pp; 6347540Skarels int s; 6412790Ssam 6512790Ssam #ifdef PGINPROF 6612790Ssam vmsizmon(); 6712790Ssam #endif 6832018Smckusick MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), 6932018Smckusick M_ZOMBIE, M_WAITOK); 7047540Skarels /* 7147540Skarels * If parent is waiting for us to exit or exec, 7247540Skarels * SPPWAIT is set; we will wakeup the parent below. 7347540Skarels */ 74*48403Skarels p->p_flag &= ~(STRC|SPPWAIT); 7512790Ssam p->p_flag |= SWEXIT; 7612882Ssam p->p_sigignore = ~0; 7739410Skarels p->p_sig = 0; 7812790Ssam untimeout(realitexpire, (caddr_t)p); 7947540Skarels 8047540Skarels /* 8147540Skarels * Close open files and release open-file table. 8247540Skarels * This may block! 8347540Skarels */ 8447540Skarels fdfree(p); 8547540Skarels p->p_fd = 0; 8645739Smckusick #ifdef SYSVSHM 8747540Skarels if (p->p_vmspace->vm_shm) 8845739Smckusick shmexit(p); 8945739Smckusick #endif 9047540Skarels vmspace_free(p->p_vmspace); 9147540Skarels p->p_vmspace = 0; 9247540Skarels 9347540Skarels if (p->p_pid == 1) 9447540Skarels panic("init died"); 9537328Skarels if (SESS_LEADER(p)) { 9642897Smarc register struct session *sp = p->p_session; 9742897Smarc 9842897Smarc if (sp->s_ttyvp) { 9940809Smarc /* 10042897Smarc * Controlling process. 10142897Smarc * Signal foreground pgrp and revoke access 10242897Smarc * to controlling terminal. 10342897Smarc */ 10442897Smarc if (sp->s_ttyp->t_pgrp) 10542916Smarc pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); 10642897Smarc vgoneall(sp->s_ttyvp); 10742897Smarc vrele(sp->s_ttyvp); 10842897Smarc sp->s_ttyvp = NULL; 10942897Smarc /* 11040809Smarc * s_ttyp is not zero'd; we use this to indicate 11140809Smarc * that the session once had a controlling terminal. 11242897Smarc * (for logging and informational purposes) 11340809Smarc */ 11437328Skarels } 11542897Smarc sp->s_leader = 0; 11637328Skarels } 11747540Skarels fixjobc(p, p->p_pgrp, 0); 11847540Skarels p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 11943380Smckusick (void) acct(p); 12047540Skarels if (--p->p_limit->p_refcnt == 0) 12147540Skarels FREE(p->p_limit, M_SUBPROC); 12247540Skarels if (--p->p_cred->p_refcnt == 0) { 12347540Skarels crfree(p->p_cred->pc_ucred); 12447540Skarels FREE(p->p_cred, M_SUBPROC); 12547540Skarels } 12637328Skarels #ifdef KTRACE 12737328Skarels /* 12837328Skarels * release trace file 12937328Skarels */ 13037328Skarels if (p->p_tracep) 13137728Smckusick vrele(p->p_tracep); 13237328Skarels #endif 13347540Skarels 13447540Skarels /* 13547540Skarels * Remove proc from allproc queue and pidhash chain. 13647540Skarels * Place onto zombproc. Unlink from parent's child list. 13747540Skarels */ 13847540Skarels if (*p->p_prev = p->p_nxt) 13916527Skarels p->p_nxt->p_prev = p->p_prev; 14047540Skarels if (p->p_nxt = zombproc) 14116527Skarels p->p_nxt->p_prev = &p->p_nxt; 14216527Skarels p->p_prev = &zombproc; 14316527Skarels zombproc = p; 14412790Ssam p->p_stat = SZOMB; 145*48403Skarels curproc = NULL; 14640670Skarels for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash) 14740670Skarels if (*pp == p) { 14840670Skarels *pp = p->p_hash; 14940670Skarels goto done; 15040670Skarels } 15140670Skarels panic("exit"); 15240670Skarels done: 15347540Skarels 15416527Skarels if (p->p_cptr) /* only need this if any child is S_ZOMB */ 15547540Skarels wakeup((caddr_t) initproc); 15616527Skarels for (q = p->p_cptr; q != NULL; q = nq) { 15716527Skarels nq = q->p_osptr; 15816527Skarels if (nq != NULL) 15916527Skarels nq->p_ysptr = NULL; 16047540Skarels if (initproc->p_cptr) 16147540Skarels initproc->p_cptr->p_ysptr = q; 16247540Skarels q->p_osptr = initproc->p_cptr; 16316527Skarels q->p_ysptr = NULL; 16447540Skarels initproc->p_cptr = q; 16512790Ssam 16647540Skarels q->p_pptr = initproc; 16716527Skarels /* 16816527Skarels * Traced processes are killed 16916527Skarels * since their existence means someone is screwing up. 17016527Skarels */ 17116527Skarels if (q->p_flag&STRC) { 17216527Skarels q->p_flag &= ~STRC; 17316527Skarels psignal(q, SIGKILL); 17412790Ssam } 17516527Skarels } 17617540Skarels p->p_cptr = NULL; 17747540Skarels 17847540Skarels /* 17947540Skarels * Save exit status and final rusage info, 18047540Skarels * adding in child rusage info and self times. 18147540Skarels */ 18247540Skarels p->p_xstat = rv; 18347540Skarels *p->p_ru = p->p_stats->p_ru; 18447540Skarels p->p_ru->ru_stime = p->p_stime; 18547540Skarels p->p_ru->ru_utime = p->p_utime; 18647540Skarels ruadd(p->p_ru, &p->p_stats->p_cru); 18747540Skarels 18847540Skarels /* 18947540Skarels * Notify parent that we're gone. 19047540Skarels */ 19112790Ssam psignal(p->p_pptr, SIGCHLD); 19212790Ssam wakeup((caddr_t)p->p_pptr); 19329946Skarels #if defined(tahoe) 19429946Skarels u.u_pcb.pcb_savacc.faddr = (float *)NULL; 19529946Skarels #endif 19647540Skarels /* 19747540Skarels * Free the memory for the user structure and kernel stack. 19847540Skarels * As we continue using it until the swtch completes 19947540Skarels * (or switches to an interrupt stack), we need to block 20047540Skarels * memory allocation by raising priority until we are gone. 20147540Skarels */ 20247540Skarels (void) splimp(); 20347540Skarels /* I don't think this will cause a sleep/realloc anywhere... */ 20447540Skarels kmem_free(kernel_map, (vm_offset_t)p->p_addr, 20547540Skarels round_page(ctob(UPAGES))); 20612790Ssam swtch(); 20747540Skarels /* NOTREACHED */ 20812790Ssam } 20912790Ssam 21037328Skarels #ifdef COMPAT_43 21142927Smckusick owait(p, uap, retval) 21242927Smckusick struct proc *p; 21342927Smckusick register struct args { 21437328Skarels int pid; 21539410Skarels int *status; 21637328Skarels int options; 21737328Skarels struct rusage *rusage; 21839410Skarels int compat; 21942927Smckusick } *uap; 22042927Smckusick int *retval; 22142927Smckusick { 22212790Ssam 22347540Skarels if ((p->p_regs[PS] & PSL_ALLCC) != PSL_ALLCC) { 22438930Skarels uap->options = 0; 22537328Skarels uap->rusage = 0; 22637328Skarels } else { 22747540Skarels uap->options = p->p_regs[R0]; 22847540Skarels uap->rusage = (struct rusage *)p->p_regs[R1]; 22912790Ssam } 23037328Skarels uap->pid = WAIT_ANY; 23137328Skarels uap->status = 0; 23239410Skarels uap->compat = 1; 23344404Skarels return (wait1(p, uap, retval)); 23412790Ssam } 23512790Ssam 23642927Smckusick wait4(p, uap, retval) 23742927Smckusick struct proc *p; 23842927Smckusick struct args { 23939410Skarels int pid; 24039410Skarels int *status; 24139410Skarels int options; 24239410Skarels struct rusage *rusage; 24339410Skarels int compat; 24442927Smckusick } *uap; 24542927Smckusick int *retval; 24642927Smckusick { 24739410Skarels 24839410Skarels uap->compat = 0; 24944404Skarels return (wait1(p, uap, retval)); 25037328Skarels } 25139410Skarels #else 25239410Skarels #define wait1 wait4 25337328Skarels #endif 25437328Skarels 25512790Ssam /* 25647540Skarels * Wait: check child processes to see if any have exited, 25747540Skarels * stopped under trace, or (optionally) stopped by a signal. 25847540Skarels * Pass back status and deallocate exited child's proc structure. 25912790Ssam */ 26042927Smckusick wait1(q, uap, retval) 26142927Smckusick register struct proc *q; 26242927Smckusick register struct args { 26337328Skarels int pid; 26439410Skarels int *status; 26537328Skarels int options; 26637328Skarels struct rusage *rusage; 26739410Skarels #ifdef COMPAT_43 26839410Skarels int compat; 26939410Skarels #endif 27042927Smckusick } *uap; 27142927Smckusick int retval[]; 27242927Smckusick { 27347540Skarels register int nfound; 27442927Smckusick register struct proc *p; 27539410Skarels int status, error; 27612790Ssam 27737328Skarels if (uap->pid == 0) 27837328Skarels uap->pid = -q->p_pgid; 27938930Skarels #ifdef notyet 28039410Skarels if (uap->options &~ (WUNTRACED|WNOHANG)) 28144404Skarels return (EINVAL); 28238930Skarels #endif 28312790Ssam loop: 28447540Skarels nfound = 0; 28516527Skarels for (p = q->p_cptr; p; p = p->p_osptr) { 28637328Skarels if (uap->pid != WAIT_ANY && 28737328Skarels p->p_pid != uap->pid && p->p_pgid != -uap->pid) 28837328Skarels continue; 28947540Skarels nfound++; 29012790Ssam if (p->p_stat == SZOMB) { 29142927Smckusick retval[0] = p->p_pid; 29237328Skarels #ifdef COMPAT_43 29339410Skarels if (uap->compat) 29442927Smckusick retval[1] = p->p_xstat; 29537328Skarels else 29637328Skarels #endif 29737328Skarels if (uap->status) { 29839410Skarels status = p->p_xstat; /* convert to int */ 29939410Skarels if (error = copyout((caddr_t)&status, 30037328Skarels (caddr_t)uap->status, sizeof(status))) 30144404Skarels return (error); 30237328Skarels } 30339410Skarels if (uap->rusage && (error = copyout((caddr_t)p->p_ru, 30439410Skarels (caddr_t)uap->rusage, sizeof (struct rusage)))) 30544404Skarels return (error); 30612790Ssam p->p_xstat = 0; 30747540Skarels ruadd(&q->p_stats->p_cru, p->p_ru); 30837328Skarels FREE(p->p_ru, M_ZOMBIE); 30947540Skarels 31047540Skarels /* 31147540Skarels * Finally finished with old proc entry. 31247540Skarels * Unlink it from its process group and free it. 31347540Skarels */ 31447540Skarels leavepgrp(p); 31516527Skarels if (*p->p_prev = p->p_nxt) /* off zombproc */ 31616527Skarels p->p_nxt->p_prev = p->p_prev; 31712790Ssam if (q = p->p_ysptr) 31812790Ssam q->p_osptr = p->p_osptr; 31912790Ssam if (q = p->p_osptr) 32012790Ssam q->p_ysptr = p->p_ysptr; 32112790Ssam if ((q = p->p_pptr)->p_cptr == p) 32212790Ssam q->p_cptr = p->p_osptr; 32347540Skarels FREE(p, M_PROC); 32447540Skarels nprocs--; 32544404Skarels return (0); 32612790Ssam } 32737328Skarels if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 && 32837328Skarels (p->p_flag & STRC || uap->options & WUNTRACED)) { 32912790Ssam p->p_flag |= SWTED; 33042927Smckusick retval[0] = p->p_pid; 33137328Skarels #ifdef COMPAT_43 33239737Smckusick if (uap->compat) { 33343895Skarels retval[1] = W_STOPCODE(p->p_xstat); 33439737Smckusick error = 0; 33539737Smckusick } else 33637328Skarels #endif 33737328Skarels if (uap->status) { 33843895Skarels status = W_STOPCODE(p->p_xstat); 33939410Skarels error = copyout((caddr_t)&status, 34037328Skarels (caddr_t)uap->status, sizeof(status)); 34139410Skarels } else 34239410Skarels error = 0; 34344404Skarels return (error); 34412790Ssam } 34512790Ssam } 34647540Skarels if (nfound == 0) 34744404Skarels return (ECHILD); 34837328Skarels if (uap->options & WNOHANG) { 34942927Smckusick retval[0] = 0; 35044404Skarels return (0); 35112790Ssam } 35242927Smckusick if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)) 35344404Skarels return (error); 35412790Ssam goto loop; 35512790Ssam } 356