solutions: Fix mangled p4.patch.
[pintos-anon] / solutions / p2.patch
index add0f5ac52989cd0a9277f21dc73bc2614334971..41f6764d445a0c27b2218abffec0bc202f95cf01 100644 (file)
@@ -1,87 +1,7 @@
-Index: src/threads/synch.c
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/synch.c,v
-retrieving revision 1.15
-diff -u -p -r1.15 synch.c
---- src/threads/synch.c        31 Dec 2004 21:13:38 -0000      1.15
-+++ src/threads/synch.c        1 Jan 2005 02:13:41 -0000
-@@ -330,3 +330,45 @@ cond_name (const struct condition *cond)
-   return cond->name;
- }
-+\f
-+/* Initializes LATCH and names it NAME (for debugging purposes).
-+   A latch is a boolean condition.  Until it is released for the
-+   first time, all threads block attempting to acquire.  After it
-+   is released once, all ongoing and subsequent acquisitions
-+   "fall through" immediately.  Releases after the first have no
-+   additional effect. */
-+void
-+latch_init (struct latch *latch, const char *name) 
-+{
-+  latch->released = false;
-+  lock_init (&latch->monitor_lock, name);
-+  cond_init (&latch->rel_cond, name);
-+}
-+
-+/* Acquires LATCH, blocking until it is released for the first
-+   time. */
-+void
-+latch_acquire (struct latch *latch) 
-+{
-+  lock_acquire (&latch->monitor_lock);
-+  if (!latch->released) 
-+    {
-+      cond_wait (&latch->rel_cond, &latch->monitor_lock);
-+      ASSERT (latch->released); 
-+    }
-+  lock_release (&latch->monitor_lock);
-+}
-+
-+/* Releases LATCH, causing all ongoing and subsequent
-+   acquisitions to pass through immediately. */
-+void
-+latch_release (struct latch *latch) 
-+{
-+  lock_acquire (&latch->monitor_lock);
-+  if (!latch->released)
-+    {
-+      latch->released = true;
-+      cond_signal (&latch->rel_cond, &latch->monitor_lock);
-+    }
-+  lock_release (&latch->monitor_lock);
-+}
-Index: src/threads/synch.h
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/synch.h,v
-retrieving revision 1.7
-diff -u -p -r1.7 synch.h
---- src/threads/synch.h        29 Sep 2004 01:04:09 -0000      1.7
-+++ src/threads/synch.h        1 Jan 2005 02:13:41 -0000
-@@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
- void cond_broadcast (struct condition *, struct lock *);
- const char *cond_name (const struct condition *);
-+/* Latch. */
-+struct latch 
-+  {
-+    bool released;              /* Released yet? */
-+    struct lock monitor_lock;   /* Monitor lock. */
-+    struct condition rel_cond;  /* Signaled when released. */
-+  };
-+
-+void latch_init (struct latch *, const char *);
-+void latch_acquire (struct latch *);
-+void latch_release (struct latch *);
-+
- #endif /* threads/synch.h */
 Index: src/threads/thread.c
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/thread.c,v
-retrieving revision 1.48
-diff -u -p -r1.48 thread.c
---- src/threads/thread.c       9 Oct 2004 18:01:37 -0000       1.48
-+++ src/threads/thread.c       1 Jan 2005 02:13:42 -0000
+diff -u src/threads/thread.c~ src/threads/thread.c
+--- src/threads/thread.c~
++++ src/threads/thread.c
 @@ -13,6 +13,7 @@
  #include "threads/synch.h"
  #ifdef USERPROG
@@ -90,106 +10,42 @@ diff -u -p -r1.48 thread.c
  #endif
  
  /* Random value for struct thread's `magic' member.
-@@ -81,6 +82,7 @@ thread_init (void) 
-   init_thread (initial_thread, "main", PRI_DEFAULT);
-   initial_thread->status = THREAD_RUNNING;
-   initial_thread->tid = allocate_tid ();
-+  sema_up (&initial_thread->can_die);
- }
- /* Starts preemptive thread scheduling by enabling interrupts.
-@@ -149,6 +151,7 @@ thread_create (const char *name, int pri
-   /* Initialize thread. */
-   init_thread (t, name, priority);
-   tid = t->tid = allocate_tid ();
-+  list_push_back (&thread_current ()->children, &t->children_elem);
-   /* Stack frame for kernel_thread(). */
-   kf = alloc_frame (t, sizeof *kf);
-@@ -241,16 +244,36 @@ thread_tid (void) 
+@@ -251,18 +252,19 @@ thread_tid (void) 
  void
  thread_exit (void) 
  {
-+  struct thread *t = thread_current ();
-+  struct list_elem *e, *next;
-+
    ASSERT (!intr_context ());
  
  #ifdef USERPROG
    process_exit ();
  #endif
+-
 +  syscall_exit ();
 +  
-+  /* Notify our parent that we're dying. */
-+  latch_release (&t->ready_to_die);
-+
-+  /* Notify our children that they can die. */
-+  for (e = list_begin (&t->children); e != list_end (&t->children);
-+       e = next) 
-+    {
-+      struct thread *child = list_entry (e, struct thread, children_elem);
-+      next = list_next (e);
-+      list_remove (e);
-+      sema_up (&child->can_die); 
-+    }
-+
-+  /* Wait until our parent is ready for us to die. */
-+  sema_down (&t->can_die);
-   /* Just set our status to dying and schedule another process.
-      We will be destroyed during the call to schedule_tail(). */
+   /* Remove thread from all threads list, set our status to dying,
+      and schedule another process.  That process will destroy us
+      when it calls thread_schedule_tail(). */
    intr_disable ();
--  thread_current ()->status = THREAD_DYING;
-+  t->status = THREAD_DYING;
+   list_remove (&thread_current()->allelem);
+   thread_current ()->status = THREAD_DYING;
    schedule ();
    NOT_REACHED ();
  }
-@@ -283,8 +290,22 @@ thread_block (void) 
-    This function will be implemented in problem 1-2.  For now, it
-    does nothing. */
--void
--thread_join (tid_t child_tid UNUSED) 
--{
-+int
-+thread_join (tid_t child_tid) 
-+{
-+  struct thread *cur = thread_current ();
-+  struct list_elem *e;
-+
-+  for (e = list_begin (&cur->children); e != list_end (&cur->children); ) 
-+    {
-+      struct thread *child = list_entry (e, struct thread, children_elem);
-+      e = list_next (e);
-+      if (child->tid == child_tid) 
-+        {
-+          latch_acquire (&child->ready_to_die);
-+          return child->exit_code;
-+        }
-+    }
-+  return -1;
- }
- /* Sets the current thread's priority to NEW_PRIORITY. */
-@@ -336,6 +379,12 @@ init_thread (struct thread *t, const cha
+@@ -400,6 +404,10 @@ init_thread (struct thread *t, const cha
    strlcpy (t->name, name, sizeof t->name);
    t->stack = (uint8_t *) t + PGSIZE;
    t->priority = priority;
-+  latch_init (&t->ready_to_die, "ready-to-die");
-+  sema_init (&t->can_die, 0, "can-die");
 +  list_init (&t->children);
-+  t->exit_code = -1;
++  t->wait_status = NULL;
 +  list_init (&t->fds);
 +  t->next_handle = 2;
    t->magic = THREAD_MAGIC;
  }
  
 Index: src/threads/thread.h
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/thread.h,v
-retrieving revision 1.28
-diff -u -p -r1.28 thread.h
---- src/threads/thread.h       29 Sep 2004 01:04:20 -0000      1.28
-+++ src/threads/thread.h       1 Jan 2005 02:13:42 -0000
+diff -u src/threads/thread.h~ src/threads/thread.h
+--- src/threads/thread.h~
++++ src/threads/thread.h
 @@ -4,6 +4,7 @@
  #include <debug.h>
  #include <list.h>
@@ -198,47 +54,54 @@ diff -u -p -r1.28 thread.h
  
  /* States in a thread's life cycle. */
  enum thread_status
-@@ -89,12 +90,23 @@ struct thread
+@@ -89,6 +90,10 @@ struct thread
      uint8_t *stack;                     /* Saved stack pointer. */
      int priority;                       /* Priority. */
  
-+    /* Members for implementing thread_join(). */
-+    struct latch ready_to_die;          /* Release when thread about to die. */
-+    struct semaphore can_die;           /* Up when thread allowed to die. */
-+    struct list children;               /* List of child threads. */
-+    struct list_elem children_elem;     /* Element of `children' list. */
-+    int exit_code;                      /* Return status. */
++    /* Owned by process.c. */
++    struct wait_status *wait_status;    /* This process's completion status. */
++    struct list children;               /* Completion status of children. */
 +
      /* Shared between thread.c and synch.c. */
      struct list_elem elem;              /* List element. */
  
- #ifdef USERPROG
+@@ -96,11 +102,31 @@ struct thread
      /* Owned by userprog/process.c. */
      uint32_t *pagedir;                  /* Page directory. */
+ #endif
++    struct file *bin_file;              /* Executable. */
 +
 +    /* Owned by syscall.c. */
 +    struct list fds;                    /* List of file descriptors. */
 +    int next_handle;                    /* Next handle value. */
- #endif
  
      /* Owned by thread.c. */
-@@ -120,7 +132,7 @@ void thread_exit (void) NO_RETURN;
- void thread_exit (void) NO_RETURN;
- void thread_yield (void);
+     unsigned magic;                     /* Detects stack overflow. */
+   };
  
--void thread_join (tid_t);
-+int thread_join (tid_t);
- void thread_set_priority (int);
- int thread_get_priority (void);
++/* Tracks the completion of a process.
++   Reference held by both the parent, in its `children' list,
++   and by the child, in its `wait_status' pointer. */
++struct wait_status
++  {
++    struct list_elem elem;              /* `children' list element. */
++    struct lock lock;                   /* Protects ref_cnt. */
++    int ref_cnt;                        /* 2=child and parent both alive,
++                                           1=either child or parent alive,
++                                           0=child and parent both dead. */
++    tid_t tid;                          /* Child thread id. */
++    int exit_code;                      /* Child exit code, if dead. */
++    struct semaphore dead;              /* 1=child alive, 0=child dead. */
++  };
++
+ /* If false (default), use round-robin scheduler.
+    If true, use multi-level feedback queue scheduler.
+    Controlled by kernel command-line options "-o mlfqs".
 Index: src/userprog/exception.c
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/exception.c,v
-retrieving revision 1.10
-diff -u -p -r1.10 exception.c
---- src/userprog/exception.c   26 Sep 2004 21:15:17 -0000      1.10
-+++ src/userprog/exception.c   1 Jan 2005 02:13:42 -0000
-@@ -147,6 +147,14 @@ page_fault (struct intr_frame *f) 
+diff -u src/userprog/exception.c~ src/userprog/exception.c
+--- src/userprog/exception.c~
++++ src/userprog/exception.c
+@@ -150,6 +150,14 @@ page_fault (struct intr_frame *f) 
    write = (f->error_code & PF_W) != 0;
    user = (f->error_code & PF_U) != 0;
  
@@ -254,117 +117,219 @@ diff -u -p -r1.10 exception.c
       body, and replace it with code that brings in the page to
       which fault_addr refers. */
 Index: src/userprog/process.c
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/process.c,v
-retrieving revision 1.6
-diff -u -p -r1.6 process.c
---- src/userprog/process.c     15 Dec 2004 02:32:02 -0000      1.6
-+++ src/userprog/process.c     1 Jan 2005 02:13:43 -0000
-@@ -18,7 +18,17 @@
+diff -u src/userprog/process.c~ src/userprog/process.c
+--- src/userprog/process.c~
++++ src/userprog/process.c
+@@ -14,11 +14,23 @@
+ #include "threads/init.h"
+ #include "threads/interrupt.h"
++#include "threads/malloc.h"
+ #include "threads/palloc.h"
  #include "threads/thread.h"
+ #include "threads/vaddr.h"
  
- static thread_func execute_thread NO_RETURN;
+ static thread_func start_process NO_RETURN;
 -static bool load (const char *cmdline, void (**eip) (void), void **esp);
 +static bool load (const char *cmd_line, void (**eip) (void), void **esp);
 +
 +/* Data structure shared between process_execute() in the
-+   invoking thread and execute_thread() in the newly invoked
++   invoking thread and start_process() in the newly invoked
 +   thread. */
 +struct exec_info 
 +  {
-+    const char *filename;        /* Program to load. */
-+    struct semaphore load_done;  /* "Up"ed when loading complete. */
-+    bool success;                /* True if program successfully loaded. */
++    const char *file_name;              /* Program to load. */
++    struct semaphore load_done;         /* "Up"ed when loading complete. */
++    struct wait_status *wait_status;    /* Child process. */
++    bool success;                       /* Program successfully loaded? */
 +  };
  
  /* Starts a new thread running a user program loaded from
-    FILENAME.  The new thread may be scheduled before
-@@ -26,31 +36,32 @@ static bool load (const char *cmdline, v
+    FILE_NAME.  The new thread may be scheduled (and may even exit)
+@@ -27,29 +39,37 @@ static bool load (const char *cmdline, v
  tid_t
- process_execute (const char *filename) 
+ process_execute (const char *file_name) 
  {
 -  char *fn_copy;
 +  struct exec_info exec;
++  char thread_name[16];
++  char *save_ptr;
    tid_t tid;
  
--  /* Make a copy of FILENAME.
+-  /* Make a copy of FILE_NAME.
 -     Otherwise there's a race between the caller and load(). */
 -  fn_copy = palloc_get_page (0);
 -  if (fn_copy == NULL)
 -    return TID_ERROR;
--  strlcpy (fn_copy, filename, PGSIZE);
+-  strlcpy (fn_copy, file_name, PGSIZE);
 +  /* Initialize exec_info. */
-+  exec.filename = filename;
-+  sema_init (&exec.load_done, 0, "load done");
++  exec.file_name = file_name;
++  sema_init (&exec.load_done, 0);
  
-   /* Create a new thread to execute FILENAME. */
--  tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
+   /* Create a new thread to execute FILE_NAME. */
+-  tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
 -  if (tid == TID_ERROR)
 -    palloc_free_page (fn_copy); 
-+  tid = thread_create (filename, PRI_DEFAULT, execute_thread, &exec);
++  strlcpy (thread_name, file_name, sizeof thread_name);
++  strtok_r (thread_name, " ", &save_ptr);
++  tid = thread_create (thread_name, PRI_DEFAULT, start_process, &exec);
 +  if (tid != TID_ERROR)
 +    {
 +      sema_down (&exec.load_done);
-+      if (!exec.success)
++      if (exec.success)
++        list_push_back (&thread_current ()->children, &exec.wait_status->elem);
++      else
 +        tid = TID_ERROR;
 +    }
++
    return tid;
  }
  
  /* A thread function that loads a user process and starts it
     running. */
  static void
--execute_thread (void *filename_)
-+execute_thread (void *exec_)
+-start_process (void *file_name_)
++start_process (void *exec_)
  {
--  char *filename = filename_;
+-  char *file_name = file_name_;
 +  struct exec_info *exec = exec_;
    struct intr_frame if_;
    bool success;
  
-   /* Initialize interrupt frame and load executable. */
-   memset (&if_, 0, sizeof if_);
-@@ -59,11 +69,9 @@ execute_thread (void *filename_)
+@@ -58,10 +78,29 @@ start_process (void *file_name_)
+   if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
    if_.cs = SEL_UCSEG;
    if_.eflags = FLAG_IF | FLAG_MBS;
-   if_.ss = SEL_UDSEG;
--  success = load (filename, &if_.eip, &if_.esp);
--
+-  success = load (file_name, &if_.eip, &if_.esp);
++  success = load (exec->file_name, &if_.eip, &if_.esp);
++
++  /* Allocate wait_status. */
++  if (success)
++    {
++      exec->wait_status = thread_current ()->wait_status
++        = malloc (sizeof *exec->wait_status);
++      success = exec->wait_status != NULL; 
++    }
 -  /* If load failed, quit. */
--  palloc_free_page (filename);
-+  success = exec->success = load (exec->filename, &if_.eip, &if_.esp);
+-  palloc_free_page (file_name);
++  /* Initialize wait_status. */
++  if (success) 
++    {
++      lock_init (&exec->wait_status->lock);
++      exec->wait_status->ref_cnt = 2;
++      exec->wait_status->tid = thread_current ()->tid;
++      exec->wait_status->exit_code = -1;
++      sema_init (&exec->wait_status->dead, 0);
++    }
++  
++  /* Notify parent thread and clean up. */
++  exec->success = success;
 +  sema_up (&exec->load_done);
    if (!success) 
      thread_exit ();
  
-   /* Switch page tables. */
-@@ -89,6 +97,8 @@ process_exit (void)
+@@ -75,18 +113,47 @@ start_process (void *file_name_)
+   NOT_REACHED ();
+ }
++/* Releases one reference to CS and, if it is now unreferenced,
++   frees it. */
++static void
++release_child (struct wait_status *cs) 
++{
++  int new_ref_cnt;
++  
++  lock_acquire (&cs->lock);
++  new_ref_cnt = --cs->ref_cnt;
++  lock_release (&cs->lock);
++
++  if (new_ref_cnt == 0)
++    free (cs);
++}
++
+ /* Waits for thread TID to die and returns its exit status.  If
+    it was terminated by the kernel (i.e. killed due to an
+    exception), returns -1.  If TID is invalid or if it was not a
+    child of the calling process, or if process_wait() has already
+    been successfully called for the given TID, returns -1
+-   immediately, without waiting.
+-
+-   This function will be implemented in problem 2-2.  For now, it
+-   does nothing. */
++   immediately, without waiting. */
+ int
+-process_wait (tid_t child_tid UNUSED) 
++process_wait (tid_t child_tid) 
+ {
++  struct thread *cur = thread_current ();
++  struct list_elem *e;
++
++  for (e = list_begin (&cur->children); e != list_end (&cur->children);
++       e = list_next (e)) 
++    {
++      struct wait_status *cs = list_entry (e, struct wait_status, elem);
++      if (cs->tid == child_tid) 
++        {
++          int exit_code;
++          list_remove (e);
++          sema_down (&cs->dead);
++          exit_code = cs->exit_code;
++          release_child (cs);
++          return exit_code;
++        }
++    }
+   return -1;
+ }
+@@ -95,8 +162,30 @@ void
+ process_exit (void)
+ {
    struct thread *cur = thread_current ();
++  struct list_elem *e, *next;
    uint32_t *pd;
  
-+  printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
++  /* Close executable (and allow writes). */
++  file_close (cur->bin_file);
++
++  /* Notify parent that we're dead. */
++  if (cur->wait_status != NULL) 
++    {
++      struct wait_status *cs = cur->wait_status;
++      printf ("%s: exit(%d)\n", cur->name, cs->exit_code);
++      sema_up (&cs->dead);
++      release_child (cs);
++    }
 +
++  /* Free entries of children list. */
++  for (e = list_begin (&cur->children); e != list_end (&cur->children);
++       e = next) 
++    {
++      struct wait_status *cs = list_entry (e, struct wait_status, elem);
++      next = list_remove (e);
++      release_child (cs);
++    }
++  
    /* Destroy the current process's page directory and switch back
-      to the kernel-only page directory.  We have to set
-      cur->pagedir to NULL before switching page directories, or a
-@@ -182,7 +192,7 @@ struct Elf32_Phdr
+      to the kernel-only page directory. */
+   pd = cur->pagedir;
+@@ -193,7 +284,7 @@ struct Elf32_Phdr
+ #define PF_W 2          /* Writable. */
  #define PF_R 4          /* Readable. */
  
- static bool load_segment (struct file *, const struct Elf32_Phdr *);
 -static bool setup_stack (void **esp);
 +static bool setup_stack (const char *cmd_line, void **esp);
- /* Aborts loading an executable, with an error message. */
- #define LOAD_ERROR(MSG)                                         \
-@@ -198,13 +208,15 @@ static bool setup_stack (void **esp);
+ static bool validate_segment (const struct Elf32_Phdr *, struct file *);
+ static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
+                           bool writable);
+@@ -209,13 +300,15 @@ static bool setup_stack (void **esp);
     and its initial stack pointer into *ESP.
     Returns true if successful, false otherwise. */
  bool
--load (const char *filename, void (**eip) (void), void **esp) 
+-load (const char *file_name, void (**eip) (void), void **esp) 
 +load (const char *cmd_line, void (**eip) (void), void **esp) 
  {
    struct thread *t = thread_current ();
-+  char filename[NAME_MAX + 2];
++  char file_name[NAME_MAX + 2];
    struct Elf32_Ehdr ehdr;
    struct file *file = NULL;
    off_t file_ofs;
@@ -372,23 +337,32 @@ diff -u -p -r1.6 process.c
 +  char *cp;
    int i;
  
-   /* Allocate page directory. */
-@@ -212,6 +224,14 @@ load (const char *filename, void (**eip)
-   if (t->pagedir == NULL)
-     LOAD_ERROR (("page directory allocation failed"));
+   /* Allocate and activate page directory. */
+@@ -224,13 +317,22 @@ load (const char *file_name, void (**eip)
+     goto done;
+   process_activate ();
  
-+  /* Extract filename from command line. */
++  /* Extract file_name from command line. */
 +  while (*cmd_line == ' ')
 +    cmd_line++;
-+  strlcpy (filename, cmd_line, sizeof filename);
-+  cp = strchr (filename, ' ');
++  strlcpy (file_name, cmd_line, sizeof file_name);
++  cp = strchr (file_name, ' ');
 +  if (cp != NULL)
 +    *cp = '\0';
 +
    /* Open executable file. */
-   file = filesys_open (filename);
-   if (file == NULL)
-@@ -272,7 +292,7 @@ load (const char *filename, void (**eip)
+-  file = filesys_open (file_name);
++  t->bin_file = file = filesys_open (file_name);
+   if (file == NULL) 
+     {
+       printf ("load: %s: open failed\n", file_name);
+       goto done; 
+     }
++  file_deny_write (file);
+   /* Read and verify executable header. */
+   if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
+@@ -284,7 +386,7 @@ load (const char *file_name, void (**eip)
      }
  
    /* Set up stack. */
@@ -397,7 +371,15 @@ diff -u -p -r1.6 process.c
      goto done;
  
    /* Start address. */
-@@ -381,10 +401,92 @@ load_segment (struct file *file, const s
+@@ -294,7 +396,6 @@ load (const char *file_name, void (**eip)
+  done:
+   /* We arrive here whether the load is successful or not. */
+-  file_close (file);
+   return success;
+ }
\f
+@@ -393,10 +494,92 @@ load_segment (struct file *file, const s
    return true;
  }
  
@@ -463,7 +445,7 @@ diff -u -p -r1.6 process.c
 +  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
 +       karg = strtok_r (NULL, " ", &saveptr))
 +    {
-+      char *uarg = upage + (karg - (char *) kpage);
++      void *uarg = upage + (karg - (char *) kpage);
 +      if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
 +        return false;
 +      argc++;
@@ -493,49 +475,46 @@ diff -u -p -r1.6 process.c
  {
    uint8_t *kpage;
    bool success = false;
-@@ -392,9 +494,9 @@ setup_stack (void **esp) 
+@@ -404,9 +587,9 @@ setup_stack (void **esp) 
    kpage = palloc_get_page (PAL_USER | PAL_ZERO);
    if (kpage != NULL) 
      {
--      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
+-      success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
 -      if (success)
 -        *esp = PHYS_BASE;
 +      uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
-+      if (install_page (upage, kpage))
++      if (install_page (upage, kpage, true))
 +        success = init_cmd_line (kpage, upage, cmd_line, esp);
        else
          palloc_free_page (kpage);
      }
 Index: src/userprog/syscall.c
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/syscall.c,v
-retrieving revision 1.4
-diff -u -p -r1.4 syscall.c
---- src/userprog/syscall.c     26 Sep 2004 21:15:17 -0000      1.4
-+++ src/userprog/syscall.c     1 Jan 2005 02:13:43 -0000
-@@ -1,20 +1,478 @@
+diff -u src/userprog/syscall.c~ src/userprog/syscall.c
+--- src/userprog/syscall.c~
++++ src/userprog/syscall.c
+@@ -1,20 +1,486 @@
  #include "userprog/syscall.h"
  #include <stdio.h>
 +#include <string.h>
  #include <syscall-nr.h>
 +#include "userprog/process.h"
 +#include "userprog/pagedir.h"
-+#include "devices/kbd.h"
++#include "devices/input.h"
++#include "devices/shutdown.h"
 +#include "filesys/filesys.h"
 +#include "filesys/file.h"
-+#include "threads/init.h"
  #include "threads/interrupt.h"
 +#include "threads/malloc.h"
-+#include "threads/mmu.h"
 +#include "threads/palloc.h"
  #include "threads/thread.h"
++#include "threads/vaddr.h"
 -
 + 
 + 
 +static int sys_halt (void);
 +static int sys_exit (int status);
 +static int sys_exec (const char *ufile);
-+static int sys_join (tid_t);
++static int sys_wait (tid_t);
 +static int sys_create (const char *ufile, unsigned initial_size);
 +static int sys_remove (const char *ufile);
 +static int sys_open (const char *ufile);
@@ -550,13 +529,14 @@ diff -u -p -r1.4 syscall.c
 -
 +static void copy_in (void *, const void *, size_t);
 + 
++/* Serializes file system operations. */
 +static struct lock fs_lock;
 + 
  void
  syscall_init (void) 
  {
-   intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
-+  lock_init (&fs_lock, "fs");
+   intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
++  lock_init (&fs_lock);
  }
 + 
 +/* System call handler. */
@@ -573,12 +553,12 @@ diff -u -p -r1.4 syscall.c
 +    };
 +
 +  /* Table of system calls. */
-+  static const struct syscall syscall_table[] = 
++  static const struct syscall syscall_table[] =
 +    {
 +      {0, (syscall_function *) sys_halt},
 +      {1, (syscall_function *) sys_exit},
 +      {1, (syscall_function *) sys_exec},
-+      {1, (syscall_function *) sys_join},
++      {1, (syscall_function *) sys_wait},
 +      {2, (syscall_function *) sys_create},
 +      {1, (syscall_function *) sys_remove},
 +      {1, (syscall_function *) sys_open},
@@ -590,13 +570,13 @@ diff -u -p -r1.4 syscall.c
 +      {1, (syscall_function *) sys_close},
 +    };
 +
-+  struct syscall *sc;
-+  int call_nr;
++  const struct syscall *sc;
++  unsigned call_nr;
 +  int args[3];
 +
 +  /* Get the system call. */
 +  copy_in (&call_nr, f->esp, sizeof call_nr);
-+  if (call_nr < 0 || call_nr >= sizeof syscall_table / sizeof *syscall_table)
++  if (call_nr >= sizeof syscall_table / sizeof *syscall_table)
 +    thread_exit ();
 +  sc = syscall_table + call_nr;
  
@@ -615,7 +595,8 @@ diff -u -p -r1.4 syscall.c
 +static bool
 +verify_user (const void *uaddr) 
 +{
-+  return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
++  return (uaddr < PHYS_BASE
++          && pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL);
 +}
 + 
 +/* Copies a byte from user address USRC to kernel address DST.
@@ -625,7 +606,7 @@ diff -u -p -r1.4 syscall.c
 +get_user (uint8_t *dst, const uint8_t *usrc)
 +{
 +  int eax;
-+  asm ("mov %%eax, offset 1f; mov %%al, %2; mov %0, %%al; 1:"
++  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
 +  return eax != 0;
 +}
@@ -637,8 +618,8 @@ diff -u -p -r1.4 syscall.c
 +put_user (uint8_t *udst, uint8_t byte)
 +{
 +  int eax;
-+  asm ("mov %%eax, offset 1f; mov %0, %b2; 1:"
-+       : "=m" (*udst), "=&a" (eax) : "r" (byte));
++  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
++       : "=m" (*udst), "=&a" (eax) : "q" (byte));
 +  return eax != 0;
 +}
 + 
@@ -675,7 +656,10 @@ diff -u -p -r1.4 syscall.c
 +  for (length = 0; length < PGSIZE; length++)
 +    {
 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
-+        thread_exit (); 
++        {
++          palloc_free_page (ks);
++          thread_exit (); 
++        }
 +       
 +      if (ks[length] == '\0')
 +        return ks;
@@ -688,14 +672,14 @@ diff -u -p -r1.4 syscall.c
 +static int
 +sys_halt (void)
 +{
-+  power_off ();
++  shutdown_power_off ();
 +}
 + 
 +/* Exit system call. */
 +static int
 +sys_exit (int exit_code) 
 +{
-+  thread_current ()->exit_code = exit_code;
++  thread_current ()->wait_status->exit_code = exit_code;
 +  thread_exit ();
 +  NOT_REACHED ();
 +}
@@ -716,11 +700,11 @@ diff -u -p -r1.4 syscall.c
 +  return tid;
 +}
 + 
-+/* Join system call. */
++/* Wait system call. */
 +static int
-+sys_join (tid_t child) 
++sys_wait (tid_t child) 
 +{
-+  return thread_join (child);
++  return process_wait (child);
 +}
 + 
 +/* Create system call. */
@@ -811,7 +795,7 @@ diff -u -p -r1.4 syscall.c
 +    }
 + 
    thread_exit ();
-+}
+ }
 + 
 +/* Filesize system call. */
 +static int
@@ -839,7 +823,7 @@ diff -u -p -r1.4 syscall.c
 +  if (handle == STDIN_FILENO) 
 +    {
 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
-+        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
++        if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, input_getc ()))
 +          thread_exit ();
 +      return bytes_read;
 +    }
@@ -947,7 +931,8 @@ diff -u -p -r1.4 syscall.c
 +  struct file_descriptor *fd = lookup_fd (handle);
 +   
 +  lock_acquire (&fs_lock);
-+  file_seek (fd->file, position);
++  if ((off_t) position >= 0)
++    file_seek (fd->file, position);
 +  lock_release (&fs_lock);
 + 
 +  return 0;
@@ -992,17 +977,16 @@ diff -u -p -r1.4 syscall.c
 +      struct file_descriptor *fd;
 +      fd = list_entry (e, struct file_descriptor, elem);
 +      next = list_next (e);
++      lock_acquire (&fs_lock);
 +      file_close (fd->file);
++      lock_release (&fs_lock);
 +      free (fd);
 +    }
- }
++}
 Index: src/userprog/syscall.h
-===================================================================
-RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/userprog/syscall.h,v
-retrieving revision 1.2
-diff -u -p -r1.2 syscall.h
---- src/userprog/syscall.h     6 Sep 2004 05:38:45 -0000       1.2
-+++ src/userprog/syscall.h     1 Jan 2005 02:13:43 -0000
+diff -u src/userprog/syscall.h~ src/userprog/syscall.h
+--- src/userprog/syscall.h~
++++ src/userprog/syscall.h
 @@ -2,5 +2,6 @@
  #define USERPROG_SYSCALL_H