|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1982, 1986, 1989, 1991, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * (c) UNIX System Laboratories, Inc. ! 27: * All or some portions of this file are derived from material licensed ! 28: * to the University of California by American Telephone and Telegraph ! 29: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 30: * the permission of UNIX System Laboratories, Inc. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94 ! 61: */ ! 62: ! 63: #include <machine/reg.h> ! 64: #include <machine/psl.h> ! 65: ! 66: #include "compat_43.h" ! 67: ! 68: #include <sys/param.h> ! 69: #include <sys/systm.h> ! 70: #include <sys/ioctl.h> ! 71: #include <sys/proc.h> ! 72: #include <sys/tty.h> ! 73: #include <sys/time.h> ! 74: #include <sys/resource.h> ! 75: #include <sys/kernel.h> ! 76: #include <sys/buf.h> ! 77: #include <sys/wait.h> ! 78: #include <sys/file.h> ! 79: #include <sys/vnode.h> ! 80: #include <sys/syslog.h> ! 81: #include <sys/malloc.h> ! 82: #include <sys/resourcevar.h> ! 83: #include <sys/ptrace.h> ! 84: #include <sys/user.h> ! 85: ! 86: #include <mach/mach_types.h> ! 87: #include <kern/thread.h> ! 88: #include <kern/thread_act.h> ! 89: #include <kern/assert.h> ! 90: ! 91: void exit1 __P((struct proc *, int)); ! 92: ! 93: /* ! 94: * exit -- ! 95: * Death of process. ! 96: */ ! 97: struct exit_args { ! 98: int rval; ! 99: }; ! 100: void ! 101: exit(p, uap, retval) ! 102: struct proc *p; ! 103: struct exit_args *uap; ! 104: int *retval; ! 105: { ! 106: exit1(p, W_EXITCODE(uap->rval, 0)); ! 107: ! 108: thread_exception_return(); ! 109: /* NOTREACHED */ ! 110: while (TRUE) ! 111: thread_block(0); ! 112: /* NOTREACHED */ ! 113: } ! 114: ! 115: /* ! 116: * Exit: deallocate address space and other resources, change proc state ! 117: * to zombie, and unlink proc from allproc and parent's lists. Save exit ! 118: * status and rusage for wait(). Check for child processes and orphan them. ! 119: */ ! 120: void ! 121: exit1(p, rv) ! 122: register struct proc *p; ! 123: int rv; ! 124: { ! 125: register struct proc *q, *nq; ! 126: thread_t self = current_thread(); ! 127: thread_act_t th_act_self = current_act(); ! 128: struct task *task = p->task; ! 129: register int i,s; ! 130: struct uthread *ut; ! 131: ! 132: /* ! 133: * If a thread in this task has already ! 134: * called exit(), then halt any others ! 135: * right here. ! 136: */ ! 137: while (p->exit_thread != self) { ! 138: if (sig_try_lock(p) <= 0) { ! 139: if (get_threadtask(th_act_self) != task) ! 140: return; ! 141: while (TRUE) { ! 142: thread_terminate_self(); ! 143: /* NOTREACHED */ ! 144: } ! 145: } ! 146: sig_lock_to_exit(p); ! 147: } ! 148: if (p->p_pid == 1) { ! 149: printf("pid 1 exited (signal %d, exit %d)", ! 150: WTERMSIG(rv), WEXITSTATUS(rv)); ! 151: panic("init died"); ! 152: } ! 153: ! 154: s = splsched(); ! 155: p->p_flag |= P_WEXIT; ! 156: splx(s); ! 157: proc_prepareexit(p); ! 158: p->p_xstat = rv; ! 159: ! 160: /* task terminate will call proc_terminate and that cleans it up */ ! 161: task_terminate_internal(task); ! 162: ! 163: /* ! 164: * we come back and returns to AST which ! 165: * should cleanup the rest ! 166: */ ! 167: #if 0 ! 168: if (task == current_task()) { ! 169: thread_exception_return(); ! 170: /*NOTREACHED*/ ! 171: } ! 172: ! 173: while (task == current_task()) { ! 174: thread_terminate_self(); ! 175: /*NOTREACHED*/ ! 176: } ! 177: #endif ! 178: } ! 179: ! 180: void ! 181: proc_prepareexit(struct proc *p) ! 182: { ! 183: int s; ! 184: struct uthread *ut; ! 185: thread_t self = current_thread(); ! 186: thread_act_t th_act_self = current_act(); ! 187: ! 188: ! 189: /* ! 190: * Remove proc from allproc queue and from pidhash chain. ! 191: * Need to do this before we do anything that can block. ! 192: * Not doing causes things like mount() find this on allproc ! 193: * in partially cleaned state. ! 194: */ ! 195: LIST_REMOVE(p, p_list); ! 196: LIST_REMOVE(p, p_hash); ! 197: ! 198: #ifdef PGINPROF ! 199: vmsizmon(); ! 200: #endif ! 201: /* ! 202: * If parent is waiting for us to exit or exec, ! 203: * P_PPWAIT is set; we will wakeup the parent below. ! 204: */ ! 205: p->p_flag &= ~(P_TRACED | P_PPWAIT); ! 206: p->p_sigignore = ~0; ! 207: p->p_siglist = 0; ! 208: ut = get_bsdthread_info(th_act_self); ! 209: ut->uu_sig = 0; ! 210: untimeout(realitexpire, (caddr_t)p); ! 211: ! 212: } ! 213: ! 214: void ! 215: proc_exit(struct proc *p) ! 216: { ! 217: register struct proc *q, *nq; ! 218: thread_t self = current_thread(); ! 219: thread_act_t th_act_self = current_act(); ! 220: struct task *task = p->task; ! 221: register int i,s; ! 222: struct uthread *ut; ! 223: boolean_t funnel_state; ! 224: ! 225: /* This can happen if thread_terminate of the single thread ! 226: * process ! 227: */ ! 228: ! 229: funnel_state = thread_set_funneled(TRUE); ! 230: if( !(p->p_flag & P_WEXIT)) { ! 231: s = splsched(); ! 232: p->p_flag |= P_WEXIT; ! 233: splx(s); ! 234: proc_prepareexit(p); ! 235: } ! 236: ! 237: MALLOC_ZONE(p->p_ru, struct rusage *, ! 238: sizeof (*p->p_ru), M_ZOMBIE, M_WAITOK); ! 239: ! 240: /* ! 241: * Close open files and release open-file table. ! 242: * This may block! ! 243: */ ! 244: fdfree(p); ! 245: ! 246: /* Close ref SYSV Shared memory*/ ! 247: if (p->vm_shm) ! 248: shmexit(p); ! 249: ! 250: if (SESS_LEADER(p)) { ! 251: register struct session *sp = p->p_session; ! 252: ! 253: if (sp->s_ttyvp) { ! 254: /* ! 255: * Controlling process. ! 256: * Signal foreground pgrp, ! 257: * drain controlling terminal ! 258: * and revoke access to controlling terminal. ! 259: */ ! 260: if (sp->s_ttyp->t_session == sp) { ! 261: if (sp->s_ttyp->t_pgrp) ! 262: pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1); ! 263: (void) ttywait(sp->s_ttyp); ! 264: /* ! 265: * The tty could have been revoked ! 266: * if we blocked. ! 267: */ ! 268: if (sp->s_ttyvp) ! 269: VOP_REVOKE(sp->s_ttyvp, REVOKEALL); ! 270: } ! 271: if (sp->s_ttyvp) ! 272: vrele(sp->s_ttyvp); ! 273: sp->s_ttyvp = NULL; ! 274: /* ! 275: * s_ttyp is not zero'd; we use this to indicate ! 276: * that the session once had a controlling terminal. ! 277: * (for logging and informational purposes) ! 278: */ ! 279: } ! 280: sp->s_leader = NULL; ! 281: } ! 282: ! 283: fixjobc(p, p->p_pgrp, 0); ! 284: p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; ! 285: #if KTRACE ! 286: /* ! 287: * release trace file ! 288: */ ! 289: p->p_traceflag = 0; /* don't trace the vrele() */ ! 290: if (p->p_tracep) ! 291: vrele(p->p_tracep); ! 292: #endif ! 293: ! 294: ! 295: q = p->p_children.lh_first; ! 296: if (q) /* only need this if any child is S_ZOMB */ ! 297: wakeup((caddr_t) initproc); ! 298: for (; q != 0; q = nq) { ! 299: nq = q->p_sibling.le_next; ! 300: proc_reparent(q, initproc); ! 301: /* ! 302: * Traced processes are killed ! 303: * since their existence means someone is messing up. ! 304: */ ! 305: if (q->p_flag & P_TRACED) { ! 306: q->p_flag &= ~P_TRACED; ! 307: if (q->sigwait_thread) { ! 308: thread_t sig_shuttle = getshuttle_thread(q->sigwait_thread); ! 309: /* ! 310: * The sigwait_thread could be stopped at a ! 311: * breakpoint. Wake it up to kill. ! 312: * Need to do this as it could be a thread which is not ! 313: * the first thread in the task. So any attempts to kill ! 314: * the process would result into a deadlock on q->sigwait. ! 315: */ ! 316: thread_resume((struct thread *)q->sigwait_thread); ! 317: clear_wait(sig_shuttle, THREAD_INTERRUPTED, FALSE); ! 318: threadsignal(q->sigwait_thread, SIGKILL, 0); ! 319: } ! 320: psignal(q, SIGKILL); ! 321: } ! 322: } ! 323: ! 324: ! 325: /* ! 326: * Save exit status and final rusage info, adding in child rusage ! 327: * info and self times. ! 328: */ ! 329: *p->p_ru = p->p_stats->p_ru; ! 330: ! 331: timerclear(&p->p_ru->ru_utime); ! 332: timerclear(&p->p_ru->ru_stime); ! 333: ! 334: if (task) { ! 335: task_basic_info_data_t tinfo; ! 336: int task_info_stuff = TASK_BASIC_INFO_COUNT; ! 337: ! 338: task_info(task, TASK_BASIC_INFO,&tinfo, &task_info_stuff); ! 339: p->p_ru->ru_utime.tv_sec = tinfo.user_time.seconds; ! 340: p->p_ru->ru_utime.tv_usec = tinfo.user_time.microseconds; ! 341: p->p_ru->ru_stime.tv_sec = tinfo.system_time.seconds; ! 342: p->p_ru->ru_stime.tv_usec = tinfo.system_time.microseconds; ! 343: } ! 344: ! 345: ! 346: ruadd(p->p_ru, &p->p_stats->p_cru); ! 347: ! 348: /* ! 349: * Free up profiling buffers. ! 350: */ ! 351: { ! 352: struct uprof *p0 = &p->p_stats->p_prof, *p1, *pn; ! 353: ! 354: p1 = p0->pr_next; ! 355: p0->pr_next = NULL; ! 356: p0->pr_scale = 0; ! 357: ! 358: for (; p1 != NULL; p1 = pn) { ! 359: pn = p1->pr_next; ! 360: kfree((vm_offset_t)p1, sizeof *p1); ! 361: } ! 362: } ! 363: ! 364: ! 365: /* Place onto zombproc. */ ! 366: LIST_INSERT_HEAD(&zombproc, p, p_list); ! 367: p->p_stat = SZOMB; ! 368: ! 369: /* ! 370: * Notify parent that we're gone. ! 371: */ ! 372: psignal(p->p_pptr, SIGCHLD); ! 373: wakeup((caddr_t)p->p_pptr); ! 374: ! 375: /* ! 376: * Notify procfs debugger ! 377: */ ! 378: if (p->p_flag & P_FSTRACE) ! 379: wakeup((caddr_t)p); ! 380: ! 381: /* ! 382: * Other substructures are freed from wait(). ! 383: */ ! 384: FREE_ZONE(p->p_stats, sizeof *p->p_stats, M_SUBPROC); ! 385: p->p_stats = NULL; ! 386: ! 387: FREE_ZONE(p->p_sigacts, sizeof *p->p_sigacts, M_SUBPROC); ! 388: p->p_sigacts = NULL; ! 389: ! 390: if (--p->p_limit->p_refcnt == 0) ! 391: FREE_ZONE(p->p_limit, sizeof *p->p_limit, M_SUBPROC); ! 392: p->p_limit = NULL; ! 393: ! 394: /* ! 395: * Finish up by terminating the task ! 396: * and halt this thread (only if a ! 397: * member of the task exiting). ! 398: */ ! 399: p->task = TASK_NULL; ! 400: //task->proc = NULL; ! 401: set_bsdtask_info(task, NULL); ! 402: ! 403: (void) thread_set_funneled(funnel_state); ! 404: } ! 405: ! 406: ! 407: struct wait4_args { ! 408: int pid; ! 409: int *status; ! 410: int options; ! 411: struct rusage *rusage; ! 412: }; ! 413: ! 414: #if COMPAT_43 ! 415: int ! 416: owait(p, uap, retval) ! 417: struct proc *p; ! 418: void *uap; ! 419: int *retval; ! 420: { ! 421: struct wait4_args *a; ! 422: ! 423: a = (struct wait4_args *)get_bsduthreadarg(current_act()); ! 424: ! 425: a->options = 0; ! 426: a->rusage = NULL; ! 427: a->pid = WAIT_ANY; ! 428: a->status = NULL; ! 429: return (wait1(p, a, retval, 1)); ! 430: } ! 431: ! 432: int ! 433: wait4(p, uap, retval) ! 434: struct proc *p; ! 435: struct wait4_args *uap; ! 436: int *retval; ! 437: { ! 438: ! 439: return (wait1(p, uap, retval, 0)); ! 440: } ! 441: ! 442: struct owait3_args { ! 443: int *status; ! 444: int options; ! 445: struct rusage *rusage; ! 446: }; ! 447: ! 448: int ! 449: owait3(p, uap, retval) ! 450: struct proc *p; ! 451: struct owait3_args *uap; ! 452: int *retval; ! 453: { ! 454: struct wait4_args *a; ! 455: ! 456: a = (struct wait4_args *)get_bsduthreadarg(current_act); ! 457: ! 458: a->rusage = uap->rusage; ! 459: a->options = uap->options; ! 460: a->status = uap->status; ! 461: a->pid = WAIT_ANY; ! 462: ! 463: return (wait1(p, a, retval, 1)); ! 464: } ! 465: ! 466: #else ! 467: #define wait1 wait4 ! 468: #endif ! 469: ! 470: int ! 471: wait1continue(result) ! 472: { ! 473: void * p, *vt; ! 474: thread_act_t thread; ! 475: struct uthread *ut; ! 476: int *retval; ! 477: ! 478: if (result != 0) { ! 479: return(result); ! 480: } ! 481: ! 482: thread = current_act(); ! 483: p = get_bsdtask_info(current_task()); ! 484: ut = get_bsdthread_info(thread); ! 485: vt = get_bsduthreadarg(thread); ! 486: retval = get_bsduthreadrval(thread); ! 487: wait1((struct proc *)p, (struct wait4_args *)vt, retval, 0); ! 488: } ! 489: ! 490: int ! 491: wait1(q, uap, retval, compat) ! 492: register struct proc *q; ! 493: register struct wait4_args *uap; ! 494: register_t *retval; ! 495: #if COMPAT_43 ! 496: int compat; ! 497: #endif ! 498: { ! 499: register int nfound; ! 500: register struct proc *p, *t; ! 501: int status, error; ! 502: ! 503: if (uap->pid == 0) ! 504: uap->pid = -q->p_pgid; ! 505: ! 506: loop: ! 507: nfound = 0; ! 508: for (p = q->p_children.lh_first; p != 0; p = p->p_sibling.le_next) { ! 509: if (uap->pid != WAIT_ANY && ! 510: p->p_pid != uap->pid && ! 511: p->p_pgid != -(uap->pid)) ! 512: continue; ! 513: nfound++; ! 514: if (p->p_stat == SZOMB) { ! 515: retval[0] = p->p_pid; ! 516: #if COMPAT_43 ! 517: if (compat) ! 518: retval[1] = p->p_xstat; ! 519: else ! 520: #endif ! 521: if (uap->status) { ! 522: status = p->p_xstat; /* convert to int */ ! 523: if (error = copyout((caddr_t)&status, ! 524: (caddr_t)uap->status, ! 525: sizeof(status))) ! 526: return (error); ! 527: } ! 528: if (uap->rusage && ! 529: (error = copyout((caddr_t)p->p_ru, ! 530: (caddr_t)uap->rusage, ! 531: sizeof (struct rusage)))) ! 532: return (error); ! 533: /* ! 534: * If we got the child via a ptrace 'attach', ! 535: * we need to give it back to the old parent. ! 536: */ ! 537: if (p->p_oppid && (t = pfind(p->p_oppid))) { ! 538: p->p_oppid = 0; ! 539: proc_reparent(p, t); ! 540: psignal(t, SIGCHLD); ! 541: wakeup((caddr_t)t); ! 542: return (0); ! 543: } ! 544: p->p_xstat = 0; ! 545: if (p->p_ru) { ! 546: ruadd(&q->p_stats->p_cru, p->p_ru); ! 547: FREE_ZONE(p->p_ru, sizeof *p->p_ru, M_ZOMBIE); ! 548: p->p_ru = NULL; ! 549: } else { ! 550: printf("Warning : lost p_ru for %s\n", p->p_comm); ! 551: } ! 552: ! 553: /* ! 554: * Decrement the count of procs running with this uid. ! 555: */ ! 556: (void)chgproccnt(p->p_cred->p_ruid, -1); ! 557: ! 558: /* ! 559: * Free up credentials. ! 560: */ ! 561: if (--p->p_cred->p_refcnt == 0) { ! 562: struct ucred *ucr = p->p_ucred; ! 563: struct pcred *pcr; ! 564: ! 565: if (ucr != NOCRED) { ! 566: p->p_ucred = NOCRED; ! 567: crfree(ucr); ! 568: } ! 569: pcr = p->p_cred; ! 570: p->p_cred = NULL; ! 571: FREE_ZONE(pcr, sizeof *pcr, M_SUBPROC); ! 572: } ! 573: ! 574: /* ! 575: * Release reference to text vnode ! 576: */ ! 577: if (p->p_textvp) ! 578: vrele(p->p_textvp); ! 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: FREE_ZONE(p, sizeof *p, M_PROC); ! 588: nprocs--; ! 589: return (0); ! 590: } ! 591: if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 && ! 592: (p->p_flag & P_TRACED || uap->options & WUNTRACED)) { ! 593: p->p_flag |= P_WAITED; ! 594: retval[0] = p->p_pid; ! 595: #if COMPAT_43 ! 596: if (compat) { ! 597: retval[1] = W_STOPCODE(p->p_xstat); ! 598: error = 0; ! 599: } else ! 600: #endif ! 601: if (uap->status) { ! 602: status = W_STOPCODE(p->p_xstat); ! 603: error = copyout((caddr_t)&status, ! 604: (caddr_t)uap->status, ! 605: sizeof(status)); ! 606: } else ! 607: error = 0; ! 608: return (error); ! 609: } ! 610: } ! 611: if (nfound == 0) ! 612: return (ECHILD); ! 613: if (uap->options & WNOHANG) { ! 614: retval[0] = 0; ! 615: return (0); ! 616: } ! 617: ! 618: if (error = tsleep0((caddr_t)q, PWAIT | PCATCH, "wait", 0, wait1continue)) { ! 619: return (error); ! 620: } ! 621: goto loop; ! 622: } ! 623: ! 624: /* ! 625: * make process 'parent' the new parent of process 'child'. ! 626: */ ! 627: void ! 628: proc_reparent(child, parent) ! 629: register struct proc *child; ! 630: register struct proc *parent; ! 631: { ! 632: ! 633: if (child->p_pptr == parent) ! 634: return; ! 635: ! 636: LIST_REMOVE(child, p_sibling); ! 637: LIST_INSERT_HEAD(&parent->p_children, child, p_sibling); ! 638: child->p_pptr = parent; ! 639: } ! 640: ! 641: kern_return_t ! 642: init_process(void) ! 643: /* ! 644: * Make the current process an "init" process, meaning ! 645: * that it doesn't have a parent, and that it won't be ! 646: * gunned down by kill(-1, 0). ! 647: */ ! 648: { ! 649: register struct proc *p = current_proc(); ! 650: ! 651: if (suser(p->p_ucred, &p->p_acflag)) ! 652: return(KERN_NO_ACCESS); ! 653: ! 654: if (p->p_pid != 1 && p->p_pgid != p->p_pid) ! 655: enterpgrp(p, p->p_pid, 0); ! 656: p->p_flag |= P_SYSTEM; ! 657: ! 658: /* ! 659: * Take us out of the sibling chain, and ! 660: * out of our parent's child chain. ! 661: */ ! 662: LIST_REMOVE(p, p_sibling); ! 663: p->p_sibling.le_prev = NULL; ! 664: p->p_sibling.le_next = NULL; ! 665: p->p_pptr = kernproc; ! 666: ! 667: return(KERN_SUCCESS); ! 668: } ! 669: ! 670: void ! 671: process_terminate_self(void) ! 672: { ! 673: struct proc *p = current_proc(); ! 674: ! 675: if (p != NULL) { ! 676: exit1(p, W_EXITCODE(0, SIGKILL)); ! 677: /*NOTREACHED*/ ! 678: } ! 679: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.