/[nova]/nova/kern/proc.c
ViewVC logotype

Diff of /nova/kern/proc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1.1.1 by jrydberg, Tue Feb 12 19:28:50 2002 UTC revision 1.2 by jrydberg, Wed Mar 27 23:21:54 2002 UTC
# Line 15  You should have received a copy of the G Line 15  You should have received a copy of the G
15  along with this program; if not, write to the Free Software  along with this program; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17    
18    #include <rtmk/special-ports.h>
19    #include <rtmk/exception.h>
20    
21    #include <sys/wait.h>
22  #include <stdio.h>  #include <stdio.h>
23  #include <stdlib.h>  #include <stdlib.h>
24  #include <string.h>  #include <string.h>
# Line 22  Foundation, Inc., 59 Temple Place - Suit Line 26  Foundation, Inc., 59 Temple Place - Suit
26  #include <assert.h>  #include <assert.h>
27    
28  #include "proc.h"  #include "proc.h"
29  #include "vfs.h"  #include "io-vfs.h"
30  #include "io-uio.h"  #include "io-uio.h"
31  #include "objfmt.h"  #include "objfmt.h"
32    #include "ihash.h"
33    
34    #include "nova-intern.h"
35    
36  #define NFDS    128  #define NFDS    128
37  #define LOSE { goto lose; }  #define LOSE { goto lose; }
38    
39    /* Hash table for all processes.  Indexed by process request
40       port.  The hash table is protected by htable lock.  */
41    ihash_t proc_hash_table;
42    pthread_mutex_t proc_hash_lock = PTHREAD_MUTEX_INITIALIZER;
43    
44  /* Tries to choose a new pid for a process.  We return new pid,  /* Tries to choose a new pid for a process.  We return new pid,
45     or zero if we for some reason fail to choose new id.  */     or zero if we for some reason fail to choose new id.  */
46  static int  static int
# Line 51  chain_parent (struct proc *parent, struc Line 63  chain_parent (struct proc *parent, struc
63        pp = &p->p_sibling;        pp = &p->p_sibling;
64        p  =  p->p_sibling;        p  =  p->p_sibling;
65      }      }
   
66    *pp = child;    *pp = child;
67  }  }
68    
69    /* Remove process CHILD from chain in parent.   */
70    static void
71    remove_parent (struct proc *child)
72    {
73      struct proc **pp = &child->p_parent->p_child,
74                    *p = child->p_parent->p_child;
75    
76      while (p)
77        {
78          if (p == child)
79            {
80              *pp = child->p_sibling;
81              child->p_parent = 0;
82              return;
83            }
84          pp = &p->p_sibling;
85          p  =  p->p_sibling;
86        }
87    }
88    
89    
90    
91    /* Exception raise function.  EXC_PORT is the proc port,
92       so we can just do a "proc_lookup" on it.  THREAD is
93       the thread that caused the exception.
94    
95       We just translate the exception into a signal and
96       send it to the process.  */
97    kern_return_t
98    proc_exception_raise (rtmk_port_t exc_port, rtmk_port_t thread,
99                          rtmk_port_t task, int exception, int code,
100                          int subcode, char *state, int state_length)
101    {
102      struct proc *p = proc_lookup ((void *) exc_port);
103      int signum;
104    
105      switch (exception)
106        {
107        case EXCEPTION_BAD_ACCESS: signum = SIGSEGV; break;
108        case EXCEPTION_BAD_INSN:   signum = SIGILL; break;
109        case EXCEPTION_ARITHMETIC: signum = SIGILL; break;
110        default:
111          signum = SIGBUS;
112          break;
113        }
114    
115      trace_printf ("--- GET EXCEPTION FROM PROCESS %d", p->p_pid);
116      trace_printf ("--- should send signal %d", signum);
117      return KERN_FAILURE;
118    }
119    
120    /* Obtain a reference to process P.  P must be unlocked.  */
121    void
122    proc_reference (struct proc *p)
123    {
124      pthread_mutex_lock (&p->p_lock);
125      p->p_refcnt++;
126      pthread_mutex_unlock (&p->p_lock);
127    }
128    
129    /* Deallocate a reference to process P.
130       If reference counter drops to zero, we release resources.  */
131    void
132    proc_deallocate (struct proc *p)
133    {
134      int free_p;
135    
136      pthread_mutex_lock (&p->p_lock);
137      free_p = --p->p_refcnt == 0;
138      pthread_mutex_unlock (&p->p_lock);
139      if (! free_p)
140        return;
141    
142      assert (p->p_parent == 0);
143      
144      trace_printf ("freeing process");
145    
146      if (p->p_task)
147        port_deallocate (task_self (), p->p_task);
148      if (p->p_thread)
149        port_deallocate (task_self (), p->p_task);
150      free (p);
151    }
152    
153  /* Execute the program pointer to by FILENAME.  */  /* Execute the program pointer to by FILENAME.  */
154  int  int
155  proc_exec (struct proc *p, char *filename, int nargv, char **argv,  proc_exec (struct proc *p, char *filename, int nargv, char **argv,
# Line 72  proc_exec (struct proc *p, char *filenam Line 167  proc_exec (struct proc *p, char *filenam
167    
168    /* We must check so that we have permission to execute the    /* We must check so that we have permission to execute the
169       program as well.  ??? VEXEC or VEXEC+VREAD?  */       program as well.  ??? VEXEC or VEXEC+VREAD?  */
170    err = VOP_ACCESS (vp, VEXEC, p ? &p->p_ucred : 0, p);    err = VOP_ACCESS (vp, VEXEC, p ? &p->p_ucred : 0);
171    if (err)    if (err)
172      return err;      return err;
173    err = VOP_OPEN (vp, VEXEC, p ? &p->p_ucred : 0, p);  
174      /* We open the file aswell.  ??? is this needed? we just
175         did an VOP_ACCESS on it, right?  */
176      err = VOP_OPEN (vp, VEXEC, p ? &p->p_ucred : 0);
177    if (err)    if (err)
178      return err;      return err;
179    
180    /* ??? create new task, new thread:  load program into it,    /* Create a new task for the new program image.
181       start it -- then terminate current process.  */       This is alot faster than doing a vm_deallocate(WHOLE MEMORY).  */
182    if (task_proc)    err = task_create (task_proc ?: task_self (), 0, &p->p_task);
183      err = task_create (task_proc, 1, &p->p_task);    if (err || ! p->p_task)
   else  
     err = task_create (task_self (), 0, &p->p_task);  
   if (err)  
184      return err;      return err;
185    
186      /* We create an initial master thread for the image
187         as well.  The current threads of TASK_PROC will be
188         destroyed when task_deallocate (TASK_PROC) is called.  */
189    err = thread_create (p->p_task, &p->p_thread);    err = thread_create (p->p_task, &p->p_thread);
190    if (err)    if (err)
191      return err;      return err;
192    
193      /* We try to load the image into P.  If this failes there's
194         no turning back really.  */
195    err = objfmt_load_exec (p, vp, nargv, argv, nenvp, envp);    err = objfmt_load_exec (p, vp, nargv, argv, nenvp, envp);
196    if (err)    if (err)
197      return err;      return err;
198      
199    /* Insert send rights to the proc port into slot 0.  */    /* Insert send rights to the proc port into slot 0.  */
200    err = task_special_port_set (p->p_task, 0, p->p_pport);    err = task_special_port_set (p->p_task, TASK_SPECIAL_PORT_BOOTSTRAP,
201                                   p->p_pport);
202    if (err)    if (err)
203      return err;      return err;
204    
205  #if 0    /* Set exception port to the process port.  This for fast
206    if (task_proc)       process lookup in the exception handler.  */
207      task_terminate (task_proc);    err = task_special_port_set (p->p_task, TASK_SPECIAL_PORT_EXCEPTION,
208  #endif                                 p->p_pport);
209      if (err)
210    fflush (stdout);      return err;
   thread_resume (p->p_thread);  
   
   return 0;  
 }  
   
 /* Executes the program pointed to by FILENAME.  FILENAME must be  
    of a valid object format.  NARGZ is number of null-terminated  
    strings in ARGZ.  NENVZ is number of null-terminated environment  
    strings in ENVZ.  In success, this function does not return.  */  
 int  
 nova_S_exec (struct proc *p, char *filename,  
              void *argz, int argz_size, void *envz, int envz_size)  
 {  
   char *envp [128], *argv [64]; /* ??? XXX ??? hardcoded */  
   int nargv, nenvp;  
   char *sp;  
211    
212    /* We start by parsing the argument vector.  We get it    /* Okey, we're done.  Everything went fine.  Now we clean up
213       in the format of: ARG\0\ARG\0ARG\0ARG\0...  */       the already existing task, if any.  */
214    for (sp = argz, nargv = 0; (int) ((int) sp - (int) argv) < argz_size;)    if (task_proc)
215      {      {
216        argv [nargv++] = sp;        task_terminate (task_proc);
217        sp += strlen (sp) + 1;        port_deallocate (task_self (), task_proc);
218      }      }
219    argv [nargv] = NULL;    thread_resume (p->p_thread);
220      return 0;
   /* Parse enviroment strings.  They are in the same format as  
      the argument vector.  We just create an env vector.  */  
   for (sp = envz, nenvp = 0; (int) ((int) sp - (int) argv) < envz_size;)  
     {  
       envp [nenvp++] = sp;  
       sp += strlen (sp) + 1;  
     }  
   envp [nenvp] = NULL;  
   
   return proc_exec (p, filename, nargv, argv, nenvp, envp);  
221  }  }
222    
223  /* Create a new dummy process.  This process can only be used with  /* Create a new dummy process.  This process can only be used with
# Line 157  proc_dummy (struct proc **pp) Line 232  proc_dummy (struct proc **pp)
232    assert (p);    assert (p);
233    memset (p, 0, sizeof (struct proc));    memset (p, 0, sizeof (struct proc));
234    
235      evq_init (&p->p_evq);
236    
237      p->p_lock = PTHREAD_MUTEX_INITIALIZER;
238      p->p_exitcond = PTHREAD_COND_INITIALIZER;
239    
240    p->p_nfds  = NFDS;    p->p_nfds  = NFDS;
241    p->p_fdset = (struct file **) malloc (NFDS * sizeof (struct file *));    p->p_fdset = (struct file **) malloc (NFDS * sizeof (struct file *));
242    memset (p->p_fdset, 0, (NFDS * sizeof (struct file *)));    memset (p->p_fdset, 0, (NFDS * sizeof (struct file *)));
243    
244    err = port_allocate_name (task_self (), (rtmk_port_t) p);    err = port_allocate (task_self (), &p->p_pport);
245    if (err)    if (err)
246      return EEXIST;      return EEXIST;
247    p->p_pport = (rtmk_port_t) p;    port_insert_right (task_self (), p->p_pport, p->p_pport,
248                         RTMK_MSG_TYPE_MAKE_SEND);
249    
250      pthread_mutex_lock (&proc_hash_lock);
251      ihash_add (proc_hash_table, p->p_pport, p, 0);
252      pthread_mutex_unlock (&proc_hash_lock);
253    
254      err = port_move_member (task_self (), p->p_pport, ux_pset);
255      if (err)
256        return err;
257    
258    p->p_pid = choose_pid ();    p->p_pid = choose_pid ();
259    *pp = p;    *pp = p;
# Line 192  proc_create_named (pid_t pid, rtmk_port_ Line 281  proc_create_named (pid_t pid, rtmk_port_
281    p->p_pid = pid;    p->p_pid = pid;
282    p->p_pport = RTMK_PORT_NULL;    p->p_pport = RTMK_PORT_NULL;
283    
284      evq_init (&p->p_evq);
285    
286    p->p_nfds  = NFDS;    p->p_nfds  = NFDS;
287    p->p_fdset = (struct file **) malloc (NFDS * sizeof (struct file *));    p->p_fdset = (struct file **) malloc (NFDS * sizeof (struct file *));
288    memset (p->p_fdset, 0, (NFDS * sizeof (struct file *)));    memset (p->p_fdset, 0, (NFDS * sizeof (struct file *)));
# Line 203  proc_create_named (pid_t pid, rtmk_port_ Line 294  proc_create_named (pid_t pid, rtmk_port_
294    return err;    return err;
295  }  }
296    
297  /* Fork PARENT process and return process structure in PP.  */  
298    /* Executes the program pointed to by FILENAME.  FILENAME must be
299       of a valid object format.  NARGZ is number of null-terminated
300       strings in ARGZ.  NENVZ is number of null-terminated environment
301       strings in ENVZ.  In success, this function does not return.  */
302    int
303    nova_S_proc_exec (struct proc *p, char *filename, int fn_length,
304                      void *argz, int argz_size, void *envz, int envz_size)
305    {
306      char *envp [128], *argv [64]; /* ??? XXX ??? hardcoded */
307      int nargv, nenvp, err;
308      char *sp;
309    
310      trace_printf ("p %d: exec %s", p->p_pid, filename);
311    
312      /* We start by parsing the argument vector.  We get it
313         in the format of: ARG\0\ARG\0ARG\0ARG\0...  */
314      for (sp = argz, nargv = 0; (int) ((int) sp - (int) argz) < argz_size;)
315        {
316          argv [nargv++] = sp;
317          sp += strlen (sp) + 1;
318        }
319      argv [nargv] = NULL;
320    
321      /* Parse enviroment strings.  They are in the same format as
322         the argument vector.  We just create an env vector.  */
323      for (sp = envz, nenvp = 0; (int) ((int) sp - (int) envz) < envz_size;)
324        {
325          envp [nenvp++] = sp;
326          sp += strlen (sp) + 1;
327        }
328      envp [nenvp] = NULL;
329    
330    #if 0
331      err = proc_exec (p, filename, nargv, argv, nenvp, envp);
332    #else
333      err = proc_exec (p, filename, nargv, argv, 0, 0);
334    #endif
335      return err;
336    }
337    
338    /* Process P killed itself.  RC is the return code.  
339       We inhibit all communication on the process port after
340       this call, so no other threads (or the same thread),
341       can do spooky stuff after this point.  */
342    int
343    nova_S_proc_exit (struct proc *p, void *rc)
344    {
345      int dealloc_p = 0;
346    
347      pthread_mutex_lock (&p->p_lock);
348    
349      p->p_exitstatus = (int) rc;
350      p->p_state = PS_ZOMBIE;
351    
352      if (p->p_parent)
353        {
354          trace_printf ("we have a parent (%p)", p->p_parent);
355          if (/*p->p_parent->p_wait_for_child_p*/ 1)
356            {
357              evq_signal (&p->p_parent->p_evq, PEV_CHILD_EXITED);
358            }
359          else
360            dealloc_p = 1;
361        }
362      else
363        dealloc_p = 1;
364    
365      /* After proc_exec is called they process can not do any
366         more requests to the kernel.  We deallocate the port
367         here -- so we ensure that it will not try to access us.  */
368      port_move_member (task_self (), p->p_pport, RTMK_PORT_NULL);
369      port_destroy (task_self (), p->p_pport);
370            
371      pthread_mutex_unlock (&p->p_lock);
372    
373      if (dealloc_p)
374        proc_deallocate (p);
375    
376      trace_printf ("process %d exits with value %d", p->p_pid, rc);
377      return 0;
378    }
379    
380    /* Change working directory of P to DIR.  */
381  int  int
382  proc_fork (struct proc *parent, struct proc **pp)  nova_S_proc_chdir (struct proc *p, char *dir, int dir_length)
383    {
384      struct vnode *vp;
385      int err;
386    
387      /* First we try to look up the file as if we where just opening it.  */
388      err = lookup (VLA_LOOKUP, p, dir, &vp);
389      if (err)
390        return err;
391      if (vp->v_type != VDIR)
392        return ENOTDIR;
393      
394      /* VRELE (p->p_cwd);  */
395    
396      p->p_cwd = vp;
397      return 0;
398    }
399    
400    /* Spawn new processes.  TASK is task of new process, THREAD is
401       main thread of new process.  We return send rights to new process
402       structure in *CHILDP.  ??? used by posix_spawn and fork?  */
403    int
404    nova_S_proc_spawn (struct proc *parent, rtmk_port_t task,
405                       rtmk_port_t thread, rtmk_port_t *child_port,
406                       int *pidp)
407  {  {
408    struct proc *p = 0;    struct proc *p = 0;
409    int err;    int err;
410    
411      trace_printf ("we want to spawn");
412    
413    p = (struct proc *) malloc (sizeof (struct proc));    p = (struct proc *) malloc (sizeof (struct proc));
414    if (! p)    if (! p)
415      { err = ENOMEM; LOSE; }      { err = ENOMEM; LOSE; }
416    memset (p, 0, sizeof (struct proc));    memset (p, 0, sizeof (struct proc));
417    
418      trace_printf ("done 1");
419    
420      p->p_refcnt = 1;
421    p->p_pid = choose_pid ();    p->p_pid = choose_pid ();
422    assert (p->p_pid);    /* ??? should never fail */    assert (p->p_pid);    /* ??? should never fail */
423    
424  #if 0    trace_printf ("done 2");
425    err = port_allocate_name (task_self (), (rtmk_port_t) p);  
426      err = port_allocate (task_self (), &p->p_pport);
427    if (err)    if (err)
428      { err = EEXIST; LOSE; }      { trace_printf ("error is %d", err); err = EEXIST; LOSE; }
429    p->p_pport = (rtmk_port_t) p;    port_insert_right (task_self (), p->p_pport, p->p_pport,
430  #endif                       RTMK_MSG_TYPE_MAKE_SEND);
431    
432      err = port_move_member (task_self (), p->p_pport, ux_pset);
433      if (err)
434        {
435          trace_printf ("lost here: %d", err);
436          return err;
437        }
438      trace_printf ("done 4");
439    
440    /* Inherit fields from the parent.  */    /* Inherit fields from the parent.  */
441    p->p_ucred  = parent->p_ucred;    p->p_ucred  = parent->p_ucred;
442    p->p_cwd    = parent->p_cwd;  /* ??? vhold */    p->p_cwd    = parent->p_cwd;  /* ??? vhold */
443    p->p_root   = parent->p_root; /* ??? vhold */    p->p_root   = parent->p_root; /* ??? vhold */
444    
445  #if 0    p->p_task   = task;
446    /* ??? fork it all.  */    p->p_thread = thread;
447    err = task_create (parent->p_task, 1, &p->p_task);  
448    if (err)    p->p_fdset  = parent->p_fdset;
449      { err = EIO; lose; }    p->p_nfds   = parent->p_nfds;
450  #endif  
451      evq_init (&p->p_evq);
452    
453      pthread_mutex_lock (&proc_hash_lock);
454      ihash_add (proc_hash_table, p->p_pport, p, 0);
455      pthread_mutex_unlock (&proc_hash_lock);
456    
457    /* Chain the new process into the parents children list.  */    /* Chain the new process into the parents children list.  */
458    p->p_parent = parent;    p->p_parent = parent;
459    chain_parent (parent, p);    chain_parent (parent, p);
460    
461    return ENOMEM;    *child_port = p->p_pport;
462      *pidp = p->p_pid;
463    
464      trace_printf ("spawning process %d", p->p_pid);
465      return 0;
466        
467   lose:   lose:
468    if (p)    if (p)
469      free (p);      free (p);
470    return err;    return err;
471  }  }
472    
473    
474    /* Wait until process has exited.  If PID_P is true, we wait until
475       process PID has exited, otherwise we wait until any child has
476       exited or a signal is raised.  */
477    int
478    nova_S_proc_wait (struct proc *p, int pid_p, int pid, int options,
479                      int *statusp, int *pidp)
480    {
481      struct proc *child;
482      int event = 0;
483    
484      trace_printf ("p %d: wait for process (%p)", p->p_pid, p);
485    
486      /* Check so that no other thread in this process is already
487         waiting on children to exit.  */
488     try_again:
489      pthread_mutex_lock (&p->p_lock);
490      if (p->p_wait_on_child_p)
491        {
492          pthread_mutex_unlock (&p->p_lock);
493          return EALREADY;
494        }
495      p->p_wait_on_child_p = 1;
496    
497      /* We loop through all siblings of the first child and see if
498         we find a zombie child.  If that is the case, return at once.  */
499      for (child = p->p_child; child; child = child->p_sibling)
500        {
501          pthread_mutex_lock (&child->p_lock);
502          if (child->p_state == PS_ZOMBIE
503              && ((pid_p && child->p_pid == pid) || !pid_p))
504            {
505              *statusp = child->p_exitstatus;
506              *pidp    = child->p_pid;
507    
508              trace_printf ("child parent is %p", child->p_parent);
509              remove_parent (child);
510    
511              pthread_mutex_unlock (&child->p_lock);
512              p->p_wait_on_child_p = 0;
513              pthread_mutex_unlock (&p->p_lock);
514    
515              proc_deallocate (child);
516              return 0;
517            }
518          pthread_mutex_unlock (&child->p_lock);
519        }
520      pthread_mutex_unlock (&p->p_lock);
521    
522      if (options & WNOHANG)
523        {
524          *pidp = 0;
525          return 0;
526        }
527    
528     fall_asleep:
529      trace_printf ("p %d falling asleep", p->p_pid);
530    
531      event = evq_wait (& p->p_evq);
532      trace_printf ("we're awake");
533    
534      switch (event)
535        {
536        case PEV_CHILD_EXITED:
537          pthread_mutex_lock (&p->p_lock);
538          p->p_wait_on_child_p = 0;
539          pthread_mutex_unlock (&p->p_lock);
540          goto try_again;
541    
542        default:
543          goto fall_asleep;
544        }
545      return 0;
546    }
547    
548    /* Get process ID of PROC.  Return PID in *PIDP.  */
549    int
550    nova_S_proc_getpid (struct proc *p, int *pidp)
551    {
552      *pidp = p->p_pid;
553      return 0;
554    }
555    

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26