From: Ben Pfaff Date: Sat, 1 Jan 2005 02:16:53 +0000 (+0000) Subject: Update solutions. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=597cd3a7dc722167fba91c8c7f572ca80107c966;p=pintos-anon Update solutions. --- diff --git a/solutions/README b/solutions/README index 1e23f07..ab3e9a0 100644 --- a/solutions/README +++ b/solutions/README @@ -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 diff --git a/solutions/p2.patch b/solutions/p2.patch index 68331bd..8f64855 100644 --- a/solutions/p2.patch +++ b/solutions/p2.patch @@ -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; } + ++/* 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; +} - /* 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 #include @@ -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 +#include @@ -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