diff options
Diffstat (limited to 'proc.c')
| -rw-r--r-- | proc.c | 257 | 
1 files changed, 131 insertions, 126 deletions
@@ -17,53 +17,18 @@ int nextpid = 1;  extern void forkret(void);  extern void trapret(void); +static void wakeup1(void *chan); +  void  pinit(void)  {    initlock(&ptable.lock, "ptable");  } -//PAGEBREAK: 36 -// Print a process listing to console.  For debugging. -// Runs when user types ^P on console. -// No lock to avoid wedging a stuck machine further. -void -procdump(void) -{ -  static char *states[] = { -  [UNUSED]    "unused", -  [EMBRYO]    "embryo", -  [SLEEPING]  "sleep ", -  [RUNNABLE]  "runble", -  [RUNNING]   "run   ", -  [ZOMBIE]    "zombie" -  }; -  int i; -  struct proc *p; -  char *state; -  uint pc[10]; -   -  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ -    if(p->state == UNUSED) -      continue; -    if(p->state >= 0 && p->state < NELEM(states) && states[p->state]) -      state = states[p->state]; -    else -      state = "???"; -    cprintf("%d %s %s", p->pid, state, p->name); -    if(p->state == SLEEPING){ -      getcallerpcs((uint*)p->context->ebp+2, pc); -      for(i=0; i<10 && pc[i] != 0; i++) -        cprintf(" %p", pc[i]); -    } -    cprintf("\n"); -  } -} - -  //PAGEBREAK: 32  // Look in the process table for an UNUSED proc. -// If found, change state to EMBRYO and return it. +// If found, change state to EMBRYO and initialize +// state required to run in the kernel.  // Otherwise return 0.  static struct proc*  allocproc(void) @@ -95,7 +60,7 @@ found:    p->tf = (struct trapframe*)sp;    // Set up new context to start executing at forkret, -  // which returns to trapret (see below). +  // which returns to trapret.    sp -= 4;    *(uint*)sp = (uint)trapret; @@ -103,6 +68,7 @@ found:    p->context = (struct context*)sp;    memset(p->context, 0, sizeof *p->context);    p->context->eip = (uint)forkret; +    return p;  } @@ -116,12 +82,10 @@ userinit(void)    p = allocproc();    initproc = p; -  if (!(p->pgdir = setupkvm())) +  if((p->pgdir = setupkvm()) == 0)      panic("userinit: out of memory?"); -  if (!allocuvm(p->pgdir, 0x0, (int)_binary_initcode_size)) -    panic("userinit: out of memory?"); -  inituvm(p->pgdir, 0x0, _binary_initcode_start, (int)_binary_initcode_size); -  p->sz = PGROUNDUP((int)_binary_initcode_size); +  inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); +  p->sz = PGSIZE;    memset(p->tf, 0, sizeof(*p->tf));    p->tf->cs = (SEG_UCODE << 3) | DPL_USER;    p->tf->ds = (SEG_UDATA << 3) | DPL_USER; @@ -142,14 +106,17 @@ userinit(void)  int  growproc(int n)  { +  uint sz; +   +  sz = proc->sz;    if(n > 0){ -    if (!allocuvm(proc->pgdir, (char *)proc->sz, n)) +    if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0)        return -1;    } else if(n < 0){ -    if (!deallocuvm(proc->pgdir, (char *)(proc->sz + n), 0 - n)) +    if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0)        return -1;    } -  proc->sz += n; +  proc->sz = sz;    switchuvm(proc);    return 0;  } @@ -168,7 +135,7 @@ fork(void)      return -1;    // Copy process state from p. -  if (!(np->pgdir = copyuvm(proc->pgdir, proc->sz))) { +  if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){      kfree(np->kstack);      np->kstack = 0;      np->state = UNUSED; @@ -192,6 +159,92 @@ fork(void)    return pid;  } +// Exit the current process.  Does not return. +// An exited process remains in the zombie state +// until its parent calls wait() to find out it exited. +void +exit(void) +{ +  struct proc *p; +  int fd; + +  if(proc == initproc) +    panic("init exiting"); + +  // Close all open files. +  for(fd = 0; fd < NOFILE; fd++){ +    if(proc->ofile[fd]){ +      fileclose(proc->ofile[fd]); +      proc->ofile[fd] = 0; +    } +  } + +  iput(proc->cwd); +  proc->cwd = 0; + +  acquire(&ptable.lock); + +  // Parent might be sleeping in wait(). +  wakeup1(proc->parent); + +  // Pass abandoned children to init. +  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ +    if(p->parent == proc){ +      p->parent = initproc; +      if(p->state == ZOMBIE) +        wakeup1(initproc); +    } +  } + +  // Jump into the scheduler, never to return. +  proc->state = ZOMBIE; +  sched(); +  panic("zombie exit"); +} + +// Wait for a child process to exit and return its pid. +// Return -1 if this process has no children. +int +wait(void) +{ +  struct proc *p; +  int havekids, pid; + +  acquire(&ptable.lock); +  for(;;){ +    // Scan through table looking for zombie children. +    havekids = 0; +    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ +      if(p->parent != proc) +        continue; +      havekids = 1; +      if(p->state == ZOMBIE){ +        // Found one. +        pid = p->pid; +        kfree(p->kstack); +        p->kstack = 0; +        freevm(p->pgdir); +        p->state = UNUSED; +        p->pid = 0; +        p->parent = 0; +        p->name[0] = 0; +        p->killed = 0; +        release(&ptable.lock); +        return pid; +      } +    } + +    // No point waiting if we don't have any children. +    if(!havekids || proc->killed){ +      release(&ptable.lock); +      return -1; +    } + +    // Wait for children to exit.  (See wakeup1 call in proc_exit.) +    sleep(proc, &ptable.lock);  //DOC: wait-sleep +  } +} +  //PAGEBREAK: 42  // Per-CPU process scheduler.  // Each CPU calls scheduler() after setting itself up. @@ -356,89 +409,41 @@ kill(int pid)    return -1;  } -// Exit the current process.  Does not return. -// An exited process remains in the zombie state -// until its parent calls wait() to find out it exited. +//PAGEBREAK: 36 +// Print a process listing to console.  For debugging. +// Runs when user types ^P on console. +// No lock to avoid wedging a stuck machine further.  void -exit(void) +procdump(void)  { +  static char *states[] = { +  [UNUSED]    "unused", +  [EMBRYO]    "embryo", +  [SLEEPING]  "sleep ", +  [RUNNABLE]  "runble", +  [RUNNING]   "run   ", +  [ZOMBIE]    "zombie" +  }; +  int i;    struct proc *p; -  int fd; - -  if(proc == initproc) -    panic("init exiting"); - -  // Close all open files. -  for(fd = 0; fd < NOFILE; fd++){ -    if(proc->ofile[fd]){ -      fileclose(proc->ofile[fd]); -      proc->ofile[fd] = 0; -    } -  } - -  iput(proc->cwd); -  proc->cwd = 0; - -  acquire(&ptable.lock); - -  // Parent might be sleeping in wait(). -  wakeup1(proc->parent); - -  // Pass abandoned children to init. +  char *state; +  uint pc[10]; +      for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ -    if(p->parent == proc){ -      p->parent = initproc; -      if(p->state == ZOMBIE) -        wakeup1(initproc); +    if(p->state == UNUSED) +      continue; +    if(p->state >= 0 && p->state < NELEM(states) && states[p->state]) +      state = states[p->state]; +    else +      state = "???"; +    cprintf("%d %s %s", p->pid, state, p->name); +    if(p->state == SLEEPING){ +      getcallerpcs((uint*)p->context->ebp+2, pc); +      for(i=0; i<10 && pc[i] != 0; i++) +        cprintf(" %p", pc[i]);      } +    cprintf("\n");    } - -  // Jump into the scheduler, never to return. -  proc->state = ZOMBIE; -  sched(); -  panic("zombie exit");  } -// Wait for a child process to exit and return its pid. -// Return -1 if this process has no children. -int -wait(void) -{ -  struct proc *p; -  int havekids, pid; - -  acquire(&ptable.lock); -  for(;;){ -    // Scan through table looking for zombie children. -    havekids = 0; -    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ -      if(p->parent != proc) -        continue; -      havekids = 1; -      if(p->state == ZOMBIE){ -        // Found one. -        pid = p->pid; -        kfree(p->kstack); -        p->kstack = 0; -        freevm(p->pgdir); -        p->state = UNUSED; -        p->pid = 0; -        p->parent = 0; -        p->name[0] = 0; -        p->killed = 0; -        release(&ptable.lock); -        return pid; -      } -    } - -    // No point waiting if we don't have any children. -    if(!havekids || proc->killed){ -      release(&ptable.lock); -      return -1; -    } - -    // Wait for children to exit.  (See wakeup1 call in proc_exit.) -    sleep(proc, &ptable.lock);  //DOC: wait-sleep -  } -}  | 
