| 1 | /* kern_exit.c 4.3 83/06/02 */ |
| 2 | |
| 3 | #include "../machine/reg.h" |
| 4 | #include "../machine/psl.h" |
| 5 | |
| 6 | #include "../h/param.h" |
| 7 | #include "../h/systm.h" |
| 8 | #include "../h/map.h" |
| 9 | #include "../h/dir.h" |
| 10 | #include "../h/user.h" |
| 11 | #include "../h/kernel.h" |
| 12 | #include "../h/proc.h" |
| 13 | #include "../h/buf.h" |
| 14 | #include "../h/wait.h" |
| 15 | #include "../h/vm.h" |
| 16 | #include "../h/file.h" |
| 17 | #include "../h/mbuf.h" |
| 18 | #include "../h/inode.h" |
| 19 | |
| 20 | /* |
| 21 | * Exit system call: pass back caller's arg |
| 22 | */ |
| 23 | rexit() |
| 24 | { |
| 25 | register struct a { |
| 26 | int rval; |
| 27 | } *uap; |
| 28 | |
| 29 | uap = (struct a *)u.u_ap; |
| 30 | exit((uap->rval & 0377) << 8); |
| 31 | } |
| 32 | |
| 33 | /* |
| 34 | * Release resources. |
| 35 | * Save u. area for parent to look at. |
| 36 | * Enter zombie state. |
| 37 | * Wake up parent and init processes, |
| 38 | * and dispose of children. |
| 39 | */ |
| 40 | exit(rv) |
| 41 | int rv; |
| 42 | { |
| 43 | register int i; |
| 44 | register struct proc *p, *q; |
| 45 | register int x; |
| 46 | struct mbuf *m = m_getclr(M_WAIT, MT_ZOMBIE); |
| 47 | |
| 48 | #ifdef PGINPROF |
| 49 | vmsizmon(); |
| 50 | #endif |
| 51 | p = u.u_procp; |
| 52 | p->p_flag &= ~(STRC|SULOCK); |
| 53 | p->p_flag |= SWEXIT; |
| 54 | p->p_sigignore = ~0; |
| 55 | p->p_cpticks = 0; |
| 56 | p->p_pctcpu = 0; |
| 57 | for (i = 0; i < NSIG; i++) |
| 58 | u.u_signal[i] = SIG_IGN; |
| 59 | untimeout(realitexpire, (caddr_t)p); |
| 60 | /* |
| 61 | * Release virtual memory. If we resulted from |
| 62 | * a vfork(), instead give the resources back to |
| 63 | * the parent. |
| 64 | */ |
| 65 | if ((p->p_flag & SVFORK) == 0) |
| 66 | vrelvm(); |
| 67 | else { |
| 68 | p->p_flag &= ~SVFORK; |
| 69 | wakeup((caddr_t)p); |
| 70 | while ((p->p_flag & SVFDONE) == 0) |
| 71 | sleep((caddr_t)p, PZERO - 1); |
| 72 | p->p_flag &= ~SVFDONE; |
| 73 | } |
| 74 | for (i = 0; i < NOFILE; i++) { |
| 75 | struct file *f; |
| 76 | int po; |
| 77 | |
| 78 | f = u.u_ofile[i]; |
| 79 | u.u_ofile[i] = NULL; |
| 80 | po = u.u_pofile[i]; |
| 81 | u.u_pofile[i] = 0; |
| 82 | closef(f, po); |
| 83 | } |
| 84 | ilock(u.u_cdir); |
| 85 | iput(u.u_cdir); |
| 86 | if (u.u_rdir) { |
| 87 | ilock(u.u_rdir); |
| 88 | iput(u.u_rdir); |
| 89 | } |
| 90 | u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; |
| 91 | acct(); |
| 92 | #ifdef QUOTA |
| 93 | qclean(); |
| 94 | #endif |
| 95 | #ifdef sun |
| 96 | ctxfree(u.u_procp); |
| 97 | #endif |
| 98 | vrelpt(u.u_procp); |
| 99 | vrelu(u.u_procp, 0); |
| 100 | (void) spl5(); /* hack for mem alloc race XXX */ |
| 101 | multprog--; |
| 102 | p->p_stat = SZOMB; |
| 103 | noproc = 1; |
| 104 | i = PIDHASH(p->p_pid); |
| 105 | x = p - proc; |
| 106 | if (pidhash[i] == x) |
| 107 | pidhash[i] = p->p_idhash; |
| 108 | else { |
| 109 | for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) |
| 110 | if (proc[i].p_idhash == x) { |
| 111 | proc[i].p_idhash = p->p_idhash; |
| 112 | goto done; |
| 113 | } |
| 114 | panic("exit"); |
| 115 | } |
| 116 | if (p->p_pid == 1) |
| 117 | panic("init died"); |
| 118 | done: |
| 119 | p->p_xstat = rv; |
| 120 | if (m == 0) |
| 121 | panic("exit: m_getclr"); |
| 122 | p->p_ru = mtod(m, struct rusage *); |
| 123 | *p->p_ru = u.u_ru; |
| 124 | ruadd(p->p_ru, &u.u_cru); |
| 125 | for (q = proc; q < procNPROC; q++) |
| 126 | if (q->p_pptr == p) { |
| 127 | if (q->p_osptr) |
| 128 | q->p_osptr->p_ysptr = q->p_ysptr; |
| 129 | if (q->p_ysptr) |
| 130 | q->p_ysptr->p_osptr = q->p_osptr; |
| 131 | if (proc[1].p_cptr) |
| 132 | proc[1].p_cptr->p_ysptr = q; |
| 133 | q->p_osptr = proc[1].p_cptr; |
| 134 | q->p_ysptr = NULL; |
| 135 | proc[1].p_cptr = q; |
| 136 | |
| 137 | q->p_pptr = &proc[1]; |
| 138 | q->p_ppid = 1; |
| 139 | wakeup((caddr_t)&proc[1]); |
| 140 | /* |
| 141 | * Traced processes are killed |
| 142 | * since their existence means someone is screwing up. |
| 143 | * Stopped processes are sent a hangup and a continue. |
| 144 | * This is designed to be ``safe'' for setuid |
| 145 | * processes since they must be willing to tolerate |
| 146 | * hangups anyways. |
| 147 | */ |
| 148 | if (q->p_flag&STRC) { |
| 149 | q->p_flag &= ~STRC; |
| 150 | psignal(q, SIGKILL); |
| 151 | } else if (q->p_stat == SSTOP) { |
| 152 | psignal(q, SIGHUP); |
| 153 | psignal(q, SIGCONT); |
| 154 | } |
| 155 | /* |
| 156 | * Protect this process from future |
| 157 | * tty signals, clear TSTP/TTIN/TTOU if pending. |
| 158 | */ |
| 159 | (void) spgrp(q, -1); |
| 160 | } |
| 161 | psignal(p->p_pptr, SIGCHLD); |
| 162 | wakeup((caddr_t)p->p_pptr); |
| 163 | swtch(); |
| 164 | } |
| 165 | |
| 166 | wait() |
| 167 | { |
| 168 | struct rusage ru, *rup; |
| 169 | |
| 170 | if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { |
| 171 | u.u_error = wait1(0, (struct rusage *)0); |
| 172 | return; |
| 173 | } |
| 174 | rup = (struct rusage *)u.u_ar0[R1]; |
| 175 | u.u_error = wait1(u.u_ar0[R0], &ru); |
| 176 | if (u.u_error) |
| 177 | return; |
| 178 | (void) copyout((caddr_t)&ru, (caddr_t)rup, sizeof (struct rusage)); |
| 179 | } |
| 180 | |
| 181 | /* |
| 182 | * Wait system call. |
| 183 | * Search for a terminated (zombie) child, |
| 184 | * finally lay it to rest, and collect its status. |
| 185 | * Look also for stopped (traced) children, |
| 186 | * and pass back status from them. |
| 187 | */ |
| 188 | wait1(options, ru) |
| 189 | register int options; |
| 190 | struct rusage *ru; |
| 191 | { |
| 192 | register f; |
| 193 | register struct proc *p, *q; |
| 194 | |
| 195 | f = 0; |
| 196 | loop: |
| 197 | for (p = proc; p < procNPROC; p++) |
| 198 | if (p->p_pptr == u.u_procp) { |
| 199 | f++; |
| 200 | if (p->p_stat == SZOMB) { |
| 201 | u.u_r.r_val1 = p->p_pid; |
| 202 | u.u_r.r_val2 = p->p_xstat; |
| 203 | p->p_xstat = 0; |
| 204 | if (ru) |
| 205 | *ru = *p->p_ru; |
| 206 | ruadd(&u.u_cru, p->p_ru); |
| 207 | (void) m_free(dtom(p->p_ru)); |
| 208 | p->p_ru = 0; |
| 209 | p->p_stat = NULL; |
| 210 | p->p_pid = 0; |
| 211 | p->p_ppid = 0; |
| 212 | if (q = p->p_ysptr) |
| 213 | q->p_osptr = p->p_osptr; |
| 214 | if (q = p->p_osptr) |
| 215 | q->p_ysptr = p->p_ysptr; |
| 216 | if ((q = p->p_pptr)->p_cptr == p) |
| 217 | q->p_cptr = p->p_osptr; |
| 218 | p->p_pptr = 0; |
| 219 | p->p_ysptr = 0; |
| 220 | p->p_osptr = 0; |
| 221 | p->p_cptr = 0; |
| 222 | p->p_sig = 0; |
| 223 | p->p_sigcatch = 0; |
| 224 | p->p_sigignore = 0; |
| 225 | p->p_sigmask = 0; |
| 226 | p->p_pgrp = 0; |
| 227 | p->p_flag = 0; |
| 228 | p->p_wchan = 0; |
| 229 | p->p_cursig = 0; |
| 230 | return (0); |
| 231 | } |
| 232 | if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && |
| 233 | (p->p_flag&STRC || options&WUNTRACED)) { |
| 234 | p->p_flag |= SWTED; |
| 235 | u.u_r.r_val1 = p->p_pid; |
| 236 | u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; |
| 237 | return (0); |
| 238 | } |
| 239 | } |
| 240 | if (f == 0) |
| 241 | return (ECHILD); |
| 242 | if (options&WNOHANG) { |
| 243 | u.u_r.r_val1 = 0; |
| 244 | return (0); |
| 245 | } |
| 246 | if ((u.u_procp->p_flag&SOUSIG) == 0 && setjmp(&u.u_qsave)) { |
| 247 | u.u_eosys = RESTARTSYS; |
| 248 | return (0); |
| 249 | } |
| 250 | sleep((caddr_t)u.u_procp, PWAIT); |
| 251 | goto loop; |
| 252 | } |