-diff -urp 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-22 00:34:01.000000000 -0700
-@@ -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
-Only in pintos/src: constants.h~
-diff -urp 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-22 00:30:05.000000000 -0700
-@@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
-
- return cond->name;
- }
-+\f
-+void
-+latch_init (struct latch *latch, const char *name)
-+{
-+ latch->released = false;
-+ lock_init (&latch->monitor_lock, name);
-+ cond_init (&latch->rel_cond, name);
-+}
-+
-+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);
-+}
-+
-+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);
-+}
-diff -urp 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-22 00:30:05.000000000 -0700
-@@ -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 */
-diff -urp pintos.orig/src/threads/thread.c pintos/src/threads/thread.c
---- pintos.orig/src/threads/thread.c 2004-09-21 22:42:17.000000000 -0700
-+++ pintos/src/threads/thread.c 2004-09-22 00:32:39.000000000 -0700
+diff -u src/threads/thread.c~ src/threads/thread.c
+--- src/threads/thread.c~ 2005-06-02 14:35:12.000000000 -0700
++++ src/threads/thread.c 2005-06-08 13:45:28.000000000 -0700
@@ -13,6 +13,7 @@
#include "threads/synch.h"
#ifdef USERPROG
#endif
/* Random value for struct thread's `magic' member.
-@@ -75,6 +76,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.
-@@ -119,6 +121,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);
-@@ -195,16 +198,36 @@ thread_tid (void)
+@@ -251,16 +252,19 @@ thread_tid (void)
void
thread_exit (void)
{
+ struct thread *t = thread_current ();
-+ 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(). */
intr_disable ();
schedule ();
NOT_REACHED ();
}
-@@ -241,6 +264,26 @@ thread_block (void)
- thread_current ()->status = THREAD_BLOCKED;
- schedule ();
- }
-+
-+/* Waits for thread with tid CHILD_TID to die. */
-+int
-+thread_join (tid_t child_tid)
-+{
-+ struct thread *cur = thread_current ();
-+ 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->ret_code;
-+ }
-+ }
-+ return -1;
-+}
- \f
- /* Idle thread. Executes when no other thread is ready to run. */
- static void
-@@ -306,6 +349,12 @@ init_thread (struct thread *t, const cha
+@@ -400,6 +404,11 @@ 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;
++ t->wait_status = NULL;
+ list_init (&t->fds);
+ t->next_handle = 2;
t->magic = THREAD_MAGIC;
}
-Only in pintos/src/threads: thread.c.orig
-Only in pintos/src/threads: thread.c.rej
-Only in pintos/src/threads: thread.c~
-diff -urp pintos.orig/src/threads/thread.h pintos/src/threads/thread.h
---- pintos.orig/src/threads/thread.h 2004-09-20 15:29:18.000000000 -0700
-+++ pintos/src/threads/thread.h 2004-09-22 00:30:05.000000000 -0700
+diff -u src/threads/thread.h~ src/threads/thread.h
+--- src/threads/thread.h~ 2005-06-02 14:32:36.000000000 -0700
++++ src/threads/thread.h 2005-06-08 13:47:09.000000000 -0700
@@ -4,6 +4,7 @@
#include <debug.h>
#include <list.h>
/* States in a thread's life cycle. */
enum thread_status
-@@ -89,12 +90,23 @@ struct thread
+@@ -89,6 +90,11 @@ 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. */
-+ list_elem children_elem; /* Element of `children' list. */
-+ int ret_code; /* Return status. */
++ /* Owned by process.c. */
++ int exit_code; /* Exit code. */
++ struct wait_status *wait_status; /* This process's completion status. */
++ struct list children; /* Completion status of children. */
+
/* Shared between thread.c and synch.c. */
- list_elem elem; /* List element. */
+ 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 */
-@@ -117,7 +129,7 @@ void thread_yield (void);
- void thread_block (void);
-
- /* This function will be implemented in problem 1-2. */
--void thread_join (tid_t);
-+int thread_join (tid_t);
-
- /* These functions will be implemented in problem 1-3. */
- void thread_set_priority (int);
-Only in pintos/src/userprog: build
-diff -urp pintos.orig/src/userprog/exception.c pintos/src/userprog/exception.c
---- pintos.orig/src/userprog/exception.c 2004-09-20 12:06:58.000000000 -0700
-+++ pintos/src/userprog/exception.c 2004-09-22 00:30:05.000000000 -0700
-@@ -134,6 +134,13 @@ page_fault (struct intr_frame *f)
+ /* Owned by thread.c. */
+ unsigned magic; /* Detects stack overflow. */
+ };
+
++/* 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. */
++ };
++
+ void thread_init (void);
+ void thread_start (void);
+ void thread_tick (void);
+diff -u src/userprog/exception.c~ src/userprog/exception.c
+--- src/userprog/exception.c~ 2005-01-01 18:09:59.000000000 -0800
++++ src/userprog/exception.c 2005-06-08 13:45:28.000000000 -0700
+@@ -150,6 +150,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 -urp pintos.orig/src/userprog/pagedir.c pintos/src/userprog/pagedir.c
---- pintos.orig/src/userprog/pagedir.c 2004-09-21 22:42:17.000000000 -0700
-+++ pintos/src/userprog/pagedir.c 2004-09-22 00:32:23.000000000 -0700
-@@ -99,7 +99,7 @@ pagedir_set_page (uint32_t *pd, void *up
- ASSERT (pg_ofs (upage) == 0);
- ASSERT (pg_ofs (kpage) == 0);
- ASSERT (upage < PHYS_BASE);
-- ASSERT (lookup_page (pd, upage, false) == NULL);
-+ ASSERT (pagedir_get_page (pd, upage) == NULL);
-
- pte = lookup_page (pd, upage, true);
- if (pte != NULL)
-Only in pintos/src/userprog: pagedir.c.orig
-Only in pintos/src/userprog: pagedir.c.rej
-Only in pintos/src/userprog: pagedir.c.rej~
-Only in pintos/src/userprog: pagedir.c~
-diff -urp pintos.orig/src/userprog/process.c pintos/src/userprog/process.c
---- pintos.orig/src/userprog/process.c 2004-09-21 22:42:17.000000000 -0700
-+++ pintos/src/userprog/process.c 2004-09-22 00:30:05.000000000 -0700
-@@ -182,7 +182,7 @@ struct Elf32_Phdr
+diff -u src/userprog/process.c~ src/userprog/process.c
+--- src/userprog/process.c~ 2005-05-26 13:19:48.000000000 -0700
++++ src/userprog/process.c 2005-06-08 13:49:13.000000000 -0700
+@@ -14,11 +14,23 @@
+ #include "threads/init.h"
+ #include "threads/interrupt.h"
+ #include "threads/mmu.h"
++#include "threads/malloc.h"
+ #include "threads/palloc.h"
+ #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. */
++ 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 (and may even exit)
+@@ -27,29 +39,37 @@ static bool load (const char *cmdline, v
+ tid_t
+ process_execute (const char *filename)
+ {
+- char *fn_copy;
++ struct exec_info exec;
++ char thread_name[16];
++ char *save_ptr;
+ 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);
+
+ /* 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);
++ strlcpy (thread_name, filename, sizeof thread_name);
++ strtok_r (thread_name, " ", &save_ptr);
++ tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
++ if (tid != TID_ERROR)
++ {
++ sema_down (&exec.load_done);
++ 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_)
+ {
+- char *filename = filename_;
++ struct exec_info *exec = exec_;
+ struct intr_frame if_;
+ bool success;
+
+@@ -58,10 +78,28 @@ execute_thread (void *filename_)
+ if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
+ if_.cs = SEL_UCSEG;
+ if_.eflags = FLAG_IF | FLAG_MBS;
+- success = load (filename, &if_.eip, &if_.esp);
++ success = load (exec->filename, &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);
++ /* Initialize wait_status. */
++ if (success)
++ {
++ lock_init (&exec->wait_status->lock);
++ exec->wait_status->ref_cnt = 2;
++ exec->wait_status->tid = thread_current ()->tid;
++ 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 ();
+
+@@ -75,18 +113,47 @@ execute_thread (void *filename_)
+ 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,32 @@ 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;
++ cs->exit_code = cur->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. */
+ pd = cur->pagedir;
+@@ -193,7 +284,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);
+ /* Loads an ELF executable from FILENAME into the current thread.
+ Stores the executable's entry point into *EIP
+@@ -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 *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];
+ char *cp;
int i;
- /* Allocate page directory. */
-@@ -212,6 +214,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 *filename, void (**eip)
+ goto done;
+ process_activate ();
+ /* 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)
+- file = filesys_open (filename);
++ t->bin_file = file = filesys_open (filename);
+ if (file == NULL)
+ {
+ printf ("load: %s: open failed\n", filename);
+ 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 *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
+@@ -294,7 +396,6 @@ load (const char *filename, 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;
}
-/* 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)
- kpage = palloc_get (PAL_USER | PAL_ZERO);
+@@ -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);
- *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 (kpage);
+ palloc_free_page (kpage);
}
-Only in pintos/src/userprog: process.c.orig
-diff -urp pintos.orig/src/userprog/syscall.c pintos/src/userprog/syscall.c
---- pintos.orig/src/userprog/syscall.c 2004-09-05 22:19:19.000000000 -0700
-+++ pintos/src/userprog/syscall.c 2004-09-22 00:30:05.000000000 -0700
-@@ -1,20 +1,429 @@
+diff -u src/userprog/syscall.c~ src/userprog/syscall.c
+--- src/userprog/syscall.c~ 2004-09-26 14:15:17.000000000 -0700
++++ src/userprog/syscall.c 2005-06-08 13:45:28.000000000 -0700
+@@ -1,20 +1,480 @@
#include "userprog/syscall.h"
#include <stdio.h>
+#include <string.h>
+#include "threads/mmu.h"
+#include "threads/palloc.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_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);
+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 *);
+-
+static void copy_in (void *, const void *, size_t);
-+
++
+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);
}
-
- static void
- syscall_handler (struct intr_frame *f)
- {
-- printf ("system call!\n");
-+ struct syscall *s;
-+ int call_nr;
-+ int args[3];
++
++/* System call handler. */
++static void
++syscall_handler (struct intr_frame *f)
++{
++ typedef int syscall_function (int, int, int);
+
-+ copy_in (&call_nr, f->esp, sizeof call_nr);
-+ if (call_nr < 0 || call_nr >= syscall_cnt)
++ /* A system call. */
++ struct syscall
+ {
-+ printf ("bad syscall number %d\n", call_nr);
-+ thread_exit ();
-+ }
++ 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_wait},
++ {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},
++ };
++
++ const struct syscall *sc;
++ unsigned call_nr;
++ int args[3];
+
-+ s = syscall_table + call_nr;
-+ ASSERT (s->arg_cnt <= sizeof args / sizeof *args);
++ /* Get the system call. */
++ copy_in (&call_nr, f->esp, sizeof call_nr);
++ if (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;
++ return (uaddr < PHYS_BASE
++ && 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_;
+ const uint8_t *usrc = usrc_;
-+
++
+ for (; size > 0; size--, dst++, usrc++)
+ if (usrc >= (uint8_t *) PHYS_BASE || !get_user (dst, usrc))
+ 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)
+{
+ char *ks;
+ size_t length;
-+
-+ ks = palloc_get (0);
++
++ 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 (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)
+{
+ tid_t tid;
+ char *kfile = copy_in_string (ufile);
-+
++
+ lock_acquire (&fs_lock);
+ tid = process_execute (kfile);
+ lock_release (&fs_lock);
-+
-+ palloc_free (kfile);
-+
++
++ palloc_free_page (kfile);
++
+ return tid;
+}
-+
++
++/* 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. */
+static int
+sys_create (const char *ufile, unsigned initial_size)
+{
+ char *kfile = copy_in_string (ufile);
+ bool ok;
-+
++
+ lock_acquire (&fs_lock);
+ ok = filesys_create (kfile, initial_size);
+ lock_release (&fs_lock);
-+
-+ palloc_free (kfile);
-+
++
++ palloc_free_page (kfile);
++
+ return ok;
+}
-+
++
++/* Remove system call. */
+static int
+sys_remove (const char *ufile)
-+{
+ {
+- printf ("system call!\n");
+ char *kfile = copy_in_string (ufile);
+ bool ok;
-+
++
+ lock_acquire (&fs_lock);
+ ok = filesys_remove (kfile);
+ lock_release (&fs_lock);
-+
-+ palloc_free (kfile);
-+
++
++ palloc_free_page (kfile);
++
+ 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;
++ struct 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 (kfile);
++
++ 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 ();
-+ list_elem *e;
-+
++ struct list_elem *e;
++
+ 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);
+ size = file_length (fd->file);
+ lock_release (&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++)
+ 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;
+ }
+ lock_release (&fs_lock);
-+
++
+ 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;
+ }
+ lock_release (&fs_lock);
-+
++
+ 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);
++ if ((off_t) position >= 0)
++ file_seek (fd->file, position);
+ lock_release (&fs_lock);
-+
++
+ 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);
+ position = file_tell (fd->file);
+ lock_release (&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);
+ free (fd);
+ return 0;
+}
-+
++
++/* On thread exit, close all open files. */
+void
+syscall_exit (void)
+{
+ struct thread *cur = thread_current ();
-+ list_elem *e, *next;
-+
++ struct list_elem *e, *next;
++
+ 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 -urp 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-22 00:30:05.000000000 -0700
+diff -u src/userprog/syscall.h~ src/userprog/syscall.h
+--- src/userprog/syscall.h~ 2004-09-05 22:38:45.000000000 -0700
++++ src/userprog/syscall.h 2005-06-08 13:45:28.000000000 -0700
@@ -2,5 +2,6 @@
#define USERPROG_SYSCALL_H