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/servers/pm/forkexit.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 /* This file deals with creating processes (via FORK) and deleting them (via
    2  * EXIT/WAIT).  When a process forks, a new slot in the 'mproc' table is
    3  * allocated for it, and a copy of the parent's core image is made for the
    4  * child.  Then the kernel and file system are informed.  A process is removed
    5  * from the 'mproc' table when two events have occurred: (1) it has exited or
    6  * been killed by a signal, and (2) the parent has done a WAIT.  If the process
    7  * exits first, it continues to occupy a slot until the parent does a WAIT.
    8  *
    9  * The entry points into this file are:
   10  *   do_fork:    perform the FORK system call
   11  *   do_pm_exit: perform the EXIT system call (by calling pm_exit())
   12  *   pm_exit:    actually do the exiting
   13  *   do_wait:    perform the WAITPID or WAIT system call
   14  */
   15 
   16 #include "pm.h"
   17 #include <sys/wait.h>
   18 #include <minix/callnr.h>
   19 #include <minix/com.h>
   20 #include <signal.h>
   21 #include "mproc.h"
   22 #include "param.h"
   23 
   24 #define LAST_FEW            2   /* last few slots reserved for superuser */
   25 
   26 FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
   27 
   28 /*===========================================================================*
   29  *                              do_fork                                      *
   30  *===========================================================================*/
   31 PUBLIC int do_fork()
   32 {
   33 /* The process pointed to by 'mp' has forked.  Create a child process. */
   34   register struct mproc *rmp;   /* pointer to parent */
   35   register struct mproc *rmc;   /* pointer to child */
   36   int child_nr, s;
   37   phys_clicks prog_clicks, child_base;
   38   phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
   39   pid_t new_pid;
   40 
   41  /* If tables might fill up during FORK, don't even start since recovery half
   42   * way through is such a nuisance.
   43   */
   44   rmp = mp;
   45   if ((procs_in_use == NR_PROCS) || 
   46                 (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
   47   {
   48         printf("PM: warning, process table is full!\n");
   49         return(EAGAIN);
   50   }
   51 
   52   /* Determine how much memory to allocate.  Only the data and stack need to
   53    * be copied, because the text segment is either shared or of zero length.
   54    */
   55   prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
   56   prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
   57   prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
   58   if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
   59 
   60   /* Create a copy of the parent's core image for the child. */
   61   child_abs = (phys_bytes) child_base << CLICK_SHIFT;
   62   parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
   63   s = sys_abscopy(parent_abs, child_abs, prog_bytes);
   64   if (s < 0) panic(__FILE__,"do_fork can't copy", s);
   65 
   66   /* Find a slot in 'mproc' for the child process.  A slot must exist. */
   67   for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
   68         if ( (rmc->mp_flags & IN_USE) == 0) break;
   69 
   70   /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
   71   child_nr = (int)(rmc - mproc);        /* slot number of the child */
   72   procs_in_use++;
   73   *rmc = *rmp;                  /* copy parent's process slot to child's */
   74   rmc->mp_parent = who;                 /* record child's parent */
   75   /* inherit only these flags */
   76   rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP);
   77   rmc->mp_child_utime = 0;              /* reset administration */
   78   rmc->mp_child_stime = 0;              /* reset administration */
   79 
   80   /* A separate I&D child keeps the parents text segment.  The data and stack
   81    * segments must refer to the new copy.
   82    */
   83   if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;
   84   rmc->mp_seg[D].mem_phys = child_base;
   85   rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + 
   86                         (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
   87   rmc->mp_exitstatus = 0;
   88   rmc->mp_sigstatus = 0;
   89 
   90   /* Find a free pid for the child and put it in the table. */
   91   new_pid = get_free_pid();
   92   rmc->mp_pid = new_pid;        /* assign pid to child */
   93 
   94   /* Tell kernel and file system about the (now successful) FORK. */
   95   sys_fork(who, child_nr);
   96   tell_fs(FORK, who, child_nr, rmc->mp_pid);
   97 
   98   /* Report child's memory map to kernel. */
   99   sys_newmap(child_nr, rmc->mp_seg);
  100 
  101   /* Reply to child to wake it up. */
  102   setreply(child_nr, 0);                /* only parent gets details */
  103   rmp->mp_reply.procnr = child_nr;      /* child's process number */
  104   return(new_pid);                      /* child's pid */
  105 }
  106 
  107 /*===========================================================================*
  108  *                              do_pm_exit                                   *
  109  *===========================================================================*/
  110 PUBLIC int do_pm_exit()
  111 {
  112 /* Perform the exit(status) system call. The real work is done by pm_exit(),
  113  * which is also called when a process is killed by a signal.
  114  */
  115   pm_exit(mp, m_in.status);
  116   return(SUSPEND);              /* can't communicate from beyond the grave */
  117 }
  118 
  119 /*===========================================================================*
  120  *                              pm_exit                                      *
  121  *===========================================================================*/
  122 PUBLIC void pm_exit(rmp, exit_status)
  123 register struct mproc *rmp;     /* pointer to the process to be terminated */
  124 int exit_status;                /* the process' exit status (for parent) */
  125 {
  126 /* A process is done.  Release most of the process' possessions.  If its
  127  * parent is waiting, release the rest, else keep the process slot and
  128  * become a zombie.
  129  */
  130   register int proc_nr;
  131   int parent_waiting, right_child;
  132   pid_t pidarg, procgrp;
  133   struct mproc *p_mp;
  134   clock_t t[5];
  135 
  136   proc_nr = (int) (rmp - mproc);        /* get process slot number */
  137 
  138   /* Remember a session leader's process group. */
  139   procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
  140 
  141   /* If the exited process has a timer pending, kill it. */
  142   if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);
  143 
  144   /* Do accounting: fetch usage times and accumulate at parent. */
  145   sys_times(proc_nr, t);
  146   p_mp = &mproc[rmp->mp_parent];                        /* process' parent */
  147   p_mp->mp_child_utime += t[0] + rmp->mp_child_utime;   /* add user time */
  148   p_mp->mp_child_stime += t[1] + rmp->mp_child_stime;   /* add system time */
  149 
  150   /* Tell the kernel and FS that the process is no longer runnable. */
  151   tell_fs(EXIT, proc_nr, 0, 0);  /* file system can free the proc slot */
  152   sys_exit(proc_nr);
  153 
  154   /* Pending reply messages for the dead process cannot be delivered. */
  155   rmp->mp_flags &= ~REPLY;
  156   
  157   /* Release the memory occupied by the child. */
  158   if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
  159         /* No other process shares the text segment, so free it. */
  160         free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
  161   }
  162   /* Free the data and stack segments. */
  163   free_mem(rmp->mp_seg[D].mem_phys,
  164       rmp->mp_seg[S].mem_vir 
  165         + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
  166 
  167   /* The process slot can only be freed if the parent has done a WAIT. */
  168   rmp->mp_exitstatus = (char) exit_status;
  169 
  170   pidarg = p_mp->mp_wpid;               /* who's being waited for? */
  171   parent_waiting = p_mp->mp_flags & WAITING;
  172   right_child =                         /* child meets one of the 3 tests? */
  173         (pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
  174 
  175   if (parent_waiting && right_child) {
  176         cleanup(rmp);                   /* tell parent and release child slot */
  177   } else {
  178         rmp->mp_flags = IN_USE|ZOMBIE;  /* parent not waiting, zombify child */
  179         sig_proc(p_mp, SIGCHLD);        /* send parent a "child died" signal */
  180   }
  181 
  182   /* If the process has children, disinherit them.  INIT is the new parent. */
  183   for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
  184         if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
  185                 /* 'rmp' now points to a child to be disinherited. */
  186                 rmp->mp_parent = INIT_PROC_NR;
  187                 parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
  188                 if (parent_waiting && (rmp->mp_flags & ZOMBIE)) cleanup(rmp);
  189         }
  190   }
  191 
  192   /* Send a hangup to the process' process group if it was a session leader. */
  193   if (procgrp != 0) check_sig(-procgrp, SIGHUP);
  194 }
  195 
  196 /*===========================================================================*
  197  *                              do_waitpid                                   *
  198  *===========================================================================*/
  199 PUBLIC int do_waitpid()
  200 {
  201 /* A process wants to wait for a child to terminate. If a child is already 
  202  * waiting, go clean it up and let this WAIT call terminate.  Otherwise, 
  203  * really wait. 
  204  * A process calling WAIT never gets a reply in the usual way at the end
  205  * of the main loop (unless WNOHANG is set or no qualifying child exists).
  206  * If a child has already exited, the routine cleanup() sends the reply
  207  * to awaken the caller.
  208  * Both WAIT and WAITPID are handled by this code.
  209  */
  210   register struct mproc *rp;
  211   int pidarg, options, children;
  212 
  213   /* Set internal variables, depending on whether this is WAIT or WAITPID. */
  214   pidarg  = (call_nr == WAIT ? -1 : m_in.pid);     /* 1st param of waitpid */
  215   options = (call_nr == WAIT ?  0 : m_in.sig_nr);  /* 3rd param of waitpid */
  216   if (pidarg == 0) pidarg = -mp->mp_procgrp;    /* pidarg < 0 ==> proc grp */
  217 
  218   /* Is there a child waiting to be collected? At this point, pidarg != 0:
  219    *    pidarg  >  0 means pidarg is pid of a specific process to wait for
  220    *    pidarg == -1 means wait for any child
  221    *    pidarg  < -1 means wait for any child whose process group = -pidarg
  222    */
  223   children = 0;
  224   for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
  225         if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
  226                 /* The value of pidarg determines which children qualify. */
  227                 if (pidarg  > 0 && pidarg != rp->mp_pid) continue;
  228                 if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
  229 
  230                 children++;             /* this child is acceptable */
  231                 if (rp->mp_flags & ZOMBIE) {
  232                         /* This child meets the pid test and has exited. */
  233                         cleanup(rp);    /* this child has already exited */
  234                         return(SUSPEND);
  235                 }
  236                 if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
  237                         /* This child meets the pid test and is being traced.*/
  238                         mp->mp_reply.reply_res2 = 0177|(rp->mp_sigstatus << 8);
  239                         rp->mp_sigstatus = 0;
  240                         return(rp->mp_pid);
  241                 }
  242         }
  243   }
  244 
  245   /* No qualifying child has exited.  Wait for one, unless none exists. */
  246   if (children > 0) {
  247         /* At least 1 child meets the pid test exists, but has not exited. */
  248         if (options & WNOHANG) return(0);    /* parent does not want to wait */
  249         mp->mp_flags |= WAITING;             /* parent wants to wait */
  250         mp->mp_wpid = (pid_t) pidarg;        /* save pid for later */
  251         return(SUSPEND);                     /* do not reply, let it wait */
  252   } else {
  253         /* No child even meets the pid test.  Return error immediately. */
  254         return(ECHILD);                      /* no - parent has no children */
  255   }
  256 }
  257 
  258 /*===========================================================================*
  259  *                              cleanup                                      *
  260  *===========================================================================*/
  261 PRIVATE void cleanup(child)
  262 register struct mproc *child;   /* tells which process is exiting */
  263 {
  264 /* Finish off the exit of a process.  The process has exited or been killed
  265  * by a signal, and its parent is waiting.
  266  */
  267   struct mproc *parent = &mproc[child->mp_parent];
  268   int exitstatus;
  269 
  270   /* Wake up the parent by sending the reply message. */
  271   exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
  272   parent->mp_reply.reply_res2 = exitstatus;
  273   setreply(child->mp_parent, child->mp_pid);
  274   parent->mp_flags &= ~WAITING;         /* parent no longer waiting */
  275 
  276   /* Release the process table entry and reinitialize some field. */
  277   child->mp_pid = 0;
  278   child->mp_flags = 0;
  279   child->mp_child_utime = 0;
  280   child->mp_child_stime = 0;
  281   procs_in_use--;
  282 }
  283 

Cache object: a4407ff93f5a6762b89963acfd558a72


[ 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.