+-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 +41,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 +80,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);
+
+- /* If load failed, quit. */
+- palloc_free_page (filename);
++ /* Allocate wait_status. */
++ if (success)
++ {
++ exec->wait_status = thread_current ()->wait_status
++ = malloc (sizeof *exec->wait_status);
++ success = exec->wait_status != NULL;
++ }
++
++ /* 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 +115,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;