root/kern/proc/proc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. proc_create
  2. proc_destroy
  3. proc_bootstrap
  4. proc_create_runprogram
  5. proc_addthread
  6. proc_remthread
  7. curproc_getas
  8. curproc_setas

   1 /*
   2  * Copyright (c) 2013
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * Process support.
  32  *
  33  * There is (intentionally) not much here; you will need to add stuff
  34  * and maybe change around what's already present.
  35  *
  36  * p_lock is intended to be held when manipulating the pointers in the
  37  * proc structure, not while doing any significant work with the
  38  * things they point to. Rearrange this (and/or change it to be a
  39  * regular lock) as needed.
  40  *
  41  * Unless you're implementing multithreaded user processes, the only
  42  * process that will have more than one thread is the kernel process.
  43  */
  44 
  45 #include <types.h>
  46 #include <proc.h>
  47 #include <current.h>
  48 #include <addrspace.h>
  49 #include <vnode.h>
  50 #include <vfs.h>
  51 #include <synch.h>
  52 #include <kern/fcntl.h>  
  53 
  54 /*
  55  * The process for the kernel; this holds all the kernel-only threads.
  56  */
  57 struct proc *kproc;
  58 
  59 /*
  60  * Mechanism for making the kernel menu thread sleep while processes are running
  61  */
  62 #ifdef UW
  63 /* count of the number of processes, excluding kproc */
  64 static unsigned int proc_count;
  65 /* provides mutual exclusion for proc_count */
  66 /* it would be better to use a lock here, but we use a semaphore because locks are not implemented in the base kernel */ 
  67 static struct semaphore *proc_count_mutex;
  68 /* used to signal the kernel menu thread when there are no processes */
  69 struct semaphore *no_proc_sem;   
  70 #endif  // UW
  71 
  72 
  73 
  74 /*
  75  * Create a proc structure.
  76  */
  77 static
  78 struct proc *
  79 proc_create(const char *name)
  80 {
  81         struct proc *proc;
  82 
  83         proc = kmalloc(sizeof(*proc));
  84         if (proc == NULL) {
  85                 return NULL;
  86         }
  87         proc->p_name = kstrdup(name);
  88         if (proc->p_name == NULL) {
  89                 kfree(proc);
  90                 return NULL;
  91         }
  92 
  93         threadarray_init(&proc->p_threads);
  94         spinlock_init(&proc->p_lock);
  95 
  96         /* VM fields */
  97         proc->p_addrspace = NULL;
  98 
  99         /* VFS fields */
 100         proc->p_cwd = NULL;
 101 
 102 #ifdef UW
 103         proc->console = NULL;
 104 #endif // UW
 105 
 106         return proc;
 107 }
 108 
 109 /*
 110  * Destroy a proc structure.
 111  */
 112 void
 113 proc_destroy(struct proc *proc)
 114 {
 115         /*
 116          * note: some parts of the process structure, such as the address space,
 117          *  are destroyed in sys_exit, before we get here
 118          *
 119          * note: depending on where this function is called from, curproc may not
 120          * be defined because the calling thread may have already detached itself
 121          * from the process.
 122          */
 123 
 124         KASSERT(proc != NULL);
 125         KASSERT(proc != kproc);
 126 
 127         /*
 128          * We don't take p_lock in here because we must have the only
 129          * reference to this structure. (Otherwise it would be
 130          * incorrect to destroy it.)
 131          */
 132 
 133         /* VFS fields */
 134         if (proc->p_cwd) {
 135                 VOP_DECREF(proc->p_cwd);
 136                 proc->p_cwd = NULL;
 137         }
 138 
 139 
 140 #ifndef UW  // in the UW version, space destruction occurs in sys_exit, not here
 141         if (proc->p_addrspace) {
 142                 /*
 143                  * In case p is the currently running process (which
 144                  * it might be in some circumstances, or if this code
 145                  * gets moved into exit as suggested above), clear
 146                  * p_addrspace before calling as_destroy. Otherwise if
 147                  * as_destroy sleeps (which is quite possible) when we
 148                  * come back we'll be calling as_activate on a
 149                  * half-destroyed address space. This tends to be
 150                  * messily fatal.
 151                  */
 152                 struct addrspace *as;
 153 
 154                 as_deactivate();
 155                 as = curproc_setas(NULL);
 156                 as_destroy(as);
 157         }
 158 #endif // UW
 159 
 160 #ifdef UW
 161         if (proc->console) {
 162           vfs_close(proc->console);
 163         }
 164 #endif // UW
 165 
 166         threadarray_cleanup(&proc->p_threads);
 167         spinlock_cleanup(&proc->p_lock);
 168 
 169         kfree(proc->p_name);
 170         kfree(proc);
 171 
 172 #ifdef UW
 173         /* decrement the process count */
 174         /* note: kproc is not included in the process count, but proc_destroy
 175            is never called on kproc (see KASSERT above), so we're OK to decrement
 176            the proc_count unconditionally here */
 177         P(proc_count_mutex); 
 178         KASSERT(proc_count > 0);
 179         proc_count--;
 180         /* signal the kernel menu thread if the process count has reached zero */
 181         if (proc_count == 0) {
 182           V(no_proc_sem);
 183         }
 184         V(proc_count_mutex);
 185 #endif // UW
 186         
 187 
 188 }
 189 
 190 /*
 191  * Create the process structure for the kernel.
 192  */
 193 void
 194 proc_bootstrap(void)
 195 {
 196   kproc = proc_create("[kernel]");
 197   if (kproc == NULL) {
 198     panic("proc_create for kproc failed\n");
 199   }
 200 #ifdef UW
 201   proc_count = 0;
 202   proc_count_mutex = sem_create("proc_count_mutex",1);
 203   if (proc_count_mutex == NULL) {
 204     panic("could not create proc_count_mutex semaphore\n");
 205   }
 206   no_proc_sem = sem_create("no_proc_sem",0);
 207   if (no_proc_sem == NULL) {
 208     panic("could not create no_proc_sem semaphore\n");
 209   }
 210 #endif // UW 
 211 }
 212 
 213 /*
 214  * Create a fresh proc for use by runprogram.
 215  *
 216  * It will have no address space and will inherit the current
 217  * process's (that is, the kernel menu's) current directory.
 218  */
 219 struct proc *
 220 proc_create_runprogram(const char *name)
 221 {
 222         struct proc *proc;
 223         char *console_path;
 224 
 225         proc = proc_create(name);
 226         if (proc == NULL) {
 227                 return NULL;
 228         }
 229 
 230 #ifdef UW
 231         /* open the console - this should always succeed */
 232         console_path = kstrdup("con:");
 233         if (console_path == NULL) {
 234           panic("unable to copy console path name during process creation\n");
 235         }
 236         if (vfs_open(console_path,O_WRONLY,0,&(proc->console))) {
 237           panic("unable to open the console during process creation\n");
 238         }
 239         kfree(console_path);
 240 #endif // UW
 241           
 242         /* VM fields */
 243 
 244         proc->p_addrspace = NULL;
 245 
 246         /* VFS fields */
 247 
 248 #ifdef UW
 249         /* we do not need to acquire the p_lock here, the running thread should
 250            have the only reference to this process */
 251         /* also, acquiring the p_lock is problematic because VOP_INCREF may block */
 252         if (curproc->p_cwd != NULL) {
 253                 VOP_INCREF(curproc->p_cwd);
 254                 proc->p_cwd = curproc->p_cwd;
 255         }
 256 #else // UW
 257         spinlock_acquire(&curproc->p_lock);
 258         if (curproc->p_cwd != NULL) {
 259                 VOP_INCREF(curproc->p_cwd);
 260                 proc->p_cwd = curproc->p_cwd;
 261         }
 262         spinlock_release(&curproc->p_lock);
 263 #endif // UW
 264 
 265 #ifdef UW
 266         /* increment the count of processes */
 267         /* we are assuming that all procs, including those created by fork(),
 268            are created using a call to proc_create_runprogram  */
 269         P(proc_count_mutex); 
 270         proc_count++;
 271         V(proc_count_mutex);
 272 #endif // UW
 273 
 274         return proc;
 275 }
 276 
 277 /*
 278  * Add a thread to a process. Either the thread or the process might
 279  * or might not be current.
 280  */
 281 int
 282 proc_addthread(struct proc *proc, struct thread *t)
 283 {
 284         int result;
 285 
 286         KASSERT(t->t_proc == NULL);
 287 
 288         spinlock_acquire(&proc->p_lock);
 289         result = threadarray_add(&proc->p_threads, t, NULL);
 290         spinlock_release(&proc->p_lock);
 291         if (result) {
 292                 return result;
 293         }
 294         t->t_proc = proc;
 295         return 0;
 296 }
 297 
 298 /*
 299  * Remove a thread from its process. Either the thread or the process
 300  * might or might not be current.
 301  */
 302 void
 303 proc_remthread(struct thread *t)
 304 {
 305         struct proc *proc;
 306         unsigned i, num;
 307 
 308         proc = t->t_proc;
 309         KASSERT(proc != NULL);
 310 
 311         spinlock_acquire(&proc->p_lock);
 312         /* ugh: find the thread in the array */
 313         num = threadarray_num(&proc->p_threads);
 314         for (i=0; i<num; i++) {
 315                 if (threadarray_get(&proc->p_threads, i) == t) {
 316                         threadarray_remove(&proc->p_threads, i);
 317                         spinlock_release(&proc->p_lock);
 318                         t->t_proc = NULL;
 319                         return;
 320                 }
 321         }
 322         /* Did not find it. */
 323         spinlock_release(&proc->p_lock);
 324         panic("Thread (%p) has escaped from its process (%p)\n", t, proc);
 325 }
 326 
 327 /*
 328  * Fetch the address space of the current process. Caution: it isn't
 329  * refcounted. If you implement multithreaded processes, make sure to
 330  * set up a refcount scheme or some other method to make this safe.
 331  */
 332 struct addrspace *
 333 curproc_getas(void)
 334 {
 335         struct addrspace *as;
 336 #ifdef UW
 337         /* Until user processes are created, threads used in testing 
 338          * (i.e., kernel threads) have no process or address space.
 339          */
 340         if (curproc == NULL) {
 341                 return NULL;
 342         }
 343 #endif
 344 
 345         spinlock_acquire(&curproc->p_lock);
 346         as = curproc->p_addrspace;
 347         spinlock_release(&curproc->p_lock);
 348         return as;
 349 }
 350 
 351 /*
 352  * Change the address space of the current process, and return the old
 353  * one.
 354  */
 355 struct addrspace *
 356 curproc_setas(struct addrspace *newas)
 357 {
 358         struct addrspace *oldas;
 359         struct proc *proc = curproc;
 360 
 361         spinlock_acquire(&proc->p_lock);
 362         oldas = proc->p_addrspace;
 363         proc->p_addrspace = newas;
 364         spinlock_release(&proc->p_lock);
 365         return oldas;
 366 }

/* [<][>][^][v][top][bottom][index][help] */