root/proc.c

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

DEFINITIONS

This source file includes following definitions.
  1. pinit
  2. allocproc
  3. userinit
  4. growproc
  5. fork
  6. exit
  7. wait
  8. scheduler
  9. sched
  10. yield
  11. forkret
  12. sleep
  13. wakeup1
  14. wakeup
  15. kill
  16. procdump

   1 #include "types.h"
   2 #include "defs.h"
   3 #include "param.h"
   4 #include "memlayout.h"
   5 #include "mmu.h"
   6 #include "x86.h"
   7 #include "proc.h"
   8 #include "spinlock.h"
   9 
  10 struct {
  11   struct spinlock lock;
  12   struct proc proc[NPROC];
  13 } ptable;
  14 
  15 static struct proc *initproc;
  16 
  17 int nextpid = 1;
  18 extern void forkret(void);
  19 extern void trapret(void);
  20 
  21 static void wakeup1(void *chan);
  22 
  23 void
  24 pinit(void)
  25 {
  26   initlock(&ptable.lock, "ptable");
  27 }
  28 
  29 //PAGEBREAK: 32
  30 // Look in the process table for an UNUSED proc.
  31 // If found, change state to EMBRYO and initialize
  32 // state required to run in the kernel.
  33 // Otherwise return 0.
  34 static struct proc*
  35 allocproc(void)
  36 {
  37   struct proc *p;
  38   char *sp;
  39 
  40   acquire(&ptable.lock);
  41   for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
  42     if(p->state == UNUSED)
  43       goto found;
  44   release(&ptable.lock);
  45   return 0;
  46 
  47 found:
  48   p->state = EMBRYO;
  49   p->pid = nextpid++;
  50   release(&ptable.lock);
  51 
  52   // Allocate kernel stack.
  53   if((p->kstack = kalloc()) == 0){
  54     p->state = UNUSED;
  55     return 0;
  56   }
  57   sp = p->kstack + KSTACKSIZE;
  58   
  59   // Leave room for trap frame.
  60   sp -= sizeof *p->tf;
  61   p->tf = (struct trapframe*)sp;
  62   
  63   // Set up new context to start executing at forkret,
  64   // which returns to trapret.
  65   sp -= 4;
  66   *(uint*)sp = (uint)trapret;
  67 
  68   sp -= sizeof *p->context;
  69   p->context = (struct context*)sp;
  70   memset(p->context, 0, sizeof *p->context);
  71   p->context->eip = (uint)forkret;
  72 
  73   return p;
  74 }
  75 
  76 //PAGEBREAK: 32
  77 // Set up first user process.
  78 void
  79 userinit(void)
  80 {
  81   struct proc *p;
  82   extern char _binary_initcode_start[], _binary_initcode_size[];
  83   
  84   p = allocproc();
  85   initproc = p;
  86   if((p->pgdir = setupkvm()) == 0)
  87     panic("userinit: out of memory?");
  88   inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
  89   p->sz = PGSIZE;
  90   memset(p->tf, 0, sizeof(*p->tf));
  91   p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
  92   p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
  93   p->tf->es = p->tf->ds;
  94   p->tf->ss = p->tf->ds;
  95   p->tf->eflags = FL_IF;
  96   p->tf->esp = PGSIZE;
  97   p->tf->eip = 0;  // beginning of initcode.S
  98 
  99   safestrcpy(p->name, "initcode", sizeof(p->name));
 100   p->cwd = namei("/");
 101 
 102   p->state = RUNNABLE;
 103 }
 104 
 105 // Grow current process's memory by n bytes.
 106 // Return 0 on success, -1 on failure.
 107 int
 108 growproc(int n)
 109 {
 110   uint sz;
 111   
 112   sz = proc->sz;
 113   if(n > 0){
 114     if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0)
 115       return -1;
 116   } else if(n < 0){
 117     if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0)
 118       return -1;
 119   }
 120   proc->sz = sz;
 121   switchuvm(proc);
 122   return 0;
 123 }
 124 
 125 // Create a new process copying p as the parent.
 126 // Sets up stack to return as if from system call.
 127 // Caller must set state of returned proc to RUNNABLE.
 128 int
 129 fork(void)
 130 {
 131   int i, pid;
 132   struct proc *np;
 133 
 134   // Allocate process.
 135   if((np = allocproc()) == 0)
 136     return -1;
 137 
 138   // Copy process state from p.
 139   if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){
 140     kfree(np->kstack);
 141     np->kstack = 0;
 142     np->state = UNUSED;
 143     return -1;
 144   }
 145   np->sz = proc->sz;
 146   np->parent = proc;
 147   *np->tf = *proc->tf;
 148 
 149   // Clear %eax so that fork returns 0 in the child.
 150   np->tf->eax = 0;
 151 
 152   for(i = 0; i < NOFILE; i++)
 153     if(proc->ofile[i])
 154       np->ofile[i] = filedup(proc->ofile[i]);
 155   np->cwd = idup(proc->cwd);
 156 
 157   safestrcpy(np->name, proc->name, sizeof(proc->name));
 158  
 159   pid = np->pid;
 160 
 161   // lock to force the compiler to emit the np->state write last.
 162   acquire(&ptable.lock);
 163   np->state = RUNNABLE;
 164   release(&ptable.lock);
 165   
 166   return pid;
 167 }
 168 
 169 // Exit the current process.  Does not return.
 170 // An exited process remains in the zombie state
 171 // until its parent calls wait() to find out it exited.
 172 void
 173 exit(void)
 174 {
 175   struct proc *p;
 176   int fd;
 177 
 178   if(proc == initproc)
 179     panic("init exiting");
 180 
 181   // Close all open files.
 182   for(fd = 0; fd < NOFILE; fd++){
 183     if(proc->ofile[fd]){
 184       fileclose(proc->ofile[fd]);
 185       proc->ofile[fd] = 0;
 186     }
 187   }
 188 
 189   begin_op();
 190   iput(proc->cwd);
 191   end_op();
 192   proc->cwd = 0;
 193 
 194   acquire(&ptable.lock);
 195 
 196   // Parent might be sleeping in wait().
 197   wakeup1(proc->parent);
 198 
 199   // Pass abandoned children to init.
 200   for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 201     if(p->parent == proc){
 202       p->parent = initproc;
 203       if(p->state == ZOMBIE)
 204         wakeup1(initproc);
 205     }
 206   }
 207 
 208   // Jump into the scheduler, never to return.
 209   proc->state = ZOMBIE;
 210   sched();
 211   panic("zombie exit");
 212 }
 213 
 214 // Wait for a child process to exit and return its pid.
 215 // Return -1 if this process has no children.
 216 int
 217 wait(void)
 218 {
 219   struct proc *p;
 220   int havekids, pid;
 221 
 222   acquire(&ptable.lock);
 223   for(;;){
 224     // Scan through table looking for zombie children.
 225     havekids = 0;
 226     for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 227       if(p->parent != proc)
 228         continue;
 229       havekids = 1;
 230       if(p->state == ZOMBIE){
 231         // Found one.
 232         pid = p->pid;
 233         kfree(p->kstack);
 234         p->kstack = 0;
 235         freevm(p->pgdir);
 236         p->state = UNUSED;
 237         p->pid = 0;
 238         p->parent = 0;
 239         p->name[0] = 0;
 240         p->killed = 0;
 241         release(&ptable.lock);
 242         return pid;
 243       }
 244     }
 245 
 246     // No point waiting if we don't have any children.
 247     if(!havekids || proc->killed){
 248       release(&ptable.lock);
 249       return -1;
 250     }
 251 
 252     // Wait for children to exit.  (See wakeup1 call in proc_exit.)
 253     sleep(proc, &ptable.lock);  //DOC: wait-sleep
 254   }
 255 }
 256 
 257 //PAGEBREAK: 42
 258 // Per-CPU process scheduler.
 259 // Each CPU calls scheduler() after setting itself up.
 260 // Scheduler never returns.  It loops, doing:
 261 //  - choose a process to run
 262 //  - swtch to start running that process
 263 //  - eventually that process transfers control
 264 //      via swtch back to the scheduler.
 265 void
 266 scheduler(void)
 267 {
 268   struct proc *p;
 269 
 270   for(;;){
 271     // Enable interrupts on this processor.
 272     sti();
 273 
 274     // Loop over process table looking for process to run.
 275     acquire(&ptable.lock);
 276     for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 277       if(p->state != RUNNABLE)
 278         continue;
 279 
 280       // Switch to chosen process.  It is the process's job
 281       // to release ptable.lock and then reacquire it
 282       // before jumping back to us.
 283       proc = p;
 284       switchuvm(p);
 285       p->state = RUNNING;
 286       swtch(&cpu->scheduler, proc->context);
 287       switchkvm();
 288 
 289       // Process is done running for now.
 290       // It should have changed its p->state before coming back.
 291       proc = 0;
 292     }
 293     release(&ptable.lock);
 294 
 295   }
 296 }
 297 
 298 // Enter scheduler.  Must hold only ptable.lock
 299 // and have changed proc->state.
 300 void
 301 sched(void)
 302 {
 303   int intena;
 304 
 305   if(!holding(&ptable.lock))
 306     panic("sched ptable.lock");
 307   if(cpu->ncli != 1)
 308     panic("sched locks");
 309   if(proc->state == RUNNING)
 310     panic("sched running");
 311   if(readeflags()&FL_IF)
 312     panic("sched interruptible");
 313   intena = cpu->intena;
 314   swtch(&proc->context, cpu->scheduler);
 315   cpu->intena = intena;
 316 }
 317 
 318 // Give up the CPU for one scheduling round.
 319 void
 320 yield(void)
 321 {
 322   acquire(&ptable.lock);  //DOC: yieldlock
 323   proc->state = RUNNABLE;
 324   sched();
 325   release(&ptable.lock);
 326 }
 327 
 328 // A fork child's very first scheduling by scheduler()
 329 // will swtch here.  "Return" to user space.
 330 void
 331 forkret(void)
 332 {
 333   static int first = 1;
 334   // Still holding ptable.lock from scheduler.
 335   release(&ptable.lock);
 336 
 337   if (first) {
 338     // Some initialization functions must be run in the context
 339     // of a regular process (e.g., they call sleep), and thus cannot 
 340     // be run from main().
 341     first = 0;
 342     iinit(ROOTDEV);
 343     initlog(ROOTDEV);
 344   }
 345   
 346   // Return to "caller", actually trapret (see allocproc).
 347 }
 348 
 349 // Atomically release lock and sleep on chan.
 350 // Reacquires lock when awakened.
 351 void
 352 sleep(void *chan, struct spinlock *lk)
 353 {
 354   if(proc == 0)
 355     panic("sleep");
 356 
 357   if(lk == 0)
 358     panic("sleep without lk");
 359 
 360   // Must acquire ptable.lock in order to
 361   // change p->state and then call sched.
 362   // Once we hold ptable.lock, we can be
 363   // guaranteed that we won't miss any wakeup
 364   // (wakeup runs with ptable.lock locked),
 365   // so it's okay to release lk.
 366   if(lk != &ptable.lock){  //DOC: sleeplock0
 367     acquire(&ptable.lock);  //DOC: sleeplock1
 368     release(lk);
 369   }
 370 
 371   // Go to sleep.
 372   proc->chan = chan;
 373   proc->state = SLEEPING;
 374   sched();
 375 
 376   // Tidy up.
 377   proc->chan = 0;
 378 
 379   // Reacquire original lock.
 380   if(lk != &ptable.lock){  //DOC: sleeplock2
 381     release(&ptable.lock);
 382     acquire(lk);
 383   }
 384 }
 385 
 386 //PAGEBREAK!
 387 // Wake up all processes sleeping on chan.
 388 // The ptable lock must be held.
 389 static void
 390 wakeup1(void *chan)
 391 {
 392   struct proc *p;
 393 
 394   for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
 395     if(p->state == SLEEPING && p->chan == chan)
 396       p->state = RUNNABLE;
 397 }
 398 
 399 // Wake up all processes sleeping on chan.
 400 void
 401 wakeup(void *chan)
 402 {
 403   acquire(&ptable.lock);
 404   wakeup1(chan);
 405   release(&ptable.lock);
 406 }
 407 
 408 // Kill the process with the given pid.
 409 // Process won't exit until it returns
 410 // to user space (see trap in trap.c).
 411 int
 412 kill(int pid)
 413 {
 414   struct proc *p;
 415 
 416   acquire(&ptable.lock);
 417   for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 418     if(p->pid == pid){
 419       p->killed = 1;
 420       // Wake process from sleep if necessary.
 421       if(p->state == SLEEPING)
 422         p->state = RUNNABLE;
 423       release(&ptable.lock);
 424       return 0;
 425     }
 426   }
 427   release(&ptable.lock);
 428   return -1;
 429 }
 430 
 431 //PAGEBREAK: 36
 432 // Print a process listing to console.  For debugging.
 433 // Runs when user types ^P on console.
 434 // No lock to avoid wedging a stuck machine further.
 435 void
 436 procdump(void)
 437 {
 438   static char *states[] = {
 439   [UNUSED]    "unused",
 440   [EMBRYO]    "embryo",
 441   [SLEEPING]  "sleep ",
 442   [RUNNABLE]  "runble",
 443   [RUNNING]   "run   ",
 444   [ZOMBIE]    "zombie"
 445   };
 446   int i;
 447   struct proc *p;
 448   char *state;
 449   uint pc[10];
 450   
 451   for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
 452     if(p->state == UNUSED)
 453       continue;
 454     if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
 455       state = states[p->state];
 456     else
 457       state = "???";
 458     cprintf("%d %s %s", p->pid, state, p->name);
 459     if(p->state == SLEEPING){
 460       getcallerpcs((uint*)p->context->ebp+2, pc);
 461       for(i=0; i<10 && pc[i] != 0; i++)
 462         cprintf(" %p", pc[i]);
 463     }
 464     cprintf("\n");
 465   }
 466 }

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