+Index: src/threads/thread.c
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
+--- src/threads/thread.c~
++++ src/threads/thread.c
@@ -13,6 +13,7 @@
#include "threads/synch.h"
#ifdef USERPROG
#endif
/* Random value for struct thread's `magic' member.
-@@ -251,16 +252,19 @@ thread_tid (void)
+@@ -251,18 +252,19 @@ thread_tid (void)
void
thread_exit (void)
{
-+ struct thread *t = thread_current ();
-+
ASSERT (!intr_context ());
#ifdef USERPROG
-
+ syscall_exit ();
+
- /* Just set our status to dying and schedule another process.
- We will be destroyed during the call to schedule_tail(). */
+ /* Remove thread from all threads list, set our status to dying,
+ and schedule another process. That process will destroy us
+ when it calls thread_schedule_tail(). */
intr_disable ();
-- thread_current ()->status = THREAD_DYING;
-+ t->status = THREAD_DYING;
+ list_remove (&thread_current()->allelem);
+ thread_current ()->status = THREAD_DYING;
schedule ();
NOT_REACHED ();
}
-@@ -400,6 +404,11 @@ init_thread (struct thread *t, const cha
+@@ -400,6 +404,10 @@ init_thread (struct thread *t, const cha
strlcpy (t->name, name, sizeof t->name);
t->stack = (uint8_t *) t + PGSIZE;
t->priority = priority;
+ list_init (&t->children);
-+ t->exit_code = -1;
+ t->wait_status = NULL;
+ list_init (&t->fds);
+ t->next_handle = 2;
t->magic = THREAD_MAGIC;
}
+Index: src/threads/thread.h
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
+--- src/threads/thread.h~
++++ src/threads/thread.h
@@ -4,6 +4,7 @@
#include <debug.h>
#include <list.h>
/* States in a thread's life cycle. */
enum thread_status
-@@ -89,6 +90,11 @@ struct thread
+@@ -89,6 +90,10 @@ struct thread
uint8_t *stack; /* Saved stack pointer. */
int priority; /* Priority. */
+ /* 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. */
+
+ struct semaphore dead; /* 1=child alive, 0=child dead. */
+ };
+
- void thread_init (void);
- void thread_start (void);
- void thread_tick (void);
+ /* If false (default), use round-robin scheduler.
+ If true, use multi-level feedback queue scheduler.
+ Controlled by kernel command-line options "-o mlfqs".
+Index: src/userprog/exception.c
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
+--- src/userprog/exception.c~
++++ src/userprog/exception.c
@@ -150,6 +150,14 @@ page_fault (struct intr_frame *f)
write = (f->error_code & PF_W) != 0;
user = (f->error_code & PF_U) != 0;
/* 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. */
+Index: src/userprog/process.c
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
+--- src/userprog/process.c~
++++ src/userprog/process.c
@@ -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"
+ #include "threads/vaddr.h"
- static thread_func execute_thread NO_RETURN;
+ static thread_func start_process NO_RETURN;
-static bool load (const char *cmdline, void (**eip) (void), void **esp);
+static bool load (const char *cmd_line, void (**eip) (void), void **esp);
+
+/* Data structure shared between process_execute() in the
-+ invoking thread and execute_thread() in the newly invoked
++ invoking thread and start_process() in the newly invoked
+ thread. */
+struct exec_info
+ {
-+ const char *filename; /* Program to load. */
++ const char *file_name; /* Program to load. */
+ struct semaphore load_done; /* "Up"ed when loading complete. */
+ struct wait_status *wait_status; /* Child process. */
+ bool success; /* Program successfully loaded? */
+ };
/* Starts a new thread running a user program loaded from
- FILENAME. The new thread may be scheduled (and may even exit)
+ FILE_NAME. The new thread may be scheduled (and may even exit)
@@ -27,29 +39,37 @@ static bool load (const char *cmdline, v
tid_t
- process_execute (const char *filename)
+ process_execute (const char *file_name)
{
- char *fn_copy;
+ struct exec_info exec;
+ char *save_ptr;
tid_t tid;
-- /* Make a copy of FILENAME.
+- /* Make a copy of FILE_NAME.
- Otherwise there's a race between the caller and load(). */
- fn_copy = palloc_get_page (0);
- if (fn_copy == NULL)
- return TID_ERROR;
-- strlcpy (fn_copy, filename, PGSIZE);
+- strlcpy (fn_copy, file_name, PGSIZE);
+ /* Initialize exec_info. */
-+ exec.filename = filename;
++ exec.file_name = file_name;
+ sema_init (&exec.load_done, 0);
- /* Create a new thread to execute FILENAME. */
-- tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
+ /* Create a new thread to execute FILE_NAME. */
+- tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
- if (tid == TID_ERROR)
- palloc_free_page (fn_copy);
-+ strlcpy (thread_name, filename, sizeof thread_name);
++ strlcpy (thread_name, file_name, sizeof thread_name);
+ strtok_r (thread_name, " ", &save_ptr);
-+ tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
++ tid = thread_create (thread_name, PRI_DEFAULT, start_process, &exec);
+ if (tid != TID_ERROR)
+ {
+ sema_down (&exec.load_done);
/* A thread function that loads a user process and starts it
running. */
static void
--execute_thread (void *filename_)
-+execute_thread (void *exec_)
+-start_process (void *file_name_)
++start_process (void *exec_)
{
-- char *filename = filename_;
+- char *file_name = file_name_;
+ struct exec_info *exec = exec_;
struct intr_frame if_;
bool success;
-@@ -58,10 +78,28 @@ execute_thread (void *filename_)
+@@ -58,10 +78,29 @@ start_process (void *file_name_)
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS;
-- success = load (filename, &if_.eip, &if_.esp);
-+ success = load (exec->filename, &if_.eip, &if_.esp);
+- success = load (file_name, &if_.eip, &if_.esp);
++ success = load (exec->file_name, &if_.eip, &if_.esp);
+
+ /* Allocate wait_status. */
+ if (success)
+ }
- /* If load failed, quit. */
-- palloc_free_page (filename);
+- palloc_free_page (file_name);
+ /* Initialize wait_status. */
+ if (success)
+ {
+ lock_init (&exec->wait_status->lock);
+ exec->wait_status->ref_cnt = 2;
+ exec->wait_status->tid = thread_current ()->tid;
++ exec->wait_status->exit_code = -1;
+ sema_init (&exec->wait_status->dead, 0);
+ }
+
if (!success)
thread_exit ();
-@@ -75,18 +113,47 @@ execute_thread (void *filename_)
+@@ -75,18 +113,47 @@ start_process (void *file_name_)
NOT_REACHED ();
}
return -1;
}
-@@ -95,8 +162,32 @@ void
+@@ -95,8 +162,30 @@ void
process_exit (void)
{
struct thread *cur = thread_current ();
+ struct list_elem *e, *next;
uint32_t *pd;
-+ printf ("%s: exit(%d)\n", cur->name, cur->exit_code);
-+
+ /* Close executable (and allow writes). */
+ file_close (cur->bin_file);
+
+ if (cur->wait_status != NULL)
+ {
+ struct wait_status *cs = cur->wait_status;
-+ cs->exit_code = cur->exit_code;
++ printf ("%s: exit(%d)\n", cur->name, cs->exit_code);
+ sema_up (&cs->dead);
+ release_child (cs);
+ }
to the kernel-only page directory. */
pd = cur->pagedir;
@@ -193,7 +284,7 @@ struct Elf32_Phdr
+ #define PF_W 2 /* Writable. */
#define PF_R 4 /* Readable. */
- static bool load_segment (struct file *, const struct Elf32_Phdr *);
-static bool setup_stack (void **esp);
+static bool setup_stack (const char *cmd_line, void **esp);
-
- /* Loads an ELF executable from FILENAME into the current thread.
- Stores the executable's entry point into *EIP
+ static bool validate_segment (const struct Elf32_Phdr *, struct file *);
+ static bool load_segment (struct file *file, off_t ofs, uint8_t *upage,
+ bool writable);
@@ -209,13 +300,15 @@ static bool setup_stack (void **esp);
and its initial stack pointer into *ESP.
Returns true if successful, false otherwise. */
bool
--load (const char *filename, void (**eip) (void), void **esp)
+-load (const char *file_name, void (**eip) (void), void **esp)
+load (const char *cmd_line, void (**eip) (void), void **esp)
{
struct thread *t = thread_current ();
-+ char filename[NAME_MAX + 2];
++ char file_name[NAME_MAX + 2];
struct Elf32_Ehdr ehdr;
struct file *file = NULL;
off_t file_ofs;
int i;
/* Allocate and activate page directory. */
-@@ -224,13 +317,22 @@ load (const char *filename, void (**eip)
+@@ -224,13 +317,22 @@ load (const char *file_name, void (**eip)
goto done;
process_activate ();
-+ /* Extract filename from command line. */
++ /* Extract file_name from command line. */
+ while (*cmd_line == ' ')
+ cmd_line++;
-+ strlcpy (filename, cmd_line, sizeof filename);
-+ cp = strchr (filename, ' ');
++ strlcpy (file_name, cmd_line, sizeof file_name);
++ cp = strchr (file_name, ' ');
+ if (cp != NULL)
+ *cp = '\0';
+
/* Open executable file. */
-- file = filesys_open (filename);
-+ t->bin_file = file = filesys_open (filename);
+- file = filesys_open (file_name);
++ t->bin_file = file = filesys_open (file_name);
if (file == NULL)
{
- printf ("load: %s: open failed\n", filename);
+ printf ("load: %s: open failed\n", file_name);
goto done;
}
+ file_deny_write (file);
/* Read and verify executable header. */
if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
-@@ -284,7 +386,7 @@ load (const char *filename, void (**eip)
+@@ -284,7 +386,7 @@ load (const char *file_name, void (**eip)
}
/* Set up stack. */
goto done;
/* Start address. */
-@@ -294,7 +396,6 @@ load (const char *filename, void (**eip)
+@@ -294,7 +396,6 @@ load (const char *file_name, void (**eip)
done:
/* We arrive here whether the load is successful or not. */
+ for (karg = strtok_r (cmd_line_copy, " ", &saveptr); karg != NULL;
+ karg = strtok_r (NULL, " ", &saveptr))
+ {
-+ char *uarg = upage + (karg - (char *) kpage);
++ void *uarg = upage + (karg - (char *) kpage);
+ if (push (kpage, &ofs, &uarg, sizeof uarg) == NULL)
+ return false;
+ argc++;
kpage = palloc_get_page (PAL_USER | PAL_ZERO);
if (kpage != NULL)
{
-- success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage);
+- success = install_page (((uint8_t *) PHYS_BASE) - PGSIZE, kpage, true);
- if (success)
- *esp = PHYS_BASE;
+ uint8_t *upage = ((uint8_t *) PHYS_BASE) - PGSIZE;
-+ if (install_page (upage, kpage))
++ if (install_page (upage, kpage, true))
+ success = init_cmd_line (kpage, upage, cmd_line, esp);
else
palloc_free_page (kpage);
}
+Index: src/userprog/syscall.c
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 @@
+--- src/userprog/syscall.c~
++++ src/userprog/syscall.c
+@@ -1,20 +1,486 @@
#include "userprog/syscall.h"
#include <stdio.h>
+#include <string.h>
#include <syscall-nr.h>
+#include "userprog/process.h"
+#include "userprog/pagedir.h"
-+#include "devices/kbd.h"
++#include "devices/input.h"
++#include "devices/shutdown.h"
+#include "filesys/filesys.h"
+#include "filesys/file.h"
-+#include "threads/init.h"
#include "threads/interrupt.h"
+#include "threads/malloc.h"
-+#include "threads/mmu.h"
+#include "threads/palloc.h"
#include "threads/thread.h"
++#include "threads/vaddr.h"
-
+
+
-
+static void copy_in (void *, const void *, size_t);
+
++/* Serializes file system operations. */
+static struct lock fs_lock;
+
void
+{
+ int eax;
+ asm ("movl $1f, %%eax; movb %b2, %0; 1:"
-+ : "=m" (*udst), "=&a" (eax) : "r" (byte));
++ : "=m" (*udst), "=&a" (eax) : "q" (byte));
+ return eax != 0;
+}
+
+ for (length = 0; length < PGSIZE; length++)
+ {
+ if (us >= (char *) PHYS_BASE || !get_user (ks + length, us++))
-+ thread_exit ();
++ {
++ palloc_free_page (ks);
++ thread_exit ();
++ }
+
+ if (ks[length] == '\0')
+ return ks;
+static int
+sys_halt (void)
+{
-+ power_off ();
++ shutdown_power_off ();
+}
+
+/* Exit system call. */
+static int
+sys_exit (int exit_code)
+{
-+ thread_current ()->exit_code = exit_code;
++ thread_current ()->wait_status->exit_code = exit_code;
+ thread_exit ();
+ NOT_REACHED ();
+}
+ if (handle == STDIN_FILENO)
+ {
+ for (bytes_read = 0; (size_t) bytes_read < size; bytes_read++)
-+ if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, kbd_getc ()))
++ if (udst >= (uint8_t *) PHYS_BASE || !put_user (udst++, input_getc ()))
+ thread_exit ();
+ return bytes_read;
+ }
+ struct file_descriptor *fd;
+ fd = list_entry (e, struct file_descriptor, elem);
+ next = list_next (e);
++ lock_acquire (&fs_lock);
+ file_close (fd->file);
++ lock_release (&fs_lock);
+ free (fd);
+ }
+}
+Index: src/userprog/syscall.h
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
+--- src/userprog/syscall.h~
++++ src/userprog/syscall.h
@@ -2,5 +2,6 @@
#define USERPROG_SYSCALL_H