Update solutions.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 1 Jan 2005 02:16:53 +0000 (02:16 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 1 Jan 2005 02:16:53 +0000 (02:16 +0000)
solutions/README
solutions/p2.patch

index 1e23f07bf5f5da19cc04791368823feb92bba69e..ab3e9a01defa5bee74f9c454b52f3e3dbeac3428 100644 (file)
@@ -1,6 +1,7 @@
 Sample solutions.
 
-* The solutions for p1-1, p1-2, p1-3, and p2 are okay.
+* The solutions for p1-1, p1-2, p1-3, and p2 are good enough.  They
+  pass all the appropriate tests in the grading directory.
 
 * The solution for p3 is terrible.  For example, there's no locking at
   all.  I just wrote it to make sure that the project was possible
index 68331bd87b80895da485cac29b216f8c922e481f..8f648559aaa3e8390f1f40d39ab6432c7f1d09dc 100644 (file)
@@ -1,20 +1,34 @@
-diff -urpN pintos.orig/src/constants.h pintos/src/constants.h
---- pintos.orig/src/constants.h        2004-09-21 17:26:39.000000000 -0700
-+++ pintos/src/constants.h     2004-09-27 16:41:17.000000000 -0700
+Index: constants.h
+===================================================================
+RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/constants.h,v
+retrieving revision 1.4
+diff -u -p -r1.4 constants.h
+--- constants.h        19 Oct 2004 17:37:30 -0000      1.4
++++ constants.h        1 Jan 2005 02:13:41 -0000
 @@ -8,4 +8,4 @@
  /*#define MACRONAME 1 */
  
  /* Uncomment if if you've implemented thread_join(). */
 -/*#define THREAD_JOIN_IMPLEMENTED 1*/
 +#define THREAD_JOIN_IMPLEMENTED 1
-diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
---- pintos.orig/src/threads/synch.c    2004-09-19 21:29:53.000000000 -0700
-+++ pintos/src/threads/synch.c 2004-09-27 16:41:17.000000000 -0700
-@@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
+Index: 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
+--- threads/synch.c    31 Dec 2004 21:13:38 -0000      1.15
++++ 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) 
 +{
@@ -23,6 +37,8 @@ diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 +  cond_init (&latch->rel_cond, name);
 +}
 +
++/* Acquires LATCH, blocking until it is released for the first
++   time. */
 +void
 +latch_acquire (struct latch *latch) 
 +{
@@ -35,6 +51,8 @@ diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 +  lock_release (&latch->monitor_lock);
 +}
 +
++/* Releases LATCH, causing all ongoing and subsequent
++   acquisitions to pass through immediately. */
 +void
 +latch_release (struct latch *latch) 
 +{
@@ -46,9 +64,13 @@ diff -urpN pintos.orig/src/threads/synch.c pintos/src/threads/synch.c
 +    }
 +  lock_release (&latch->monitor_lock);
 +}
-diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
---- pintos.orig/src/threads/synch.h    2004-09-19 21:29:53.000000000 -0700
-+++ pintos/src/threads/synch.h 2004-09-27 16:41:17.000000000 -0700
+Index: 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
+--- threads/synch.h    29 Sep 2004 01:04:09 -0000      1.7
++++ 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 *);
@@ -66,9 +88,13 @@ diff -urpN pintos.orig/src/threads/synch.h pintos/src/threads/synch.h
 +void latch_release (struct latch *);
 +
  #endif /* threads/synch.h */
-diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
---- pintos.orig/src/threads/thread.c   2004-09-26 14:15:17.000000000 -0700
-+++ pintos/src/threads/thread.c        2004-09-27 16:41:17.000000000 -0700
+Index: 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
+--- threads/thread.c   9 Oct 2004 18:01:37 -0000       1.48
++++ threads/thread.c   1 Jan 2005 02:13:42 -0000
 @@ -13,6 +13,7 @@
  #include "threads/synch.h"
  #ifdef USERPROG
@@ -77,7 +103,7 @@ diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  #endif
  
  /* Random value for struct thread's `magic' member.
-@@ -80,6 +81,7 @@ thread_init (void) 
+@@ -81,6 +82,7 @@ thread_init (void) 
    init_thread (initial_thread, "main", PRI_DEFAULT);
    initial_thread->status = THREAD_RUNNING;
    initial_thread->tid = allocate_tid ();
@@ -85,7 +111,7 @@ diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  }
  
  /* Starts preemptive thread scheduling by enabling interrupts.
-@@ -148,6 +150,7 @@ thread_create (const char *name, int pri
+@@ -149,6 +151,7 @@ thread_create (const char *name, int pri
    /* Initialize thread. */
    init_thread (t, name, priority);
    tid = t->tid = allocate_tid ();
@@ -93,7 +119,7 @@ diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
  
    /* Stack frame for kernel_thread(). */
    kf = alloc_frame (t, sizeof *kf);
-@@ -224,16 +227,36 @@ thread_tid (void) 
+@@ -241,16 +244,36 @@ thread_tid (void) 
  void
  thread_exit (void) 
  {
@@ -131,9 +157,9 @@ diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
    schedule ();
    NOT_REACHED ();
  }
-@@ -270,6 +293,26 @@ thread_block (void) 
-   thread_current ()->status = THREAD_BLOCKED;
-   schedule ();
+@@ -300,6 +323,26 @@ kernel_thread (thread_func *function, vo
+   function (aux);       /* Execute the thread function. */
+   thread_exit ();       /* If function() returns, kill the thread. */
  }
 +
 +/* Waits for thread with tid CHILD_TID to die. */
@@ -150,30 +176,34 @@ diff -urpN pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
 +      if (child->tid == child_tid) 
 +        {
 +          latch_acquire (&child->ready_to_die);
-+          return child->ret_code; 
++          return child->exit_code; 
 +        }
 +    }
 +  return -1;
 +}
  \f
- /* Idle thread.  Executes when no other thread is ready to run. */
- static void
-@@ -335,6 +378,12 @@ init_thread (struct thread *t, const cha
+ /* Returns the running thread. */
+ struct thread *
+@@ -336,6 +379,12 @@ 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->ret_code = -1;
++  t->exit_code = -1;
 +  list_init (&t->fds);
 +  t->next_handle = 2;
    t->magic = THREAD_MAGIC;
  }
  
-diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
---- pintos.orig/src/threads/thread.h   2004-09-26 14:15:17.000000000 -0700
-+++ pintos/src/threads/thread.h        2004-09-27 16:41:17.000000000 -0700
+Index: 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
+--- threads/thread.h   29 Sep 2004 01:04:20 -0000      1.28
++++ threads/thread.h   1 Jan 2005 02:13:42 -0000
 @@ -4,6 +4,7 @@
  #include <debug.h>
  #include <list.h>
@@ -191,7 +221,7 @@ diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
 +    struct semaphore can_die;           /* Up when thread allowed to die. */
 +    struct list children;               /* List of child threads. */
 +    list_elem children_elem;            /* Element of `children' list. */
-+    int ret_code;                       /* Return status. */
++    int exit_code;                      /* Return status. */
 +
      /* Shared between thread.c and synch.c. */
      list_elem elem;                     /* List element. */
@@ -205,9 +235,9 @@ diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
 +    int next_handle;                    /* Next handle value. */
  #endif
  
-     /* Owned by thread.c */
-@@ -119,7 +131,7 @@ void thread_yield (void);
- void thread_block (void);
+     /* Owned by thread.c. */
+@@ -120,7 +132,7 @@ void thread_exit (void) NO_RETURN;
+ void thread_yield (void);
  
  /* This function will be implemented in problem 1-2. */
 -void thread_join (tid_t);
@@ -215,13 +245,18 @@ diff -urpN pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
  
  /* These functions will be implemented in problem 1-3. */
  void thread_set_priority (int);
-diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
---- pintos.orig/src/userprog/exception.c       2004-09-26 14:15:17.000000000 -0700
-+++ pintos/src/userprog/exception.c    2004-09-27 16:41:17.000000000 -0700
-@@ -147,6 +147,13 @@ page_fault (struct intr_frame *f) 
+Index: 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
+--- userprog/exception.c       26 Sep 2004 21:15:17 -0000      1.10
++++ userprog/exception.c       1 Jan 2005 02:13:42 -0000
+@@ -147,6 +147,14 @@ page_fault (struct intr_frame *f) 
    write = (f->error_code & PF_W) != 0;
    user = (f->error_code & PF_U) != 0;
  
++  /* Handle bad dereferences from system call implementations. */
 +  if (!user) 
 +    {
 +      f->eip = (void (*) (void)) f->eax;
@@ -232,24 +267,116 @@ diff -urpN pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
    /* To implement virtual memory, delete the rest of the function
       body, and replace it with code that brings in the page to
       which fault_addr refers. */
-diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
---- pintos.orig/src/userprog/process.c 2004-09-22 17:58:29.000000000 -0700
-+++ pintos/src/userprog/process.c      2004-09-27 16:41:17.000000000 -0700
-@@ -182,7 +182,7 @@ struct Elf32_Phdr
+Index: 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
+--- userprog/process.c 15 Dec 2004 02:32:02 -0000      1.6
++++ userprog/process.c 1 Jan 2005 02:13:43 -0000
+@@ -18,7 +18,17 @@
+ #include "threads/thread.h"
+ static thread_func execute_thread 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
++   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. */
++  };
+ /* Starts a new thread running a user program loaded from
+    FILENAME.  The new thread may be scheduled before
+@@ -26,31 +36,31 @@ static bool load (const char *cmdline, v
+ tid_t
+ process_execute (const char *filename) 
+ {
+-  char *fn_copy;
++  struct exec_info exec;
+   tid_t tid;
+-  /* Make a copy of FILENAME.
+-     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);
++  /* Initialize exec_info. */
++  exec.filename = filename;
++  sema_init (&exec.load_done, 0, "load done");
+   /* Create a new thread to execute FILENAME. */
+-  tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
+-  if (tid == TID_ERROR)
+-    palloc_free_page (fn_copy); 
++  tid = thread_create (filename, PRI_DEFAULT, execute_thread, &exec);
++  if (tid != TID_ERROR)
++    {
++      sema_down (&exec.load_done);
++      if (!exec.success)
++        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_)
+ {
+-  char *filename = filename_;
++  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_)
+   if_.cs = SEL_UCSEG;
+   if_.eflags = FLAG_IF | FLAG_MBS;
+   if_.ss = SEL_UDSEG;
+-  success = load (filename, &if_.eip, &if_.esp);
+-
+-  /* If load failed, quit. */
+-  palloc_free_page (filename);
+-  if (!success) 
++  exec->success = load (exec->filename, &if_.eip, &if_.esp);
++  sema_up (&exec->load_done);
++  if (!exec->success)
+     thread_exit ();
+   /* Switch page tables. */
+@@ -89,6 +97,8 @@ process_exit (void)
+   struct thread *cur = thread_current ();
+   uint32_t *pd;
++  printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
++
+   /* 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
  #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 *cmdline, 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 +198,15 @@ static bool setup_stack (void **esp);
+@@ -198,13 +208,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 *cmdline, 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];
@@ -261,14 +388,14 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
    int i;
  
    /* Allocate page directory. */
-@@ -212,6 +214,14 @@ load (const char *filename, void (**eip)
+@@ -212,6 +224,14 @@ load (const char *filename, void (**eip)
    if (t->pagedir == NULL)
      LOAD_ERROR (("page directory allocation failed"));
  
 +  /* Extract filename from command line. */
-+  while (*cmdline == ' ')
-+    cmdline++;
-+  strlcpy (filename, cmdline, sizeof filename);
++  while (*cmd_line == ' ')
++    cmd_line++;
++  strlcpy (filename, cmd_line, sizeof filename);
 +  cp = strchr (filename, ' ');
 +  if (cp != NULL)
 +    *cp = '\0';
@@ -276,21 +403,22 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
    /* Open executable file. */
    file = filesys_open (filename);
    if (file == NULL)
-@@ -269,7 +279,7 @@ load (const char *filename, void (**eip)
+@@ -272,7 +292,7 @@ load (const char *filename, void (**eip)
      }
  
    /* Set up stack. */
 -  if (!setup_stack (esp))
-+  if (!setup_stack (cmdline, esp))
++  if (!setup_stack (cmd_line, esp))
      goto done;
  
    /* Start address. */
-@@ -371,10 +381,80 @@ load_segment (struct file *file, const s
+@@ -381,10 +401,92 @@ load_segment (struct file *file, const s
    return true;
  }
  
 -/* Create a minimal stack by mapping a zeroed page at the top of
 -   user virtual memory. */
++/* Reverse the order of the ARGC pointers to char in ARGV. */
 +static void
 +reverse (int argc, char **argv) 
 +{
@@ -302,6 +430,13 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
 +    }
 +}
 +
++/* Pushes the SIZE bytes in BUF onto the stack in KPAGE, whose
++   page-relative stack pointer is *OFS, and then adjusts *OFS
++   appropriately.  The bytes pushed are rounded to a 32-bit
++   boundary.
++
++   If successful, returns a pointer to the newly pushed object.
++   On failure, returns a null pointer. */
 +static void *
 +push (uint8_t *kpage, size_t *ofs, const void *buf, size_t size) 
 +{
@@ -314,20 +449,24 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
 +  return kpage + *ofs + (padsize - size);
 +}
 +
++/* Sets up command line arguments in KPAGE, which will be mapped
++   to UPAGE in user space.  The command line arguments are taken
++   from CMD_LINE, separated by spaces.  Sets *ESP to the initial
++   stack pointer for the process. */
 +static bool
-+init_cmdline (uint8_t *kpage, uint8_t *upage, const char *cmdline,
-+              void **esp) 
++init_cmd_line (uint8_t *kpage, uint8_t *upage, const char *cmd_line,
++               void **esp) 
 +{
 +  size_t ofs = PGSIZE;
 +  char *const null = NULL;
-+  char *cmdline_copy;
++  char *cmd_line_copy;
 +  char *karg, *saveptr;
 +  int argc;
 +  char **argv;
 +
 +  /* Push command line string. */
-+  cmdline_copy = push (kpage, &ofs, cmdline, strlen (cmdline) + 1);
-+  if (cmdline_copy == NULL)
++  cmd_line_copy = push (kpage, &ofs, cmd_line, strlen (cmd_line) + 1);
++  if (cmd_line_copy == NULL)
 +    return false;
 +
 +  if (push (kpage, &ofs, &null, sizeof null) == NULL)
@@ -336,7 +475,7 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
 +  /* Parse command line into arguments
 +     and push them in reverse order. */
 +  argc = 0;
-+  for (karg = strtok_r (cmdline_copy, " ", &saveptr); karg != NULL;
++  for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
 +       karg = strtok_r (NULL, " ", &saveptr))
 +    {
 +      char *uarg = upage + (karg - (char *) kpage);
@@ -361,15 +500,15 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
 +}
 +
 +/* Create a minimal stack for T by mapping a page at the
-+   top of user virtual memory.  Fills in the page using CMDLINE
++   top of user virtual memory.  Fills in the page using CMD_LINE
 +   and sets *ESP to the stack pointer. */
  static bool
 -setup_stack (void **esp) 
-+setup_stack (const char *cmdline, void **esp) 
++setup_stack (const char *cmd_line, void **esp) 
  {
    uint8_t *kpage;
    bool success = false;
-@@ -382,9 +462,9 @@ setup_stack (void **esp) 
+@@ -392,9 +494,9 @@ setup_stack (void **esp) 
    kpage = palloc_get_page (PAL_USER | PAL_ZERO);
    if (kpage != NULL) 
      {
@@ -378,14 +517,18 @@ diff -urpN pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
 -        *esp = PHYS_BASE;
 +      uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
 +      if (install_page (upage, kpage))
-+        success = init_cmdline (kpage, upage, cmdline, esp);
++        success = init_cmd_line (kpage, upage, cmd_line, esp);
        else
          palloc_free_page (kpage);
      }
-diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
---- pintos.orig/src/userprog/syscall.c 2004-09-26 14:15:17.000000000 -0700
-+++ pintos/src/userprog/syscall.c      2004-09-27 16:43:00.000000000 -0700
-@@ -1,20 +1,429 @@
+Index: 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
+--- userprog/syscall.c 26 Sep 2004 21:15:17 -0000      1.4
++++ userprog/syscall.c 1 Jan 2005 02:13:43 -0000
+@@ -1,20 +1,478 @@
  #include "userprog/syscall.h"
  #include <stdio.h>
 +#include <string.h>
@@ -403,7 +546,6 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
  #include "threads/thread.h"
 -
 + 
-+typedef int syscall_function (int, int, int);
 + 
 +static int sys_halt (void);
 +static int sys_exit (int status);
@@ -418,30 +560,6 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +static int sys_seek (int handle, unsigned position);
 +static int sys_tell (int handle);
 +static int sys_close (int handle);
-+ 
-+struct syscall 
-+  {
-+    size_t arg_cnt;
-+    syscall_function *func;
-+  };
-+ 
-+struct syscall syscall_table[] = 
-+  {
-+    {0, (syscall_function *) sys_halt},
-+    {1, (syscall_function *) sys_exit},
-+    {1, (syscall_function *) sys_exec},
-+    {1, (syscall_function *) sys_join},
-+    {2, (syscall_function *) sys_create},
-+    {1, (syscall_function *) sys_remove},
-+    {1, (syscall_function *) sys_open},
-+    {1, (syscall_function *) sys_filesize},
-+    {3, (syscall_function *) sys_read},
-+    {3, (syscall_function *) sys_write},
-+    {2, (syscall_function *) sys_seek},
-+    {1, (syscall_function *) sys_tell},
-+    {1, (syscall_function *) sys_close},
-+  };
-+static const int syscall_cnt = sizeof syscall_table / sizeof *syscall_table;
 + 
  static void syscall_handler (struct intr_frame *);
 -
@@ -455,52 +573,95 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
    intr_register (0x30, 3, INTR_ON, syscall_handler, "syscall");
 +  lock_init (&fs_lock, "fs");
  }
--
 + 
- static void
--syscall_handler (struct intr_frame *f UNUSED) 
++/* System call handler. */
++static void
 +syscall_handler (struct intr_frame *f) 
- {
--  printf ("system call!\n");
-+  struct syscall *s;
++{
++  typedef int syscall_function (int, int, int);
++
++  /* A system call. */
++  struct syscall 
++    {
++      size_t arg_cnt;           /* Number of arguments. */
++      syscall_function *func;   /* Implementation. */
++    };
++
++  /* Table of system calls. */
++  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},
++      {2, (syscall_function *) sys_create},
++      {1, (syscall_function *) sys_remove},
++      {1, (syscall_function *) sys_open},
++      {1, (syscall_function *) sys_filesize},
++      {3, (syscall_function *) sys_read},
++      {3, (syscall_function *) sys_write},
++      {2, (syscall_function *) sys_seek},
++      {1, (syscall_function *) sys_tell},
++      {1, (syscall_function *) sys_close},
++    };
++
++  struct syscall *sc;
 +  int call_nr;
 +  int args[3];
-+ 
++
++  /* Get the system call. */
 +  copy_in (&call_nr, f->esp, sizeof call_nr);
-+  if (call_nr < 0 || call_nr >= syscall_cnt)
-+    {
-+      printf ("bad syscall number %d\n", call_nr);
-+      thread_exit ();
-+    }
-+ 
-+  s = syscall_table + call_nr;
-+  ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
++  if (call_nr < 0 || call_nr >= sizeof syscall_table / sizeof *syscall_table)
++    thread_exit ();
++  sc = syscall_table + call_nr;
++  /* Get the system call arguments. */
++  ASSERT (sc->arg_cnt <= sizeof args / sizeof *args);
 +  memset (args, 0, sizeof args);
-+  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * s->arg_cnt);
-+  f->eax = s->func (args[0], args[1], args[2]);
++  copy_in (args, (uint32_t *) f->esp + 1, sizeof *args * sc->arg_cnt);
++
++  /* Execute the system call,
++     and set the return value. */
++  f->eax = sc->func (args[0], args[1], args[2]);
 +}
 + 
++/* Returns true if UADDR is a valid, mapped user address,
++   false otherwise. */
 +static bool
 +verify_user (const void *uaddr) 
 +{
 +  return pagedir_get_page (thread_current ()->pagedir, uaddr) != NULL;
 +}
 + 
-+static inline bool get_user (uint8_t *dst, const uint8_t *usrc) {
++/* Copies a byte from user address USRC to kernel address DST.
++   USRC must be below PHYS_BASE.
++   Returns true if successful, false if a segfault occurred. */
++static inline bool
++get_user (uint8_t *dst, const uint8_t *usrc)
++{
 +  int eax;
 +  asm ("movl $1f, %%eax; movb %2, %%al; movb %%al, %0; 1:"
 +       : "=m" (*dst), "=&a" (eax) : "m" (*usrc));
 +  return eax != 0;
 +}
 + 
-+static inline bool put_user (uint8_t *udst, uint8_t byte) {
++/* Writes BYTE to user address UDST.
++   UDST must be below PHYS_BASE.
++   Returns true if successful, false if a segfault occurred. */
++static inline bool
++put_user (uint8_t *udst, uint8_t byte)
++{
 +  int eax;
 +  asm ("movl $1f, %%eax; movb %b2, %0; 1:"
 +       : "=m" (*udst), "=&a" (eax) : "r" (byte));
 +  return eax != 0;
 +}
 + 
-+static void
++/* Copies SIZE bytes from user address USRC to kernel address
++   DST.
++   Call thread_exit() if any of the user accesses are invalid. */
+ static void
+-syscall_handler (struct intr_frame *f UNUSED) 
 +copy_in (void *dst_, const void *usrc_, size_t size) 
 +{
 +  uint8_t *dst = dst_;
@@ -511,6 +672,11 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +      thread_exit ();
 +}
 + 
++/* Creates a copy of user string US in kernel memory
++   and returns it as a page that must be freed with
++   palloc_free_page().
++   Truncates the string at PGSIZE bytes in size.
++   Call thread_exit() if any of the user accesses are invalid. */
 +static char *
 +copy_in_string (const char *us) 
 +{
@@ -519,42 +685,37 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 + 
 +  ks = palloc_get_page (0);
 +  if (ks == NULL) 
-+    {
-+      printf ("copy_in_string: out of memory\n");
-+      thread_exit ();
-+    }
++    thread_exit ();
 + 
 +  for (length = 0; length < PGSIZE; length++)
 +    {
 +      if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++)) 
-+        {
-+          printf ("bad user reference (%p)\n", us + length);
-+          thread_exit (); 
-+        }
++        thread_exit (); 
 +       
 +      if (ks[length] == '\0')
 +        return ks;
 +    }
-+ 
-+  printf ("copy_in_string: string too long\n");
-+  palloc_free_page (ks);
-+  thread_exit ();
++  ks[PGSIZE - 1] = '\0';
++  return ks;
 +}
 + 
++/* Halt system call. */
 +static int
 +sys_halt (void)
 +{
 +  power_off ();
 +}
 + 
++/* Exit system call. */
 +static int
-+sys_exit (int ret_code) 
++sys_exit (int exit_code) 
 +{
-+  thread_current ()->ret_code = ret_code;
++  thread_current ()->exit_code = exit_code;
 +  thread_exit ();
 +  NOT_REACHED ();
 +}
 + 
++/* Exec system call. */
 +static int
 +sys_exec (const char *ufile) 
 +{
@@ -570,12 +731,14 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return tid;
 +}
 + 
++/* Join system call. */
 +static int
 +sys_join (tid_t child) 
 +{
 +  return thread_join (child);
 +}
 + 
++/* Create system call. */
 +static int
 +sys_create (const char *ufile, unsigned initial_size) 
 +{
@@ -591,9 +754,11 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return ok;
 +}
 + 
++/* Remove system call. */
 +static int
 +sys_remove (const char *ufile) 
-+{
+ {
+-  printf ("system call!\n");
 +  char *kfile = copy_in_string (ufile);
 +  bool ok;
 +   
@@ -606,42 +771,46 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return ok;
 +}
 + 
-+struct fildes
++/* A file descriptor, for binding a file handle to a file. */
++struct file_descriptor
 +  {
-+    list_elem elem;
-+    struct file *file;
-+    int handle;
++    list_elem elem;     /* List element. */
++    struct file *file;  /* File. */
++    int handle;         /* File handle. */
 +  };
 + 
++/* Open system call. */
 +static int
 +sys_open (const char *ufile) 
 +{
 +  char *kfile = copy_in_string (ufile);
-+  struct fildes *fd;
++  struct file_descriptor *fd;
 +  int handle = -1;
 + 
 +  fd = malloc (sizeof *fd);
-+  if (fd == NULL)
-+    goto exit;
-+ 
-+  lock_acquire (&fs_lock);
-+  fd->file = filesys_open (kfile);
-+  if (fd->file != NULL)
++  if (fd != NULL)
 +    {
-+      struct thread *cur = thread_current ();
-+      handle = fd->handle = cur->next_handle++;
-+      list_push_front (&cur->fds, &fd->elem);
++      lock_acquire (&fs_lock);
++      fd->file = filesys_open (kfile);
++      if (fd->file != NULL)
++        {
++          struct thread *cur = thread_current ();
++          handle = fd->handle = cur->next_handle++;
++          list_push_front (&cur->fds, &fd->elem);
++        }
++      else 
++        free (fd);
++      lock_release (&fs_lock);
 +    }
-+  else 
-+    free (fd);
-+  lock_release (&fs_lock);
-+ 
-+ exit:
++  
 +  palloc_free_page (kfile);
 +  return handle;
 +}
 + 
-+static struct fildes *
++/* Returns the file descriptor associated with the given handle.
++   Terminates the process if HANDLE is not associated with an
++   open file. */
++static struct file_descriptor *
 +lookup_fd (int handle) 
 +{
 +  struct thread *cur = thread_current ();
@@ -650,19 +819,20 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds);
 +       e = list_next (e))
 +    {
-+      struct fildes *fd = list_entry (e, struct fildes, elem);
++      struct file_descriptor *fd;
++      fd = list_entry (e, struct file_descriptor, elem);
 +      if (fd->handle == handle)
 +        return fd;
 +    }
 + 
-+  printf ("no handle %d\n", handle);
    thread_exit ();
- }
++}
 + 
++/* Filesize system call. */
 +static int
 +sys_filesize (int handle) 
 +{
-+  struct fildes *fd = lookup_fd (handle);
++  struct file_descriptor *fd = lookup_fd (handle);
 +  int size;
 + 
 +  lock_acquire (&fs_lock);
@@ -672,13 +842,15 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return size;
 +}
 + 
++/* Read system call. */
 +static int
 +sys_read (int handle, void *udst_, unsigned size) 
 +{
 +  uint8_t *udst = udst_;
-+  struct fildes *fd;
++  struct file_descriptor *fd;
 +  int bytes_read = 0;
-+ 
++
++  /* Handle keyboard reads. */
 +  if (handle == STDIN_FILENO) 
 +    {
 +      for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
@@ -686,21 +858,25 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +          thread_exit ();
 +      return bytes_read;
 +    }
-+ 
-+  lock_acquire (&fs_lock);
++
++  /* Handle all other reads. */
 +  fd = lookup_fd (handle);
++  lock_acquire (&fs_lock);
 +  while (size > 0) 
 +    {
++      /* How much to read into this page? */
 +      size_t page_left = PGSIZE - pg_ofs (udst);
 +      size_t read_amt = size < page_left ? size : page_left;
 +      off_t retval;
-+ 
++
++      /* Check that touching this page is okay. */
 +      if (!verify_user (udst)) 
 +        {
 +          lock_release (&fs_lock);
 +          thread_exit ();
 +        }
-+       
++
++      /* Read from file into page. */
 +      retval = file_read (fd->file, udst, read_amt);
 +      if (retval < 0)
 +        {
@@ -708,11 +884,13 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +            bytes_read = -1; 
 +          break;
 +        }
-+ 
 +      bytes_read += retval;
++
++      /* If it was a short read we're done. */
 +      if (retval != (off_t) read_amt)
 +        break;
-+ 
++
++      /* Advance. */
 +      udst += retval;
 +      size -= retval;
 +    }
@@ -721,28 +899,34 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return bytes_read;
 +}
 + 
++/* Write system call. */
 +static int
 +sys_write (int handle, void *usrc_, unsigned size) 
 +{
 +  uint8_t *usrc = usrc_;
-+  struct fildes *fd = NULL;
++  struct file_descriptor *fd = NULL;
 +  int bytes_written = 0;
-+ 
-+  lock_acquire (&fs_lock);
++
++  /* Lookup up file descriptor. */
 +  if (handle != STDOUT_FILENO)
 +    fd = lookup_fd (handle);
++
++  lock_acquire (&fs_lock);
 +  while (size > 0) 
 +    {
++      /* How much bytes to write to this page? */
 +      size_t page_left = PGSIZE - pg_ofs (usrc);
 +      size_t write_amt = size < page_left ? size : page_left;
 +      off_t retval;
-+ 
++
++      /* Check that we can touch this user page. */
 +      if (!verify_user (usrc)) 
 +        {
 +          lock_release (&fs_lock);
 +          thread_exit ();
 +        }
-+ 
++
++      /* Do the write. */
 +      if (handle == STDOUT_FILENO)
 +        {
 +          putbuf (usrc, write_amt);
@@ -756,11 +940,13 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +            bytes_written = -1;
 +          break;
 +        }
-+ 
 +      bytes_written += retval;
++
++      /* If it was a short write we're done. */
 +      if (retval != (off_t) write_amt)
 +        break;
-+ 
++
++      /* Advance. */
 +      usrc += retval;
 +      size -= retval;
 +    }
@@ -769,10 +955,11 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return bytes_written;
 +}
 + 
++/* Seek system call. */
 +static int
 +sys_seek (int handle, unsigned position) 
 +{
-+  struct fildes *fd = lookup_fd (handle);
++  struct file_descriptor *fd = lookup_fd (handle);
 +   
 +  lock_acquire (&fs_lock);
 +  file_seek (fd->file, position);
@@ -781,10 +968,11 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return 0;
 +}
 + 
++/* Tell system call. */
 +static int
 +sys_tell (int handle) 
 +{
-+  struct fildes *fd = lookup_fd (handle);
++  struct file_descriptor *fd = lookup_fd (handle);
 +  unsigned position;
 +   
 +  lock_acquire (&fs_lock);
@@ -794,10 +982,11 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return position;
 +}
 + 
++/* Close system call. */
 +static int
 +sys_close (int handle) 
 +{
-+  struct fildes *fd = lookup_fd (handle);
++  struct file_descriptor *fd = lookup_fd (handle);
 +  lock_acquire (&fs_lock);
 +  file_close (fd->file);
 +  lock_release (&fs_lock);
@@ -806,6 +995,7 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +  return 0;
 +}
 + 
++/* On thread exit, close all open files. */
 +void
 +syscall_exit (void) 
 +{
@@ -814,15 +1004,20 @@ diff -urpN pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
 +   
 +  for (e = list_begin (&cur->fds); e != list_end (&cur->fds); e = next)
 +    {
-+      struct fildes *fd = list_entry (e, struct fildes, elem);
++      struct file_descriptor *fd;
++      fd = list_entry (e, struct file_descriptor, elem);
 +      next = list_next (e);
 +      file_close (fd->file);
 +      free (fd);
 +    }
-+}
-diff -urpN pintos.orig/src/userprog/syscall.h pintos/src/userprog/syscall.h
---- pintos.orig/src/userprog/syscall.h 2004-09-05 22:38:45.000000000 -0700
-+++ pintos/src/userprog/syscall.h      2004-09-27 16:41:17.000000000 -0700
+ }
+Index: 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
+--- userprog/syscall.h 6 Sep 2004 05:38:45 -0000       1.2
++++ userprog/syscall.h 1 Jan 2005 02:13:43 -0000
 @@ -2,5 +2,6 @@
  #define USERPROG_SYSCALL_H