+Index: src/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
+--- src/userprog/process.c 15 Dec 2004 02:32:02 -0000 1.6
++++ src/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,32 @@ 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);
++ success = exec->success = load (exec->filename, &if_.eip, &if_.esp);
++ sema_up (&exec->load_done);
+ if (!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