Fix race condition in process loading.
[pintos-anon] / solutions / p1-2.patch
1 diff -X pat -urpN threads/synch.c! src/threads/synch.c
2 --- src/threads/synch.c~        2004-09-19 21:29:53.000000000 -0700
3 +++ src/threads/synch.c 2004-09-27 16:50:14.000000000 -0700
4 @@ -330,3 +330,35 @@ cond_name (const struct condition *cond)
5  
6    return cond->name;
7  }
8 +\f
9 +void
10 +latch_init (struct latch *latch, const char *name) 
11 +{
12 +  latch->released = false;
13 +  lock_init (&latch->monitor_lock, name);
14 +  cond_init (&latch->rel_cond, name);
15 +}
16 +
17 +void
18 +latch_acquire (struct latch *latch) 
19 +{
20 +  lock_acquire (&latch->monitor_lock);
21 +  if (!latch->released) 
22 +    {
23 +      cond_wait (&latch->rel_cond, &latch->monitor_lock);
24 +      ASSERT (latch->released); 
25 +    }
26 +  lock_release (&latch->monitor_lock);
27 +}
28 +
29 +void
30 +latch_release (struct latch *latch) 
31 +{
32 +  lock_acquire (&latch->monitor_lock);
33 +  if (!latch->released)
34 +    {
35 +      latch->released = true;
36 +      cond_signal (&latch->rel_cond, &latch->monitor_lock);
37 +    }
38 +  lock_release (&latch->monitor_lock);
39 +}
40 diff -X pat -urpN src/threads/synch.h~ src/threads/synch.h
41 --- src/threads/synch.h~        2004-09-19 21:29:53.000000000 -0700
42 +++ src/threads/synch.h 2004-09-27 16:50:14.000000000 -0700
43 @@ -44,4 +44,16 @@ void cond_signal (struct condition *, st
44  void cond_broadcast (struct condition *, struct lock *);
45  const char *cond_name (const struct condition *);
46  
47 +/* Latch. */
48 +struct latch 
49 +  {
50 +    bool released;              /* Released yet? */
51 +    struct lock monitor_lock;   /* Monitor lock. */
52 +    struct condition rel_cond;  /* Signaled when released. */
53 +  };
54 +
55 +void latch_init (struct latch *, const char *);
56 +void latch_acquire (struct latch *);
57 +void latch_release (struct latch *);
58 +
59  #endif /* threads/synch.h */
60 diff -X pat -urpN src/threads/thread.c~ src/threads/thread.c
61 --- src/threads/thread.c~       2004-09-26 14:15:17.000000000 -0700
62 +++ src/threads/thread.c        2004-09-27 16:51:03.000000000 -0700
63 @@ -80,6 +80,7 @@ thread_init (void) 
64    init_thread (initial_thread, "main", PRI_DEFAULT);
65    initial_thread->status = THREAD_RUNNING;
66    initial_thread->tid = allocate_tid ();
67 +  sema_up (&initial_thread->can_die);
68  }
69  
70  /* Starts preemptive thread scheduling by enabling interrupts.
71 @@ -148,6 +149,7 @@ thread_create (const char *name, int pri
72    /* Initialize thread. */
73    init_thread (t, name, priority);
74    tid = t->tid = allocate_tid ();
75 +  list_push_back (&thread_current ()->children, &t->children_elem);
76  
77    /* Stack frame for kernel_thread(). */
78    kf = alloc_frame (t, sizeof *kf);
79 @@ -224,16 +226,34 @@ thread_tid (void) 
80  void
81  thread_exit (void) 
82  {
83 +  struct thread *t = thread_current ();
84 +  list_elem *e, *next;
85 +
86    ASSERT (!intr_context ());
87  
88  #ifdef USERPROG
89    process_exit ();
90  #endif
91  
92 +  /* Notify our parent that we're dying. */
93 +  latch_release (&t->ready_to_die);
94 +
95 +  /* Notify our children that they can die. */
96 +  for (e = list_begin (&t->children); e != list_end (&t->children); e = next)
97 +    {
98 +      struct thread *child = list_entry (e, struct thread, children_elem);
99 +      next = list_next (e);
100 +      list_remove (e);
101 +      sema_up (&child->can_die); 
102 +    }
103 +
104 +  /* Wait until our parent is ready for us to die. */
105 +  sema_down (&t->can_die);
106 +
107    /* Just set our status to dying and schedule another process.
108       We will be destroyed during the call to schedule_tail(). */
109    intr_disable ();
110 -  thread_current ()->status = THREAD_DYING;
111 +  t->status = THREAD_DYING;
112    schedule ();
113    NOT_REACHED ();
114  }
115 @@ -270,6 +290,22 @@ thread_block (void) 
116    thread_current ()->status = THREAD_BLOCKED;
117    schedule ();
118  }
119 +
120 +/* Waits for thread with tid CHILD_TID to die. */
121 +void
122 +thread_join (tid_t child_tid) 
123 +{
124 +  struct thread *cur = thread_current ();
125 +  list_elem *e;
126 +
127 +  for (e = list_begin (&cur->children); e != list_end (&cur->children); ) 
128 +    {
129 +      struct thread *child = list_entry (e, struct thread, children_elem);
130 +      e = list_next (e);
131 +      if (child->tid == child_tid) 
132 +        latch_acquire (&child->ready_to_die);
133 +    }
134 +}
135  \f
136  /* Idle thread.  Executes when no other thread is ready to run. */
137  static void
138 @@ -335,6 +371,9 @@ init_thread (struct thread *t, const cha
139    strlcpy (t->name, name, sizeof t->name);
140    t->stack = (uint8_t *) t + PGSIZE;
141    t->priority = priority;
142 +  latch_init (&t->ready_to_die, "ready-to-die");
143 +  sema_init (&t->can_die, 0, "can-die");
144 +  list_init (&t->children);
145    t->magic = THREAD_MAGIC;
146  }
147  
148 diff -X pat -urpN src/threads/thread.h~ src/threads/thread.h
149 --- src/threads/thread.h~       2004-09-26 14:15:17.000000000 -0700
150 +++ src/threads/thread.h        2004-09-27 16:50:14.000000000 -0700
151 @@ -4,6 +4,7 @@
152  #include <debug.h>
153  #include <list.h>
154  #include <stdint.h>
155 +#include "threads/synch.h"
156  
157  /* States in a thread's life cycle. */
158  enum thread_status
159 @@ -89,6 +90,12 @@ struct thread
160      uint8_t *stack;                     /* Saved stack pointer. */
161      int priority;                       /* Priority. */
162  
163 +    /* Members for implementing thread_join(). */
164 +    struct latch ready_to_die;          /* Release when thread about to die. */
165 +    struct semaphore can_die;           /* Up when thread allowed to die. */
166 +    struct list children;               /* List of child threads. */
167 +    list_elem children_elem;            /* Element of `children' list. */
168 +
169      /* Shared between thread.c and synch.c. */
170      list_elem elem;                     /* List element. */
171