~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/mm/forkexit.c


  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_mm_exit: perform the EXIT system call (by calling mm_exit())
 12  *   mm_exit:    actually do the exiting
 13  *   do_wait:    perform the WAITPID or WAIT system call
 14  */
 15 
 16 
 17 #include "mm.h"
 18 #include <sys/wait.h>
 19 #include <minix/callnr.h>
 20 #include <signal.h>
 21 #include "mproc.h"
 22 #include "param.h"
 23 
 24 /*
 25  * This file has been changed quite a lot to allow for extendable data
 26  * and stack segments in smx.  Consequently, all INTEL-specific code
 27  * has been removed to improve readability.
 28  */
 29 #if (MACHINE != SUN)
 30 #error "This file has been tailored for use with Solaris MINIX only"
 31 #endif
 32 
 33 #define LAST_FEW            2   /* last few slots reserved for superuser */
 34 
 35 PRIVATE pid_t next_pid = INIT_PID+1;    /* next pid to be assigned */
 36 
 37 FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
 38 
 39 /*===========================================================================*
 40  *                              do_fork                                      *
 41  *===========================================================================*/
 42 PUBLIC int do_fork()
 43 {
 44 /* The process pointed to by 'mp' has forked.  Create a child process. */
 45 
 46   register struct mproc *rmp;   /* pointer to parent */
 47   register struct mproc *rmc;   /* pointer to child */
 48   int i, child_nr, t;
 49   phys_clicks prog_clicks, child_base = 0;
 50   phys_bytes prog_bytes, parent_abs, child_abs; /* Intel only */
 51 
 52  /* If tables might fill up during FORK, don't even start since recovery half
 53   * way through is such a nuisance.
 54   */
 55   rmp = mp;
 56   if (procs_in_use == NR_PROCS) return(EAGAIN);
 57   if (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0)return(EAGAIN);
 58 
 59   /* Determine how much memory to allocate.  Only the data and stack need to
 60    * be copied, because the text segment is either shared or of zero length.
 61    */
 62   prog_clicks = (phys_clicks) rmp->mp_seg[D].mem_len + rmp->mp_seg[S].mem_len;
 63   prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
 64   if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
 65 
 66   /* Create a copy of the parent's core image for the child. */
 67   child_abs = (phys_bytes) child_base << CLICK_SHIFT;
 68   parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
 69   i = sys_copy(ABS, 0, parent_abs, ABS, 0, child_abs,
 70                rmp->mp_seg[D].mem_len << CLICK_SHIFT);
 71   if (i < 0) panic("do_fork can't copy", i);
 72   i = sys_copy(ABS, 0, rmp->mp_seg[S].mem_phys << CLICK_SHIFT, ABS, 0,
 73                child_abs + (rmp->mp_seg[D].mem_len << CLICK_SHIFT),
 74                rmp->mp_seg[S].mem_len << CLICK_SHIFT);
 75   if (i < 0) panic("do_fork can't copy", i);
 76 
 77   /* Find a slot in 'mproc' for the child process.  A slot must exist. */
 78   for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
 79         if ( (rmc->mp_flags & IN_USE) == 0) break;
 80 
 81   /* Set up the child and its memory map; copy its 'mproc' slot from parent. */
 82   child_nr = (int)(rmc - mproc);        /* slot number of the child */
 83   procs_in_use++;
 84   *rmc = *rmp;                  /* copy parent's process slot to child's */
 85 
 86   rmc->mp_parent = who;         /* record child's parent */
 87   rmc->mp_flags &= ~TRACED;     /* child does not inherit trace status */
 88   /*
 89    * In smx, only processes with separate I&D are supported.
 90    */
 91   if (!(rmc->mp_flags & SEPARATE)) {
 92       panic("do_fork: process without separate I&D segments", NO_NUM);
 93   }
 94   rmc->mp_seg[D].mem_phys = child_base;
 95   rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + rmc->mp_seg[D].mem_len;
 96   rmc->mp_exitstatus = 0;
 97   rmc->mp_sigstatus = 0;
 98 
 99   /* Find a free pid for the child and put it in the table. */
100   do {
101         t = 0;                  /* 't' = 0 means pid still free */
102         next_pid = (next_pid < 30000 ? next_pid + 1 : INIT_PID + 1);
103         for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++)
104                 if (rmp->mp_pid == next_pid || rmp->mp_procgrp == next_pid) {
105                         t = 1;
106                         break;
107                 }
108         rmc->mp_pid = next_pid; /* assign pid to child */
109   } while (t);
110 
111   /* Tell kernel and file system about the (now successful) FORK. */
112   sys_fork(who, child_nr, rmc->mp_pid, child_base); /* child_base is 68K only*/
113   tell_fs(FORK, who, child_nr, rmc->mp_pid);
114 
115   /* Report child's memory map to kernel. */
116   sys_newmap(child_nr, rmc->mp_seg);
117 
118   /* Reply to child to wake it up. */
119   reply(child_nr, 0, 0, NIL_PTR);
120   return(next_pid);              /* child's pid */
121 }
122 
123 
124 /*===========================================================================*
125  *                              do_mm_exit                                   *
126  *===========================================================================*/
127 PUBLIC int do_mm_exit()
128 {
129 /* Perform the exit(status) system call. The real work is done by mm_exit(),
130  * which is also called when a process is killed by a signal.
131  */
132 
133   mm_exit(mp, status);
134   dont_reply = TRUE;            /* don't reply to newly terminated process */
135   return(OK);                   /* pro forma return code */
136 }
137 
138 
139 /*===========================================================================*
140  *                              mm_exit                                      *
141  *===========================================================================*/
142 PUBLIC void mm_exit(rmp, exit_status)
143 register struct mproc *rmp;     /* pointer to the process to be terminated */
144 int exit_status;                /* the process' exit status (for parent) */
145 {
146 /* A process is done.  Release most of the process' possessions.  If its
147  * parent is waiting, release the rest, else hang.
148  */
149 
150   register int proc_nr;
151   int parent_waiting, right_child;
152   pid_t pidarg, procgrp;
153   phys_clicks base, size;
154 
155   proc_nr = (int) (rmp - mproc);        /* get process slot number */
156 
157   /* Remember a session leader's process group. */
158   procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
159 
160   /* If the exited process has a timer pending, kill it. */
161   if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);
162 
163   /* Tell the kernel and FS that the process is no longer runnable. */
164   tell_fs(EXIT, proc_nr, 0, 0);  /* file system can free the proc slot */
165   sys_xit(rmp->mp_parent, proc_nr, &base, &size);
166 
167   /* Release the memory occupied by the child. */
168   if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
169         /* No other process shares the text segment, so free it. */
170         free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
171   }
172   /* Free the data and stack segments. */
173   free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[D].mem_len);
174   free_mem(rmp->mp_seg[S].mem_phys, rmp->mp_seg[S].mem_len);
175 
176   /* The process slot can only be freed if the parent has done a WAIT. */
177   rmp->mp_exitstatus = (char) exit_status;
178   pidarg = mproc[rmp->mp_parent].mp_wpid;       /* who's being waited for? */
179   parent_waiting = mproc[rmp->mp_parent].mp_flags & WAITING;
180   if (pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp)
181         right_child = TRUE;             /* child meets one of the 3 tests */
182   else
183         right_child = FALSE;            /* child fails all 3 tests */
184   if (parent_waiting && right_child)
185         cleanup(rmp);                   /* tell parent and release child slot */
186   else
187         rmp->mp_flags |= HANGING;       /* parent not waiting, suspend child */
188 
189   /* If the process has children, disinherit them.  INIT is the new parent. */
190   for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
191         if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
192                 /* 'rmp' now points to a child to be disinherited. */
193                 rmp->mp_parent = INIT_PROC_NR;
194                 parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
195                 if (parent_waiting && (rmp->mp_flags & HANGING)) cleanup(rmp);
196         }
197   }
198 
199   /* Send a hangup to the process' process group if it was a session leader. */
200   if (procgrp != 0) check_sig(-procgrp, SIGHUP);
201 }
202 
203 
204 /*===========================================================================*
205  *                              do_waitpid                                   *
206  *===========================================================================*/
207 PUBLIC int do_waitpid()
208 {
209 /* A process wants to wait for a child to terminate. If one is already waiting,
210  * go clean it up and let this WAIT call terminate.  Otherwise, really wait.
211  * Both WAIT and WAITPID are handled by this code.
212  */
213 
214   register struct mproc *rp;
215   int pidarg, options, children, res2;
216 
217   /* A process calling WAIT never gets a reply in the usual way via the
218    * reply() in the main loop (unless WNOHANG is set or no qualifying child
219    * exists).  If a child has already exited, the routine cleanup() sends 
220    * the reply to awaken the caller.
221    */
222 
223   /* Set internal variables, depending on whether this is WAIT or WAITPID. */
224   pidarg  = (mm_call == WAIT ? -1 : pid);       /* first param of waitpid */
225   options = (mm_call == WAIT ?  0 : sig_nr);    /* third param of waitpid */
226   if (pidarg == 0) pidarg = -mp->mp_procgrp;    /* pidarg < 0 ==> proc grp */
227 
228   /* Is there a child waiting to be collected? At this point, pidarg != 0:
229    *    pidarg  >  0 means pidarg is pid of a specific process to wait for
230    *    pidarg == -1 means wait for any child
231    *    pidarg  < -1 means wait for any child whose process group = -pidarg
232    */
233   children = 0;
234   for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
235         if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
236                 /* The value of pidarg determines which children qualify. */
237                 if (pidarg  > 0 && pidarg != rp->mp_pid) continue;
238                 if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
239 
240                 children++;             /* this child is acceptable */
241                 if (rp->mp_flags & HANGING) {
242                         /* This child meets the pid test and has exited. */
243                         cleanup(rp);    /* this child has already exited */
244                         dont_reply = TRUE;
245                         return(OK);
246                 }
247                 if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
248                         /* This child meets the pid test and is being traced.*/
249                         res2 =  0177 | (rp->mp_sigstatus << 8);
250                         reply(who, rp->mp_pid, res2, NIL_PTR);
251                         dont_reply = TRUE;
252                         rp->mp_sigstatus = 0;
253                         return(OK);
254                 }
255         }
256   }
257 
258   /* No qualifying child has exited.  Wait for one, unless none exists. */
259   if (children > 0) {
260         /* At least 1 child meets the pid test exists, but has not exited. */
261         if (options & WNOHANG) return(0);    /* parent does not want to wait */
262         mp->mp_flags |= WAITING;             /* parent wants to wait */
263         mp->mp_wpid = (pid_t) pidarg;        /* save pid for later */
264         dont_reply = TRUE;                   /* do not reply now though */
265         return(OK);                          /* yes - wait for one to exit */
266   } else {
267         /* No child even meets the pid test.  Return error immediately. */
268         return(ECHILD);                      /* no - parent has no children */
269   }
270 }
271 
272 
273 /*===========================================================================*
274  *                              cleanup                                      *
275  *===========================================================================*/
276 PRIVATE void cleanup(child)
277 register struct mproc *child;   /* tells which process is exiting */
278 {
279 /* Finish off the exit of a process.  The process has exited or been killed
280  * by a signal, and its parent is waiting.
281  */
282 
283   int exitstatus;
284 
285   /* Wake up the parent. */
286   exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
287   reply(child->mp_parent, child->mp_pid, exitstatus, NIL_PTR);
288   mproc[child->mp_parent].mp_flags &= ~WAITING; /* parent no longer waiting */
289 
290   /* Release the process table entry. */
291   child->mp_flags = 0;
292   procs_in_use--;
293 }
294 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.