The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_exit.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1982, 1986, 1989, 1991, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  * (c) UNIX System Laboratories, Inc.
    5  * All or some portions of this file are derived from material licensed
    6  * to the University of California by American Telephone and Telegraph
    7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
    8  * the permission of UNIX System Laboratories, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the University of
   21  *      California, Berkeley and its contributors.
   22  * 4. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  *
   38  *      @(#)kern_exit.c 8.7 (Berkeley) 2/12/94
   39  * $FreeBSD$
   40  */
   41 
   42 #include "opt_compat.h"
   43 #include "opt_ktrace.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/sysproto.h>
   48 #include <sys/kernel.h>
   49 #include <sys/malloc.h>
   50 #include <sys/proc.h>
   51 #include <sys/pioctl.h>
   52 #include <sys/tty.h>
   53 #include <sys/wait.h>
   54 #include <sys/vnode.h>
   55 #include <sys/resourcevar.h>
   56 #include <sys/signalvar.h>
   57 #include <sys/ptrace.h>
   58 #include <sys/acct.h>           /* for acct_process() function prototype */
   59 #include <sys/filedesc.h>
   60 #include <sys/shm.h>
   61 #include <sys/sem.h>
   62 #include <sys/aio.h>
   63 #include <sys/jail.h>
   64 
   65 #include <vm/vm.h>
   66 #include <vm/vm_param.h>
   67 #include <sys/lock.h>
   68 #include <vm/pmap.h>
   69 #include <vm/vm_map.h>
   70 #include <vm/vm_zone.h>
   71 #include <vm/vm_extern.h>
   72 #include <sys/user.h>
   73 
   74 /* Required to be non-static for SysVR4 emulator */
   75 MALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status");
   76 
   77 static MALLOC_DEFINE(M_ATEXIT, "atexit", "atexit callback");
   78 
   79 static int wait1 __P((struct proc *, struct wait_args *, int));
   80 
   81 /*
   82  * callout list for things to do at exit time
   83  */
   84 struct exitlist {
   85         exitlist_fn function;
   86         TAILQ_ENTRY(exitlist) next;
   87 };
   88 
   89 TAILQ_HEAD(exit_list_head, exitlist);
   90 static struct exit_list_head exit_list = TAILQ_HEAD_INITIALIZER(exit_list);
   91 
   92 /*
   93  * exit --
   94  *      Death of process.
   95  */
   96 void
   97 sys_exit(p, uap)
   98         struct proc *p;
   99         struct sys_exit_args /* {
  100                 int     rval;
  101         } */ *uap;
  102 {
  103 
  104         exit1(p, W_EXITCODE(uap->rval, 0));
  105         /* NOTREACHED */
  106 }
  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(p, rv)
  115         register struct proc *p;
  116         int rv;
  117 {
  118         register struct proc *q, *nq;
  119         register struct vmspace *vm;
  120         struct vnode *vtmp;
  121         struct exitlist *ep;
  122 
  123         if (p->p_pid == 1) {
  124                 printf("init died (signal %d, exit %d)\n",
  125                     WTERMSIG(rv), WEXITSTATUS(rv));
  126                 panic("Going nowhere without my init!");
  127         }
  128 
  129         aio_proc_rundown(p);
  130 
  131         /* are we a task leader? */
  132         if(p == p->p_leader) {
  133                 struct kill_args killArgs;
  134                 killArgs.signum = SIGKILL;
  135                 q = p->p_peers;
  136                 while(q) {
  137                         killArgs.pid = q->p_pid;
  138                         /*
  139                          * The interface for kill is better
  140                          * than the internal signal
  141                          */
  142                         kill(p, &killArgs);
  143                         nq = q;
  144                         q = q->p_peers;
  145                 }
  146                 while (p->p_peers) 
  147                   tsleep((caddr_t)p, PWAIT, "exit1", 0);
  148         } 
  149 
  150 #ifdef PGINPROF
  151         vmsizmon();
  152 #endif
  153         STOPEVENT(p, S_EXIT, rv);
  154         wakeup(&p->p_stype);    /* Wakeup anyone in procfs' PIOCWAIT */
  155 
  156         /* 
  157          * Check if any loadable modules need anything done at process exit.
  158          * e.g. SYSV IPC stuff
  159          * XXX what if one of these generates an error?
  160          */
  161         TAILQ_FOREACH(ep, &exit_list, next) 
  162                 (*ep->function)(p);
  163 
  164         if (p->p_flag & P_PROFIL)
  165                 stopprofclock(p);
  166         MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
  167                 M_ZOMBIE, M_WAITOK);
  168         /*
  169          * If parent is waiting for us to exit or exec,
  170          * P_PPWAIT is set; we will wakeup the parent below.
  171          */
  172         p->p_flag &= ~(P_TRACED | P_PPWAIT);
  173         p->p_flag |= P_WEXIT;
  174         SIGEMPTYSET(p->p_siglist);
  175         if (timevalisset(&p->p_realtimer.it_value))
  176                 untimeout(realitexpire, (caddr_t)p, p->p_ithandle);
  177 
  178         /*
  179          * Reset any sigio structures pointing to us as a result of
  180          * F_SETOWN with our pid.
  181          */
  182         funsetownlst(&p->p_sigiolst);
  183 
  184         /*
  185          * Close open files and release open-file table.
  186          * This may block!
  187          */
  188         fdfree(p);
  189 
  190         if(p->p_leader->p_peers) {
  191                 q = p->p_leader;
  192                 while(q->p_peers != p)
  193                         q = q->p_peers;
  194                 q->p_peers = p->p_peers;
  195                 wakeup((caddr_t)p->p_leader);
  196         }
  197 
  198         /*
  199          * XXX Shutdown SYSV semaphores
  200          */
  201         semexit(p);
  202 
  203         /* The next two chunks should probably be moved to vmspace_exit. */
  204         vm = p->p_vmspace;
  205         /*
  206          * Release user portion of address space.
  207          * This releases references to vnodes,
  208          * which could cause I/O if the file has been unlinked.
  209          * Need to do this early enough that we can still sleep.
  210          * Can't free the entire vmspace as the kernel stack
  211          * may be mapped within that space also.
  212          *
  213          * Processes sharing the same vmspace may exit in one order, and
  214          * get cleaned up by vmspace_exit() in a different order.  The
  215          * last exiting process to reach this point releases as much of
  216          * the environment as it can, and the last process cleaned up
  217          * by vmspace_exit() (which decrements exitingcnt) cleans up the
  218          * remainder.
  219          */
  220         ++vm->vm_exitingcnt;
  221         if (--vm->vm_refcnt == 0) {
  222                 if (vm->vm_shm)
  223                         shmexit(p);
  224                 pmap_remove_pages(vmspace_pmap(vm), VM_MIN_ADDRESS,
  225                     VM_MAXUSER_ADDRESS);
  226                 (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
  227                     VM_MAXUSER_ADDRESS);
  228         }
  229 
  230         if (SESS_LEADER(p)) {
  231                 register struct session *sp = p->p_session;
  232 
  233                 if (sp->s_ttyvp) {
  234                         /*
  235                          * Controlling process.
  236                          * Signal foreground pgrp,
  237                          * drain controlling terminal
  238                          * and revoke access to controlling terminal.
  239                          */
  240                         if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) {
  241                                 if (sp->s_ttyp->t_pgrp)
  242                                         pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
  243                                 (void) ttywait(sp->s_ttyp);
  244                                 /*
  245                                  * The tty could have been revoked
  246                                  * if we blocked.
  247                                  */
  248                                 if (sp->s_ttyvp)
  249                                         VOP_REVOKE(sp->s_ttyvp, REVOKEALL);
  250                         }
  251                         if (sp->s_ttyvp)
  252                                 vrele(sp->s_ttyvp);
  253                         sp->s_ttyvp = NULL;
  254                         /*
  255                          * s_ttyp is not zero'd; we use this to indicate
  256                          * that the session once had a controlling terminal.
  257                          * (for logging and informational purposes)
  258                          */
  259                 }
  260                 sp->s_leader = NULL;
  261         }
  262         fixjobc(p, p->p_pgrp, 0);
  263         (void)acct_process(p);
  264 #ifdef KTRACE
  265         /*
  266          * release trace file
  267          */
  268         p->p_traceflag = 0;     /* don't trace the vrele() */
  269         if ((vtmp = p->p_tracep) != NULL) {
  270                 p->p_tracep = NULL;
  271                 vrele(vtmp);
  272         }
  273 #endif
  274         /*
  275          * Release reference to text vnode
  276          */
  277         if ((vtmp = p->p_textvp) != NULL) {
  278                 p->p_textvp = NULL;
  279                 vrele(vtmp);
  280         }
  281 
  282         /*
  283          * Remove proc from allproc queue and pidhash chain.
  284          * Place onto zombproc.  Unlink from parent's child list.
  285          */
  286         LIST_REMOVE(p, p_list);
  287         LIST_INSERT_HEAD(&zombproc, p, p_list);
  288         p->p_stat = SZOMB;
  289 
  290         LIST_REMOVE(p, p_hash);
  291 
  292         q = LIST_FIRST(&p->p_children);
  293         if (q)          /* only need this if any child is S_ZOMB */
  294                 wakeup((caddr_t) initproc);
  295         for (; q != 0; q = nq) {
  296                 nq = LIST_NEXT(q, p_sibling);
  297                 LIST_REMOVE(q, p_sibling);
  298                 LIST_INSERT_HEAD(&initproc->p_children, q, p_sibling);
  299                 q->p_pptr = initproc;
  300                 q->p_sigparent = SIGCHLD;
  301                 /*
  302                  * Traced processes are killed
  303                  * since their existence means someone is screwing up.
  304                  */
  305                 if (q->p_flag & P_TRACED) {
  306                         q->p_flag &= ~P_TRACED;
  307                         psignal(q, SIGKILL);
  308                 }
  309         }
  310 
  311         /*
  312          * Save exit status and final rusage info, adding in child rusage
  313          * info and self times.
  314          */
  315         p->p_xstat = rv;
  316         *p->p_ru = p->p_stats->p_ru;
  317         calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
  318         ruadd(p->p_ru, &p->p_stats->p_cru);
  319 
  320         /*
  321          * Pretend that an mi_switch() to the next process occurs now.  We
  322          * must set `switchtime' directly since we will call cpu_switch()
  323          * directly.  Set it now so that the rest of the exit time gets
  324          * counted somewhere if possible.
  325          */
  326         microuptime(&switchtime);
  327         switchticks = ticks;
  328 
  329         /*
  330          * notify interested parties of our demise.
  331          */
  332         KNOTE(&p->p_klist, NOTE_EXIT);
  333 
  334         /*
  335          * Notify parent that we're gone.  If parent has the PS_NOCLDWAIT
  336          * flag set, notify process 1 instead (and hope it will handle
  337          * this situation).
  338          */
  339         if (p->p_pptr->p_procsig->ps_flag & PS_NOCLDWAIT) {
  340                 struct proc *pp = p->p_pptr;
  341                 proc_reparent(p, initproc);
  342                 p->p_sigparent = SIGCHLD;
  343                 /*
  344                  * If this was the last child of our parent, notify
  345                  * parent, so in case he was wait(2)ing, he will
  346                  * continue.
  347                  */
  348                 if (LIST_EMPTY(&pp->p_children))
  349                         wakeup((caddr_t)pp);
  350         }
  351 
  352         if (p->p_pptr == initproc)
  353                 psignal(p->p_pptr, SIGCHLD);
  354         else if (p->p_sigparent != 0)
  355                 psignal(p->p_pptr, p->p_sigparent);
  356 
  357         wakeup((caddr_t)p->p_pptr);
  358 #if defined(tahoe)
  359         /* move this to cpu_exit */
  360         p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
  361 #endif
  362         /*
  363          * Clear curproc after we've done all operations
  364          * that could block, and before tearing down the rest
  365          * of the process state that might be used from clock, etc.
  366          * Also, can't clear curproc while we're still runnable,
  367          * as we're not on a run queue (we are current, just not
  368          * a proper proc any longer!).
  369          *
  370          * Other substructures are freed from wait().
  371          */
  372         SET_CURPROC(NULL);
  373         if (--p->p_limit->p_refcnt == 0) {
  374                 FREE(p->p_limit, M_SUBPROC);
  375                 p->p_limit = NULL;
  376         }
  377 
  378         /*
  379          * Finally, call machine-dependent code to release the remaining
  380          * resources including address space, the kernel stack and pcb.
  381          * The address space is released by "vmspace_free(p->p_vmspace)";
  382          * This is machine-dependent, as we may have to change stacks
  383          * or ensure that the current one isn't reallocated before we
  384          * finish.  cpu_exit will end with a call to cpu_switch(), finishing
  385          * our execution (pun intended).
  386          */
  387         cpu_exit(p);
  388 }
  389 
  390 #ifdef COMPAT_43
  391 int
  392 owait(p, uap)
  393         struct proc *p;
  394         register struct owait_args /* {
  395                 int     dummy;
  396         } */ *uap;
  397 {
  398         struct wait_args w;
  399 
  400         w.options = 0;
  401         w.rusage = NULL;
  402         w.pid = WAIT_ANY;
  403         w.status = NULL;
  404         return (wait1(p, &w, 1));
  405 }
  406 #endif /* COMPAT_43 */
  407 
  408 int
  409 wait4(p, uap)
  410         struct proc *p;
  411         struct wait_args *uap;
  412 {
  413 
  414         return (wait1(p, uap, 0));
  415 }
  416 
  417 static int
  418 wait1(q, uap, compat)
  419         register struct proc *q;
  420         register struct wait_args /* {
  421                 int pid;
  422                 int *status;
  423                 int options;
  424                 struct rusage *rusage;
  425         } */ *uap;
  426         int compat;
  427 {
  428         register int nfound;
  429         register struct proc *p, *t;
  430         int status, error;
  431 
  432         if (uap->pid == 0)
  433                 uap->pid = -q->p_pgid;
  434         if (uap->options &~ (WUNTRACED|WNOHANG|WLINUXCLONE))
  435                 return (EINVAL);
  436 loop:
  437         nfound = 0;
  438         LIST_FOREACH(p, &q->p_children, p_sibling) {
  439                 if (uap->pid != WAIT_ANY &&
  440                     p->p_pid != uap->pid && p->p_pgid != -uap->pid)
  441                         continue;
  442 
  443                 /* This special case handles a kthread spawned by linux_clone 
  444                  * (see linux_misc.c).  The linux_wait4 and linux_waitpid functions
  445                  * need to be able to distinguish between waiting on a process and
  446                  * waiting on a thread.  It is a thread if p_sigparent is not SIGCHLD,
  447                  * and the WLINUXCLONE option signifies we want to wait for threads
  448                  * and not processes.
  449                  */
  450                 if ((p->p_sigparent != SIGCHLD) ^ ((uap->options & WLINUXCLONE) != 0))
  451                         continue;
  452 
  453                 nfound++;
  454                 if (p->p_stat == SZOMB) {
  455                         /* charge childs scheduling cpu usage to parent */
  456                         if (curproc->p_pid != 1) {
  457                                 curproc->p_estcpu =
  458                                     ESTCPULIM(curproc->p_estcpu + p->p_estcpu);
  459                         }
  460 
  461                         q->p_retval[0] = p->p_pid;
  462 #ifdef COMPAT_43
  463                         if (compat)
  464                                 q->p_retval[1] = p->p_xstat;
  465                         else
  466 #endif
  467                         if (uap->status) {
  468                                 status = p->p_xstat;    /* convert to int */
  469                                 if ((error = copyout((caddr_t)&status,
  470                                     (caddr_t)uap->status, sizeof(status))))
  471                                         return (error);
  472                         }
  473                         if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
  474                             (caddr_t)uap->rusage, sizeof (struct rusage))))
  475                                 return (error);
  476                         /*
  477                          * If we got the child via a ptrace 'attach',
  478                          * we need to give it back to the old parent.
  479                          */
  480                         if (p->p_oppid && (t = pfind(p->p_oppid))) {
  481                                 p->p_oppid = 0;
  482                                 proc_reparent(p, t);
  483                                 psignal(t, SIGCHLD);
  484                                 wakeup((caddr_t)t);
  485                                 return (0);
  486                         }
  487                         p->p_xstat = 0;
  488                         ruadd(&q->p_stats->p_cru, p->p_ru);
  489                         FREE(p->p_ru, M_ZOMBIE);
  490                         p->p_ru = NULL;
  491 
  492                         /*
  493                          * Decrement the count of procs running with this uid.
  494                          */
  495                         (void)chgproccnt(p->p_cred->p_uidinfo, -1, 0);
  496 
  497                         /*
  498                          * Free up credentials.
  499                          */
  500                         if (--p->p_cred->p_refcnt == 0) {
  501                                 crfree(p->p_ucred);
  502                                 uifree(p->p_cred->p_uidinfo);
  503                                 FREE(p->p_cred, M_SUBPROC);
  504                                 p->p_cred = NULL;
  505                         }
  506 
  507                         /*
  508                          * Destroy empty prisons
  509                          */
  510                         if (p->p_prison && !--p->p_prison->pr_ref) {
  511                                 if (p->p_prison->pr_linux != NULL)
  512                                         FREE(p->p_prison->pr_linux, M_PRISON);
  513                                 FREE(p->p_prison, M_PRISON);
  514                         }
  515 
  516                         /*
  517                          * Remove unused arguments
  518                          */
  519                         if (p->p_args && --p->p_args->ar_ref == 0)
  520                                 FREE(p->p_args, M_PARGS);
  521 
  522                         /*
  523                          * Finally finished with old proc entry.
  524                          * Unlink it from its process group and free it.
  525                          */
  526                         leavepgrp(p);
  527                         LIST_REMOVE(p, p_list); /* off zombproc */
  528                         LIST_REMOVE(p, p_sibling);
  529 
  530                         if (--p->p_procsig->ps_refcnt == 0) {
  531                                 if (p->p_sigacts != &p->p_addr->u_sigacts)
  532                                         FREE(p->p_sigacts, M_SUBPROC);
  533                                 FREE(p->p_procsig, M_SUBPROC);
  534                                 p->p_procsig = NULL;
  535                         }
  536 
  537                         /*
  538                          * Give machine-dependent layer a chance
  539                          * to free anything that cpu_exit couldn't
  540                          * release while still running in process context.
  541                          */
  542                         vm_waitproc(p);
  543                         zfree(proc_zone, p);
  544                         nprocs--;
  545                         return (0);
  546                 }
  547                 if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
  548                     (p->p_flag & P_TRACED || uap->options & WUNTRACED)) {
  549                         p->p_flag |= P_WAITED;
  550                         q->p_retval[0] = p->p_pid;
  551 #ifdef COMPAT_43
  552                         if (compat) {
  553                                 q->p_retval[1] = W_STOPCODE(p->p_xstat);
  554                                 error = 0;
  555                         } else
  556 #endif
  557                         if (uap->status) {
  558                                 status = W_STOPCODE(p->p_xstat);
  559                                 error = copyout((caddr_t)&status,
  560                                         (caddr_t)uap->status, sizeof(status));
  561                         } else
  562                                 error = 0;
  563                         return (error);
  564                 }
  565         }
  566         if (nfound == 0)
  567                 return (ECHILD);
  568         if (uap->options & WNOHANG) {
  569                 q->p_retval[0] = 0;
  570                 return (0);
  571         }
  572         if ((error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)))
  573                 return (error);
  574         goto loop;
  575 }
  576 
  577 /*
  578  * make process 'parent' the new parent of process 'child'.
  579  */
  580 void
  581 proc_reparent(child, parent)
  582         register struct proc *child;
  583         register struct proc *parent;
  584 {
  585 
  586         if (child->p_pptr == parent)
  587                 return;
  588 
  589         LIST_REMOVE(child, p_sibling);
  590         LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
  591         child->p_pptr = parent;
  592 }
  593 
  594 /*
  595  * The next two functions are to handle adding/deleting items on the
  596  * exit callout list
  597  * 
  598  * at_exit():
  599  * Take the arguments given and put them onto the exit callout list,
  600  * However first make sure that it's not already there.
  601  * returns 0 on success.
  602  */
  603 
  604 int
  605 at_exit(function)
  606         exitlist_fn function;
  607 {
  608         struct exitlist *ep;
  609 
  610 #ifdef INVARIANTS
  611         /* Be noisy if the programmer has lost track of things */
  612         if (rm_at_exit(function)) 
  613                 printf("WARNING: exit callout entry (%p) already present\n",
  614                     function);
  615 #endif
  616         ep = malloc(sizeof(*ep), M_ATEXIT, M_NOWAIT);
  617         if (ep == NULL)
  618                 return (ENOMEM);
  619         ep->function = function;
  620         TAILQ_INSERT_TAIL(&exit_list, ep, next);
  621         return (0);
  622 }
  623 
  624 /*
  625  * Scan the exit callout list for the given item and remove it.
  626  * Returns the number of items removed (0 or 1)
  627  */
  628 int
  629 rm_at_exit(function)
  630         exitlist_fn function;
  631 {
  632         struct exitlist *ep;
  633 
  634         TAILQ_FOREACH(ep, &exit_list, next) {
  635                 if (ep->function == function) {
  636                         TAILQ_REMOVE(&exit_list, ep, next);
  637                         free(ep, M_ATEXIT);
  638                         return(1);
  639                 }
  640         }       
  641         return (0);
  642 }
  643 
  644 void check_sigacts (void)
  645 {
  646         struct proc *p = curproc;
  647         struct sigacts *pss;
  648         int s;
  649 
  650         if (p->p_procsig->ps_refcnt == 1 &&
  651             p->p_sigacts != &p->p_addr->u_sigacts) {
  652                 pss = p->p_sigacts;
  653                 s = splhigh();
  654                 p->p_addr->u_sigacts = *pss;
  655                 p->p_sigacts = &p->p_addr->u_sigacts;
  656                 splx(s);
  657                 FREE(pss, M_SUBPROC);
  658         }
  659 }
  660 

Cache object: b1810b02f5cea39ad2e51c157d5954b6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.