Annotation of sys/kern/kern_exit.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_exit.c,v 1.71 2007/04/12 22:14:15 tedu Exp $ */
! 2: /* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1982, 1986, 1989, 1991, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: * (c) UNIX System Laboratories, Inc.
! 8: * All or some portions of this file are derived from material licensed
! 9: * to the University of California by American Telephone and Telegraph
! 10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
! 11: * the permission of UNIX System Laboratories, Inc.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. Neither the name of the University nor the names of its contributors
! 22: * may be used to endorse or promote products derived from this software
! 23: * without specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/ioctl.h>
! 43: #include <sys/proc.h>
! 44: #include <sys/tty.h>
! 45: #include <sys/time.h>
! 46: #include <sys/resource.h>
! 47: #include <sys/kernel.h>
! 48: #include <sys/buf.h>
! 49: #include <sys/wait.h>
! 50: #include <sys/file.h>
! 51: #include <sys/vnode.h>
! 52: #include <sys/syslog.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/resourcevar.h>
! 55: #include <sys/ptrace.h>
! 56: #include <sys/acct.h>
! 57: #include <sys/filedesc.h>
! 58: #include <sys/signalvar.h>
! 59: #include <sys/sched.h>
! 60: #include <sys/ktrace.h>
! 61: #include <sys/pool.h>
! 62: #include <sys/mutex.h>
! 63: #ifdef SYSVSHM
! 64: #include <sys/shm.h>
! 65: #endif
! 66: #ifdef SYSVSEM
! 67: #include <sys/sem.h>
! 68: #endif
! 69:
! 70: #include "systrace.h"
! 71: #include <dev/systrace.h>
! 72:
! 73: #include <sys/mount.h>
! 74: #include <sys/syscallargs.h>
! 75:
! 76: #include <machine/cpu.h>
! 77:
! 78: #include <uvm/uvm_extern.h>
! 79:
! 80: /*
! 81: * exit --
! 82: * Death of process.
! 83: */
! 84: int
! 85: sys_exit(struct proc *p, void *v, register_t *retval)
! 86: {
! 87: struct sys_exit_args /* {
! 88: syscallarg(int) rval;
! 89: } */ *uap = v;
! 90:
! 91: exit1(p, W_EXITCODE(SCARG(uap, rval), 0), EXIT_NORMAL);
! 92: /* NOTREACHED */
! 93: return (0);
! 94: }
! 95:
! 96: #ifdef RTHREADS
! 97: int
! 98: sys_threxit(struct proc *p, void *v, register_t *retval)
! 99: {
! 100: struct sys_threxit_args *uap = v;
! 101:
! 102: exit1(p, W_EXITCODE(SCARG(uap, rval), 0), EXIT_THREAD);
! 103:
! 104: return (0);
! 105: }
! 106: #endif
! 107:
! 108: /*
! 109: * Exit: deallocate address space and other resources, change proc state
! 110: * to zombie, and unlink proc from allproc and parent's lists. Save exit
! 111: * status and rusage for wait(). Check for child processes and orphan them.
! 112: */
! 113: void
! 114: exit1(struct proc *p, int rv, int flags)
! 115: {
! 116: struct proc *q, *nq;
! 117:
! 118: if (p->p_pid == 1)
! 119: panic("init died (signal %d, exit %d)",
! 120: WTERMSIG(rv), WEXITSTATUS(rv));
! 121:
! 122: /* unlink ourselves from the active threads */
! 123: TAILQ_REMOVE(&p->p_p->ps_threads, p, p_thr_link);
! 124: #ifdef RTHREADS
! 125: if (TAILQ_EMPTY(&p->p_p->ps_threads))
! 126: wakeup(&p->p_p->ps_threads);
! 127: /*
! 128: * if one thread calls exit, we take down everybody.
! 129: * we have to be careful not to get recursively caught.
! 130: * this is kinda sick.
! 131: */
! 132: if (flags == EXIT_NORMAL && p->p_p->ps_mainproc != p &&
! 133: (p->p_p->ps_mainproc->p_flag & P_WEXIT) == 0) {
! 134: /*
! 135: * we are one of the threads. we SIGKILL the parent,
! 136: * it will wake us up again, then we proceed.
! 137: */
! 138: atomic_setbits_int(&p->p_p->ps_mainproc->p_flag, P_IGNEXITRV);
! 139: p->p_p->ps_mainproc->p_xstat = rv;
! 140: psignal(p->p_p->ps_mainproc, SIGKILL);
! 141: tsleep(p->p_p, PUSER, "thrdying", 0);
! 142: } else if (p == p->p_p->ps_mainproc) {
! 143: atomic_setbits_int(&p->p_flag, P_WEXIT);
! 144: if (flags == EXIT_NORMAL) {
! 145: q = TAILQ_FIRST(&p->p_p->ps_threads);
! 146: for (; q != NULL; q = nq) {
! 147: nq = TAILQ_NEXT(q, p_thr_link);
! 148: atomic_setbits_int(&q->p_flag, P_IGNEXITRV);
! 149: q->p_xstat = rv;
! 150: psignal(q, SIGKILL);
! 151: }
! 152: }
! 153: wakeup(p->p_p);
! 154: while (!TAILQ_EMPTY(&p->p_p->ps_threads))
! 155: tsleep(&p->p_p->ps_threads, PUSER, "thrdeath", 0);
! 156: }
! 157: #endif
! 158:
! 159: if (p->p_flag & P_PROFIL)
! 160: stopprofclock(p);
! 161: p->p_ru = pool_get(&rusage_pool, PR_WAITOK);
! 162: /*
! 163: * If parent is waiting for us to exit or exec, P_PPWAIT is set; we
! 164: * wake up the parent early to avoid deadlock.
! 165: */
! 166: atomic_setbits_int(&p->p_flag, P_WEXIT);
! 167: atomic_clearbits_int(&p->p_flag, P_TRACED);
! 168: if (p->p_flag & P_PPWAIT) {
! 169: atomic_clearbits_int(&p->p_flag, P_PPWAIT);
! 170: wakeup(p->p_pptr);
! 171: }
! 172: p->p_sigignore = ~0;
! 173: p->p_siglist = 0;
! 174: timeout_del(&p->p_realit_to);
! 175: timeout_del(&p->p_stats->p_virt_to);
! 176: timeout_del(&p->p_stats->p_prof_to);
! 177:
! 178: /*
! 179: * Close open files and release open-file table.
! 180: * This may block!
! 181: */
! 182: fdfree(p);
! 183:
! 184: #ifdef SYSVSEM
! 185: semexit(p);
! 186: #endif
! 187: if (SESS_LEADER(p)) {
! 188: struct session *sp = p->p_session;
! 189:
! 190: if (sp->s_ttyvp) {
! 191: /*
! 192: * Controlling process.
! 193: * Signal foreground pgrp,
! 194: * drain controlling terminal
! 195: * and revoke access to controlling terminal.
! 196: */
! 197: if (sp->s_ttyp->t_session == sp) {
! 198: if (sp->s_ttyp->t_pgrp)
! 199: pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
! 200: (void) ttywait(sp->s_ttyp);
! 201: /*
! 202: * The tty could have been revoked
! 203: * if we blocked.
! 204: */
! 205: if (sp->s_ttyvp)
! 206: VOP_REVOKE(sp->s_ttyvp, REVOKEALL);
! 207: }
! 208: if (sp->s_ttyvp)
! 209: vrele(sp->s_ttyvp);
! 210: sp->s_ttyvp = NULL;
! 211: /*
! 212: * s_ttyp is not zero'd; we use this to indicate
! 213: * that the session once had a controlling terminal.
! 214: * (for logging and informational purposes)
! 215: */
! 216: }
! 217: sp->s_leader = NULL;
! 218: }
! 219: fixjobc(p, p->p_pgrp, 0);
! 220: #ifdef ACCOUNTING
! 221: (void)acct_process(p);
! 222: #endif
! 223: #ifdef KTRACE
! 224: /*
! 225: * release trace file
! 226: */
! 227: p->p_traceflag = 0; /* don't trace the vrele() */
! 228: if (p->p_tracep)
! 229: ktrsettracevnode(p, NULL);
! 230: #endif
! 231: #if NSYSTRACE > 0
! 232: if (ISSET(p->p_flag, P_SYSTRACE))
! 233: systrace_exit(p);
! 234: #endif
! 235: /*
! 236: * NOTE: WE ARE NO LONGER ALLOWED TO SLEEP!
! 237: */
! 238: p->p_stat = SDEAD;
! 239:
! 240: /*
! 241: * Remove proc from pidhash chain so looking it up won't
! 242: * work. Move it from allproc to zombproc, but do not yet
! 243: * wake up the reaper. We will put the proc on the
! 244: * deadproc list later (using the p_hash member), and
! 245: * wake up the reaper when we do.
! 246: */
! 247: LIST_REMOVE(p, p_hash);
! 248: LIST_REMOVE(p, p_list);
! 249: LIST_INSERT_HEAD(&zombproc, p, p_list);
! 250:
! 251: /*
! 252: * Give orphaned children to init(8).
! 253: */
! 254: q = LIST_FIRST(&p->p_children);
! 255: if (q) /* only need this if any child is S_ZOMB */
! 256: wakeup(initproc);
! 257: for (; q != 0; q = nq) {
! 258: nq = LIST_NEXT(q, p_sibling);
! 259: proc_reparent(q, initproc);
! 260: /*
! 261: * Traced processes are killed
! 262: * since their existence means someone is screwing up.
! 263: */
! 264: if (q->p_flag & P_TRACED) {
! 265: atomic_clearbits_int(&q->p_flag, P_TRACED);
! 266: psignal(q, SIGKILL);
! 267: }
! 268: }
! 269:
! 270:
! 271: /*
! 272: * Save exit status and final rusage info, adding in child rusage
! 273: * info and self times.
! 274: */
! 275: if (!(p->p_flag & P_IGNEXITRV))
! 276: p->p_xstat = rv;
! 277: *p->p_ru = p->p_stats->p_ru;
! 278: calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
! 279: ruadd(p->p_ru, &p->p_stats->p_cru);
! 280:
! 281: /*
! 282: * clear %cpu usage during swap
! 283: */
! 284: p->p_pctcpu = 0;
! 285:
! 286: /*
! 287: * notify interested parties of our demise.
! 288: */
! 289: KNOTE(&p->p_klist, NOTE_EXIT);
! 290:
! 291: /*
! 292: * Notify parent that we're gone. If we have P_NOZOMBIE or parent has
! 293: * the P_NOCLDWAIT flag set, notify process 1 instead (and hope it
! 294: * will handle this situation).
! 295: */
! 296: if ((p->p_flag & P_NOZOMBIE) || (p->p_pptr->p_flag & P_NOCLDWAIT)) {
! 297: struct proc *pp = p->p_pptr;
! 298: proc_reparent(p, initproc);
! 299: /*
! 300: * If this was the last child of our parent, notify
! 301: * parent, so in case he was wait(2)ing, he will
! 302: * continue.
! 303: */
! 304: if (LIST_EMPTY(&pp->p_children))
! 305: wakeup(pp);
! 306: }
! 307:
! 308: if (p->p_exitsig != 0)
! 309: psignal(p->p_pptr, P_EXITSIG(p));
! 310: wakeup(p->p_pptr);
! 311:
! 312: /*
! 313: * Release the process's signal state.
! 314: */
! 315: sigactsfree(p);
! 316:
! 317: /*
! 318: * Clear curproc after we've done all operations
! 319: * that could block, and before tearing down the rest
! 320: * of the process state that might be used from clock, etc.
! 321: * Also, can't clear curproc while we're still runnable,
! 322: * as we're not on a run queue (we are current, just not
! 323: * a proper proc any longer!).
! 324: *
! 325: * Other substructures are freed from wait().
! 326: */
! 327: curproc = NULL;
! 328:
! 329: /*
! 330: * If emulation has process exit hook, call it now.
! 331: */
! 332: if (p->p_emul->e_proc_exit)
! 333: (*p->p_emul->e_proc_exit)(p);
! 334:
! 335: /* This process no longer needs to hold the kernel lock. */
! 336: KERNEL_PROC_UNLOCK(p);
! 337:
! 338: /*
! 339: * Finally, call machine-dependent code to switch to a new
! 340: * context (possibly the idle context). Once we are no longer
! 341: * using the dead process's vmspace and stack, exit2() will be
! 342: * called to schedule those resources to be released by the
! 343: * reaper thread.
! 344: *
! 345: * Note that cpu_exit() will end with a call equivalent to
! 346: * cpu_switch(), finishing our execution (pun intended).
! 347: */
! 348: uvmexp.swtch++;
! 349: cpu_exit(p);
! 350: }
! 351:
! 352: /*
! 353: * Locking of this proclist is special; it's accessed in a
! 354: * critical section of process exit, and thus locking it can't
! 355: * modify interrupt state. We use a simple spin lock for this
! 356: * proclist. Processes on this proclist are also on zombproc;
! 357: * we use the p_hash member to linkup to deadproc.
! 358: */
! 359: struct mutex deadproc_mutex = MUTEX_INITIALIZER(IPL_NONE);
! 360: struct proclist deadproc = LIST_HEAD_INITIALIZER(deadproc);
! 361:
! 362: /*
! 363: * We are called from cpu_exit() once it is safe to schedule the
! 364: * dead process's resources to be freed.
! 365: *
! 366: * NOTE: One must be careful with locking in this routine. It's
! 367: * called from a critical section in machine-dependent code, so
! 368: * we should refrain from changing any interrupt state.
! 369: *
! 370: * We lock the deadproc list, place the proc on that list (using
! 371: * the p_hash member), and wake up the reaper.
! 372: */
! 373: void
! 374: exit2(struct proc *p)
! 375: {
! 376: int s;
! 377:
! 378: mtx_enter(&deadproc_mutex);
! 379: LIST_INSERT_HEAD(&deadproc, p, p_hash);
! 380: mtx_leave(&deadproc_mutex);
! 381:
! 382: wakeup(&deadproc);
! 383:
! 384: SCHED_LOCK(s);
! 385: }
! 386:
! 387: /*
! 388: * Process reaper. This is run by a kernel thread to free the resources
! 389: * of a dead process. Once the resources are free, the process becomes
! 390: * a zombie, and the parent is allowed to read the undead's status.
! 391: */
! 392: void
! 393: reaper(void)
! 394: {
! 395: struct proc *p;
! 396:
! 397: KERNEL_PROC_UNLOCK(curproc);
! 398:
! 399: for (;;) {
! 400: mtx_enter(&deadproc_mutex);
! 401: p = LIST_FIRST(&deadproc);
! 402: if (p == NULL) {
! 403: /* No work for us; go to sleep until someone exits. */
! 404: mtx_leave(&deadproc_mutex);
! 405: (void) tsleep(&deadproc, PVM, "reaper", 0);
! 406: continue;
! 407: }
! 408:
! 409: /* Remove us from the deadproc list. */
! 410: LIST_REMOVE(p, p_hash);
! 411: mtx_leave(&deadproc_mutex);
! 412: KERNEL_PROC_LOCK(curproc);
! 413:
! 414: /*
! 415: * Give machine-dependent code a chance to free any
! 416: * resources it couldn't free while still running on
! 417: * that process's context. This must be done before
! 418: * uvm_exit(), in case these resources are in the PCB.
! 419: */
! 420: cpu_wait(p);
! 421:
! 422: /*
! 423: * Free the VM resources we're still holding on to.
! 424: * We must do this from a valid thread because doing
! 425: * so may block.
! 426: */
! 427: uvm_exit(p);
! 428:
! 429: /* Process is now a true zombie. */
! 430: if ((p->p_flag & P_NOZOMBIE) == 0) {
! 431: p->p_stat = SZOMB;
! 432:
! 433: /* Wake up the parent so it can get exit status. */
! 434: psignal(p->p_pptr, SIGCHLD);
! 435: wakeup(p->p_pptr);
! 436: } else {
! 437: /* Noone will wait for us. Just zap the process now */
! 438: proc_zap(p);
! 439: }
! 440:
! 441: KERNEL_PROC_UNLOCK(curproc);
! 442: }
! 443: }
! 444:
! 445: pid_t
! 446: sys_wait4(struct proc *q, void *v, register_t *retval)
! 447: {
! 448: struct sys_wait4_args /* {
! 449: syscallarg(pid_t) pid;
! 450: syscallarg(int *) status;
! 451: syscallarg(int) options;
! 452: syscallarg(struct rusage *) rusage;
! 453: } */ *uap = v;
! 454: int nfound;
! 455: struct proc *p, *t;
! 456: int status, error;
! 457:
! 458: if (SCARG(uap, pid) == 0)
! 459: SCARG(uap, pid) = -q->p_pgid;
! 460: if (SCARG(uap, options) &~ (WUNTRACED|WNOHANG|WALTSIG|WCONTINUED))
! 461: return (EINVAL);
! 462:
! 463: loop:
! 464: nfound = 0;
! 465: LIST_FOREACH(p, &q->p_children, p_sibling) {
! 466: if ((p->p_flag & P_NOZOMBIE) ||
! 467: (SCARG(uap, pid) != WAIT_ANY &&
! 468: p->p_pid != SCARG(uap, pid) &&
! 469: p->p_pgid != -SCARG(uap, pid)))
! 470: continue;
! 471:
! 472: /*
! 473: * Wait for processes with p_exitsig != SIGCHLD processes only
! 474: * if WALTSIG is set; wait for processes with pexitsig ==
! 475: * SIGCHLD only if WALTSIG is clear.
! 476: */
! 477: if ((SCARG(uap, options) & WALTSIG) ?
! 478: (p->p_exitsig == SIGCHLD) : (P_EXITSIG(p) != SIGCHLD))
! 479: continue;
! 480:
! 481: nfound++;
! 482: if (p->p_stat == SZOMB) {
! 483: retval[0] = p->p_pid;
! 484:
! 485: if (SCARG(uap, status)) {
! 486: status = p->p_xstat; /* convert to int */
! 487: error = copyout(&status,
! 488: SCARG(uap, status), sizeof(status));
! 489: if (error)
! 490: return (error);
! 491: }
! 492: if (SCARG(uap, rusage) &&
! 493: (error = copyout(p->p_ru,
! 494: SCARG(uap, rusage), sizeof(struct rusage))))
! 495: return (error);
! 496:
! 497: /*
! 498: * If we got the child via a ptrace 'attach',
! 499: * we need to give it back to the old parent.
! 500: */
! 501: if (p->p_oppid && (t = pfind(p->p_oppid))) {
! 502: p->p_oppid = 0;
! 503: proc_reparent(p, t);
! 504: if (p->p_exitsig != 0)
! 505: psignal(t, P_EXITSIG(p));
! 506: wakeup(t);
! 507: return (0);
! 508: }
! 509:
! 510: scheduler_wait_hook(q, p);
! 511: p->p_xstat = 0;
! 512: ruadd(&q->p_stats->p_cru, p->p_ru);
! 513:
! 514: proc_zap(p);
! 515:
! 516: return (0);
! 517: }
! 518: if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
! 519: (p->p_flag & P_TRACED || SCARG(uap, options) & WUNTRACED)) {
! 520: atomic_setbits_int(&p->p_flag, P_WAITED);
! 521: retval[0] = p->p_pid;
! 522:
! 523: if (SCARG(uap, status)) {
! 524: status = W_STOPCODE(p->p_xstat);
! 525: error = copyout(&status, SCARG(uap, status),
! 526: sizeof(status));
! 527: } else
! 528: error = 0;
! 529: return (error);
! 530: }
! 531: if ((SCARG(uap, options) & WCONTINUED) && (p->p_flag & P_CONTINUED)) {
! 532: atomic_clearbits_int(&p->p_flag, P_CONTINUED);
! 533: retval[0] = p->p_pid;
! 534:
! 535: if (SCARG(uap, status)) {
! 536: status = _WCONTINUED;
! 537: error = copyout(&status, SCARG(uap, status),
! 538: sizeof(status));
! 539: } else
! 540: error = 0;
! 541: return (error);
! 542: }
! 543: }
! 544: if (nfound == 0)
! 545: return (ECHILD);
! 546: if (SCARG(uap, options) & WNOHANG) {
! 547: retval[0] = 0;
! 548: return (0);
! 549: }
! 550: if ((error = tsleep(q, PWAIT | PCATCH, "wait", 0)) != 0)
! 551: return (error);
! 552: goto loop;
! 553: }
! 554:
! 555: /*
! 556: * make process 'parent' the new parent of process 'child'.
! 557: */
! 558: void
! 559: proc_reparent(struct proc *child, struct proc *parent)
! 560: {
! 561:
! 562: if (child->p_pptr == parent)
! 563: return;
! 564:
! 565: if (parent == initproc)
! 566: child->p_exitsig = SIGCHLD;
! 567:
! 568: LIST_REMOVE(child, p_sibling);
! 569: LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
! 570: child->p_pptr = parent;
! 571: }
! 572:
! 573: void
! 574: proc_zap(struct proc *p)
! 575: {
! 576: pool_put(&rusage_pool, p->p_ru);
! 577: if (p->p_ptstat)
! 578: free(p->p_ptstat, M_SUBPROC);
! 579:
! 580: /*
! 581: * Finally finished with old proc entry.
! 582: * Unlink it from its process group and free it.
! 583: */
! 584: leavepgrp(p);
! 585: LIST_REMOVE(p, p_list); /* off zombproc */
! 586: LIST_REMOVE(p, p_sibling);
! 587:
! 588: /*
! 589: * Decrement the count of procs running with this uid.
! 590: */
! 591: (void)chgproccnt(p->p_cred->p_ruid, -1);
! 592:
! 593: /*
! 594: * Release reference to text vnode
! 595: */
! 596: if (p->p_textvp)
! 597: vrele(p->p_textvp);
! 598:
! 599: /*
! 600: * Remove us from our process list, possibly killing the process
! 601: * in the process (pun intended).
! 602: */
! 603: #if 0
! 604: TAILQ_REMOVE(&p->p_p->ps_threads, p, p_thr_link);
! 605: #endif
! 606: if (TAILQ_EMPTY(&p->p_p->ps_threads)) {
! 607: limfree(p->p_p->ps_limit);
! 608: if (--p->p_p->ps_cred->p_refcnt == 0) {
! 609: crfree(p->p_p->ps_cred->pc_ucred);
! 610: pool_put(&pcred_pool, p->p_p->ps_cred);
! 611: }
! 612: pool_put(&process_pool, p->p_p);
! 613: }
! 614:
! 615: pool_put(&proc_pool, p);
! 616: nprocs--;
! 617: }
! 618:
CVSweb