-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)
+{
+ cond_init (&latch->rel_cond, name);
+}
+
++/* Acquires LATCH, blocking until it is released for the first
++ time. */
+void
+latch_acquire (struct latch *latch)
+{
+ lock_release (&latch->monitor_lock);
+}
+
++/* Releases LATCH, causing all ongoing and subsequent
++ acquisitions to pass through immediately. */
+void
+latch_release (struct latch *latch)
+{
+ }
+ 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 *);
+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
#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 ();
}
/* 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 ();
/* 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)
{
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. */
+ 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>
+ 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. */
+ 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);
/* 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;
/* 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];
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';
/* 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)
+{
+ }
+}
+
++/* 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)
+{
+ 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)
+ /* 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);
+}
+
+/* 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)
{
- *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>
#include "threads/thread.h"
-
+
-+typedef int syscall_function (int, int, int);
+
+static int sys_halt (void);
+static int sys_exit (int status);
+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 *);
-
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_;
+ 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)
+{
+
+ 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)
+{
+ 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)
+{
+ return ok;
+}
+
++/* Remove system call. */
+static int
+sys_remove (const char *ufile)
-+{
+ {
+- printf ("system call!\n");
+ char *kfile = copy_in_string (ufile);
+ bool ok;
+
+ 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 ();
+ 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);
+ 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++)
+ 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)
+ {
+ 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;
+ }
+ 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);
+ 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;
+ }
+ 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);
+ 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);
+ 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);
+ return 0;
+}
+
++/* On thread exit, close all open files. */
+void
+syscall_exit (void)
+{
+
+ 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