diff source/proc.c @ 0:c450faca55f4

Init
author Tatsuki IHA <innparusu@cr.ie.u-ryukyu.ac.jp>
date Sun, 22 Oct 2017 18:25:39 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/proc.c	Sun Oct 22 18:25:39 2017 +0900
@@ -0,0 +1,453 @@
+/*****************************************************************
+*       proc.c
+*       adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz
+*       University of Otago
+*
+********************************************************************/
+
+
+
+#include "types.h"
+#include "defs.h"
+#include "param.h"
+#include "memlayout.h"
+#include "mmu.h"
+#include "arm.h"
+#include "proc.h"
+#include "spinlock.h"
+
+struct {
+  struct spinlock lock;
+  struct proc proc[NPROC];
+} ptable;
+
+static struct proc *initproc;
+
+int first_sched = 1;
+int nextpid = 1;
+extern void forkret(void);
+extern void trapret(void);
+
+static void wakeup1(void *chan);
+
+void
+pinit(void)
+{
+  memset(&ptable, 0, sizeof(ptable));
+  initlock(&ptable.lock, "ptable");
+
+}
+
+//PAGEBREAK: 32
+// Look in the process table for an UNUSED proc.
+// If found, change state to EMBRYO and initialize
+// state required to run in the kernel.
+// Otherwise return 0.
+static struct proc*
+allocproc(void)
+{
+  struct proc *p;
+  char *sp;
+
+  acquire(&ptable.lock);
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
+    if(p->state == UNUSED)
+      goto found;
+  release(&ptable.lock);
+  return 0;
+
+found:
+  p->state = EMBRYO;
+  p->pid = nextpid++;
+  release(&ptable.lock);
+
+  // Allocate kernel stack.
+  if((p->kstack = kalloc()) == 0){
+    p->state = UNUSED;
+    return 0;
+  }
+  memset(p->kstack, 0, PGSIZE);
+  sp = p->kstack + KSTACKSIZE;
+  
+  // Leave room for trap frame.
+  sp -= sizeof *p->tf;
+  p->tf = (struct trapframe*)sp;
+  
+  // Set up new context to start executing at forkret,
+  // which returns to trapret.
+
+  sp -= sizeof *p->context;
+  p->context = (struct context*)sp;
+  memset(p->context, 0, sizeof *p->context);
+  p->context->pc = (uint)forkret;
+  p->context->lr = (uint)trapret;
+
+  return p;
+}
+
+//PAGEBREAK: 32
+// Set up first user process.
+void
+userinit(void)
+{
+  struct proc *p;
+  extern char _binary_initcode_start[], _binary_initcode_end[];
+  uint _binary_initcode_size;
+
+  _binary_initcode_size = (uint)_binary_initcode_end - (uint)_binary_initcode_start;
+  p = allocproc();
+//cprintf("after allocproc: initcode start: %x end %x\n", _binary_initcode_start, _binary_initcode_end);
+  initproc = p;
+//cprintf("initproc is %x\n", initproc);
+  if((p->pgdir = setupkvm()) == 0)
+    panic("userinit: out of memory?");
+//cprintf("after setupkvm\n");
+  inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size);
+//cprintf("after initkvm\n");
+  p->sz = PGSIZE;
+  memset(p->tf, 0, sizeof(*p->tf));
+  p->tf->spsr = 0x10;
+  p->tf->sp = PGSIZE;
+  p->tf->pc = 0;  // beginning of initcode.S
+
+  safestrcpy(p->name, "initcode", sizeof(p->name));
+  p->cwd = namei("/");
+
+  p->state = RUNNABLE;
+}
+
+// Grow current process's memory by n bytes.
+// Return 0 on success, -1 on failure.
+int
+growproc(int n)
+{
+  uint sz;
+
+  sz = curr_proc->sz;
+  if(n > 0){
+    if((sz = allocuvm(curr_proc->pgdir, sz, sz + n)) == 0)
+      return -1;
+  } else if(n < 0){
+    if((sz = deallocuvm(curr_proc->pgdir, sz, sz + n)) == 0)
+      return -1;
+  }
+  curr_proc->sz = sz;
+  switchuvm(curr_proc);
+  return 0;
+}
+
+// Create a new process copying p as the parent.
+// Sets up stack to return as if from system call.
+// Caller must set state of returned proc to RUNNABLE.
+int
+fork(void)
+{
+  int i, pid;
+  struct proc *np;
+
+  // Allocate process.
+  if((np = allocproc()) == 0)
+    return -1;
+
+  // Copy process state from p.
+  if((np->pgdir = copyuvm(curr_proc->pgdir, curr_proc->sz)) == 0){
+    kfree(np->kstack);
+    np->kstack = 0;
+    np->state = UNUSED;
+    return -1;
+  }
+  np->sz = curr_proc->sz;
+  np->parent = curr_proc;
+  *np->tf = *curr_proc->tf;
+
+  // Clear r0 so that fork returns 0 in the child.
+  np->tf->r0 = 0;
+
+  for(i = 0; i < NOFILE; i++)
+    if(curr_proc->ofile[i])
+      np->ofile[i] = filedup(curr_proc->ofile[i]);
+  np->cwd = idup(curr_proc->cwd);
+ 
+  pid = np->pid;
+  np->state = RUNNABLE;
+  safestrcpy(np->name, curr_proc->name, sizeof(curr_proc->name));
+  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(curr_proc == initproc)
+    panic("init exiting");
+
+  // Close all open files.
+  for(fd = 0; fd < NOFILE; fd++){
+    if(curr_proc->ofile[fd]){
+      fileclose(curr_proc->ofile[fd]);
+      curr_proc->ofile[fd] = 0;
+    }
+  }
+
+  iput(curr_proc->cwd);
+  curr_proc->cwd = 0;
+
+  acquire(&ptable.lock);
+
+  // Parent might be sleeping in wait().
+  wakeup1(curr_proc->parent);
+
+  // Pass abandoned children to init.
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+    if(p->parent == curr_proc){
+      p->parent = initproc;
+      if(p->state == ZOMBIE)
+        wakeup1(initproc);
+    }
+  }
+
+  // Jump into the scheduler, never to return.
+  curr_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 != curr_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 || curr_proc->killed){
+      release(&ptable.lock);
+      return -1;
+    }
+//cprintf("inside wait before calling sleep\n");
+    // Wait for children to exit.  (See wakeup1 call in proc_exit.)
+    sleep(curr_proc, &ptable.lock);  //DOC: wait-sleep
+  }
+}
+
+//PAGEBREAK: 42
+// Per-CPU process scheduler.
+// Each CPU calls scheduler() after setting itself up.
+// Scheduler never returns.  It loops, doing:
+//  - choose a process to run
+//  - swtch to start running that process
+//  - eventually that process transfers control
+//      via swtch back to the scheduler.
+void
+scheduler(void)
+{
+  struct proc *p;
+
+  for(;;){
+    // Enable interrupts on this processor.
+    //cprintf("before enabling interrupts\n");
+    if(first_sched) first_sched = 0;
+    else sti();
+
+    // Loop over process table looking for process to run.
+    acquire(&ptable.lock);
+    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+      if(p->state != RUNNABLE)
+        continue;
+
+      // Switch to chosen process.  It is the process's job
+      // to release ptable.lock and then reacquire it
+      // before jumping back to us.
+      curr_proc = p;
+//cprintf("before switching page table\n");
+      switchuvm(p);
+      p->state = RUNNING;
+//cprintf("after switching page table\n");
+
+      swtch(&curr_cpu->scheduler, curr_proc->context);
+
+      switchkvm();
+
+      // Process is done running for now.
+      // It should have changed its p->state before coming back.
+      curr_proc = 0;
+    }
+    release(&ptable.lock);
+
+  }
+}
+
+// Enter scheduler.  Must hold only ptable.lock
+// and have changed proc->state.
+void
+sched(void)
+{
+  int intena;
+
+  if(!holding(&ptable.lock))
+    panic("sched ptable.lock");
+  if(curr_cpu->ncli != 1)
+    panic("sched locks");
+  if(curr_proc->state == RUNNING)
+    panic("sched running");
+  if(!(readcpsr()&PSR_DISABLE_IRQ))
+    panic("sched interruptible");
+  intena = curr_cpu->intena;
+  swtch(&curr_proc->context, curr_cpu->scheduler);
+  curr_cpu->intena = intena;
+}
+
+// Give up the CPU for one scheduling round.
+void
+yield(void)
+{
+  acquire(&ptable.lock);  //DOC: yieldlock
+  curr_proc->state = RUNNABLE;
+  sched();
+  release(&ptable.lock);
+}
+
+// A fork child's very first scheduling by scheduler()
+// will swtch here.  "Return" to user space.
+void
+forkret(void)
+{
+  static int first = 1;
+  // Still holding ptable.lock from scheduler.
+  release(&ptable.lock);
+
+  if (first) {
+    // Some initialization functions must be run in the context
+    // of a regular process (e.g., they call sleep), and thus cannot 
+    // be run from main().
+    first = 0;
+    initlog();
+  }
+//cprintf("inside forkret\n");
+  
+  // Return to "caller", actually trapret (see allocproc).
+}
+
+// Atomically release lock and sleep on chan.
+// Reacquires lock when awakened.
+void
+sleep(void *chan, struct spinlock *lk)
+{
+  if(curr_proc == 0)
+    panic("sleep");
+
+  if(lk == 0)
+    panic("sleep without lk");
+
+  // Must acquire ptable.lock in order to
+  // change p->state and then call sched.
+  // Once we hold ptable.lock, we can be
+  // guaranteed that we won't miss any wakeup
+  // (wakeup runs with ptable.lock locked),
+  // so it's okay to release lk.
+  if(lk != &ptable.lock){  //DOC: sleeplock0
+    acquire(&ptable.lock);  //DOC: sleeplock1
+    release(lk);
+  }
+
+  // Go to sleep.
+  curr_proc->chan = chan;
+  curr_proc->state = SLEEPING;
+//cprintf("inside sleep before calling sched\n");
+  sched();
+
+  // Tidy up.
+  curr_proc->chan = 0;
+
+  // Reacquire original lock.
+  if(lk != &ptable.lock){  //DOC: sleeplock2
+    release(&ptable.lock);
+    acquire(lk);
+  }
+}
+
+//PAGEBREAK!
+// Wake up all processes sleeping on chan.
+// The ptable lock must be held.
+static void
+wakeup1(void *chan)
+{
+  struct proc *p;
+
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
+    if(p->state == SLEEPING && p->chan == chan)
+      p->state = RUNNABLE;
+}
+
+// Wake up all processes sleeping on chan.
+void
+wakeup(void *chan)
+{
+  acquire(&ptable.lock);
+  wakeup1(chan);
+  release(&ptable.lock);
+}
+
+// Kill the process with the given pid.
+// Process won't exit until it returns
+// to user space (see trap in trap.c).
+int
+kill(int pid)
+{
+  struct proc *p;
+
+  acquire(&ptable.lock);
+  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+    if(p->pid == pid){
+      p->killed = 1;
+      // Wake process from sleep if necessary.
+      if(p->state == SLEEPING)
+        p->state = RUNNABLE;
+      release(&ptable.lock);
+      return 0;
+    }
+  }
+  release(&ptable.lock);
+  return -1;
+}
+
+//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)
+{
+}
+
+