When run.out is missing in &grade_test, just return an error that
[pintos-anon] / solutions / p1-3.patch
1 Index: src/threads/synch.c
2 ===================================================================
3 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/synch.c,v
4 retrieving revision 1.15
5 diff -u -p -u -r1.15 synch.c
6 --- src/threads/synch.c 31 Dec 2004 21:13:38 -0000      1.15
7 +++ src/threads/synch.c 31 Dec 2004 22:31:03 -0000
8 @@ -77,6 +77,17 @@ sema_down (struct semaphore *sema) 
9    intr_set_level (old_level);
10  }
11  
12 +/* Returns true if thread A has lower priority than thread B. */
13 +static bool
14 +donated_lower_priority (const list_elem *a_, const list_elem *b_,
15 +                        void *aux UNUSED) 
16 +{
17 +  const struct thread *a = list_entry (a_, struct thread, donor_elem);
18 +  const struct thread *b = list_entry (b_, struct thread, donor_elem);
19 +
20 +  return a->priority < b->priority;
21 +}
22 +
23  /* Up or "V" operation on a semaphore.  Increments SEMA's value
24     and wakes up one thread of those waiting for SEMA, if any.
25  
26 @@ -89,10 +100,28 @@ sema_up (struct semaphore *sema) 
27    ASSERT (sema != NULL);
28  
29    old_level = intr_disable ();
30 -  if (!list_empty (&sema->waiters)) 
31 -    thread_unblock (list_entry (list_pop_front (&sema->waiters),
32 -                                struct thread, elem));
33    sema->value++;
34 +  if (!list_empty (&sema->waiters)) 
35 +    {
36 +      /* Find highest-priority waiting thread. */
37 +      struct thread *max = list_entry (list_max (&sema->waiters,
38 +                                                 donated_lower_priority, NULL),
39 +                                       struct thread, elem);
40 +
41 +      /* Remove `max' from wait list and unblock. */
42 +      list_remove (&max->elem);
43 +      thread_unblock (max);
44 +
45 +      /* Yield to a higher-priority thread, if we're running in a
46 +         context where it makes sense to do so.
47 +         
48 +         Kind of a funny interaction with donation here.
49 +         We only support donation for locks, and locks turn off
50 +         interrupts before calling us, so we automatically don't
51 +         do the yield here, delegating to lock_release(). */
52 +      if (!intr_context () && old_level == INTR_ON)
53 +        thread_yield_to_higher_priority ();
54 +    }
55    intr_set_level (old_level);
56  }
57  
58 @@ -184,6 +213,23 @@ lock_acquire (struct lock *lock)
59    ASSERT (!lock_held_by_current_thread (lock));
60  
61    old_level = intr_disable ();
62 +
63 +  if (lock->holder != NULL) 
64 +    {
65 +      /* Donate our priority to the thread holding the lock.
66 +         First, update the data structures. */
67 +      struct thread *donor = thread_current ();
68 +      donor->want_lock = lock;
69 +      donor->donee = lock->holder;
70 +      list_push_back (&lock->holder->donors, &donor->donor_elem);
71 +      
72 +      /* Now implement the priority donation itself
73 +         by recomputing the donee's priority
74 +         and cascading the donation as far as necessary. */
75 +      while (donor->donee != NULL && thread_recompute_priority (donor->donee))
76 +        donor = donor->donee;
77 +    }
78 +
79    sema_down (&lock->semaphore);
80    lock->holder = thread_current ();
81    intr_set_level (old_level);
82 @@ -198,13 +244,38 @@ void
83  lock_release (struct lock *lock) 
84  {
85    enum intr_level old_level;
86 +  struct thread *t = thread_current ();
87 +  list_elem *e;
88  
89    ASSERT (lock != NULL);
90    ASSERT (lock_held_by_current_thread (lock));
91  
92    old_level = intr_disable ();
93 +
94 +  /* Remove donations from threads that want the lock we're
95 +     releasing. */
96 +  for (e = list_begin (&t->donors); e != list_end (&t->donors); ) 
97 +    {
98 +      struct thread *donor = list_entry (e, struct thread, donor_elem);
99 +      if (donor->want_lock == lock) 
100 +        {
101 +          donor->donee = NULL;
102 +          e = list_remove (e);
103 +        }
104 +      else
105 +        e = list_next (e);
106 +    }
107 +
108 +  /* Release lock. */
109    lock->holder = NULL;
110    sema_up (&lock->semaphore);
111 +
112 +  /* Recompute our priority based on our remaining donations,
113 +     then yield to a higher-priority ready thread if one now
114 +     exists. */
115 +  thread_recompute_priority (t);
116 +  thread_yield_to_higher_priority ();
117 +
118    intr_set_level (old_level);
119  }
120  
121 Index: src/threads/thread.c
122 ===================================================================
123 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/thread.c,v
124 retrieving revision 1.48
125 diff -u -p -u -r1.48 thread.c
126 --- src/threads/thread.c        9 Oct 2004 18:01:37 -0000       1.48
127 +++ src/threads/thread.c        31 Dec 2004 22:31:03 -0000
128 @@ -166,6 +166,8 @@ thread_create (const char *name, int pri
129  
130    /* Add to run queue. */
131    thread_unblock (t);
132 +  if (priority > thread_get_priority ())
133 +    thread_yield ();
134  
135    return tid;
136  }
137 @@ -186,6 +188,18 @@ thread_block (void) 
138    schedule ();
139  }
140  
141 +/* Returns true if A has higher priority than B,
142 +   within a list of threads. */
143 +static bool
144 +thread_higher_priority (const list_elem *a_, const list_elem *b_,
145 +                        void *aux UNUSED) 
146 +{
147 +  const struct thread *a = list_entry (a_, struct thread, elem);
148 +  const struct thread *b = list_entry (b_, struct thread, elem);
149 +
150 +  return a->priority > b->priority;
151 +}
152 +
153  /* Transitions a blocked thread T to the ready-to-run state.
154     This is an error if T is not blocked.  (Use thread_yield() to
155     make the running thread ready.) */
156 @@ -198,7 +212,7 @@ thread_unblock (struct thread *t) 
157  
158    old_level = intr_disable ();
159    ASSERT (t->status == THREAD_BLOCKED);
160 -  list_push_back (&ready_list, &t->elem);
161 +  list_insert_ordered (&ready_list, &t->elem, thread_higher_priority, NULL);
162    t->status = THREAD_READY;
163    intr_set_level (old_level);
164  }
165 @@ -266,8 +280,8 @@ thread_yield (void) 
166    ASSERT (!intr_context ());
167  
168    old_level = intr_disable ();
169 -  list_push_back (&ready_list, &cur->elem);
170 +  list_insert_ordered (&ready_list, &cur->elem, thread_higher_priority, NULL);
171    cur->status = THREAD_READY;
172    schedule ();
173    intr_set_level (old_level);
174  }
175 @@ -274,19 +288,74 @@
176  {
177  }
178  
179 -/* Sets the current thread's priority to NEW_PRIORITY. */
180 -void
181 -thread_set_priority (int new_priority) 
182 -{
183 -  thread_current ()->priority = new_priority;
184 -}
185 -
186 -/* Returns the current thread's priority. */
187 -int
188 -thread_get_priority (void) 
189 -{
190 -  return thread_current ()->priority;
191 -}
192 +
193 +/* Sets the current thread's priority to PRIORITY. */
194 +void
195 +thread_set_priority (int priority) 
196 +{
197 +  struct thread *t = thread_current ();
198 +  enum intr_level old_level;
199 +
200 +  t->normal_priority = priority;
201 +
202 +  old_level = intr_disable ();
203 +  while (thread_recompute_priority (t) && t->donee != NULL)
204 +    t = t->donee;
205 +  thread_yield_to_higher_priority ();
206 +  intr_set_level (old_level);
207 +}
208 +
209 +/* Returns the current thread's priority. */
210 +int
211 +thread_get_priority (void) 
212 +{
213 +  return thread_current ()->priority;
214 +}
215 +
216 +/* Returns true if thread A has lower priority than thread B,
217 +   within a list of donors. */
218 +static bool
219 +donated_lower_priority (const list_elem *a_, const list_elem *b_,
220 +                       void *aux UNUSED) 
221 +{
222 +  const struct thread *a = list_entry (a_, struct thread, donor_elem);
223 +  const struct thread *b = list_entry (b_, struct thread, donor_elem);
224 +
225 +  return a->priority < b->priority;
226 +}
227 +
228 +/* Recomputes T's priority in terms of its normal priority and
229 +   its donors' priorities, if any.
230 +   Returns true if T's new priority is higher than its old
231 +   priority, false otherwise. */
232 +bool
233 +thread_recompute_priority (struct thread *t) 
234 +{
235 +  int old = t->priority;
236 +  int donation = 0;
237 +  if (!list_empty (&t->donors))
238 +    donation = list_entry (list_max (&t->donors, donated_lower_priority, NULL),
239 +                           struct thread, donor_elem)->priority;
240 +  t->priority = donation > t->normal_priority ? donation : t->normal_priority;
241 +  return t->priority > old;
242 +}
243 +
244 +/* If the ready list contains a thread with a higher priority,
245 +   yields to it. */
246 +void
247 +thread_yield_to_higher_priority (void)
248 +{
249 +  enum intr_level old_level = intr_disable ();
250 +  if (!list_empty (&ready_list)) 
251 +    {
252 +      struct thread *cur = thread_current ();
253 +      struct thread *max = list_entry (list_front (&ready_list),
254 +                                       struct thread, elem);
255 +      if (max->priority > cur->priority)
256 +        thread_yield (); 
257 +    }
258 +  intr_set_level (old_level);
259 +}
260  \f
261  /* Idle thread.  Executes when no other thread is ready to run. */
262  static void
263 @@ -335,8 +417,9 @@ init_thread (struct thread *t, const cha
264    t->status = THREAD_BLOCKED;
265    strlcpy (t->name, name, sizeof t->name);
266    t->stack = (uint8_t *) t + PGSIZE;
267 -  t->priority = priority;
268 +  t->priority = t->normal_priority = priority;
269    t->magic = THREAD_MAGIC;
270 +  list_init (&t->donors);
271  }
272  
273  /* Allocates a SIZE-byte frame at the top of thread T's stack and
274 Index: src/threads/thread.h
275 ===================================================================
276 RCS file: /afs/ir.stanford.edu/users/b/l/blp/private/cvs/pintos/src/threads/thread.h,v
277 retrieving revision 1.28
278 diff -u -p -u -r1.28 thread.h
279 --- src/threads/thread.h        29 Sep 2004 01:04:20 -0000      1.28
280 +++ src/threads/thread.h        31 Dec 2004 22:31:03 -0000
281 @@ -87,7 +87,14 @@ struct thread
282      enum thread_status status;          /* Thread state. */
283      char name[16];                      /* Name (for debugging purposes). */
284      uint8_t *stack;                     /* Saved stack pointer. */
285 -    int priority;                       /* Priority. */
286 +
287 +    /* Thread priority. */
288 +    int priority;                       /* Priority, including donations. */
289 +    int normal_priority;                /* Priority, without donations. */
290 +    struct list donors;                 /* Threads donating priority to us. */
291 +    list_elem donor_elem;               /* Element in donors list. */
292 +    struct thread *donee;               /* Thread we're donating to. */
293 +    struct lock *want_lock;             /* Lock we're waiting to acquire. */
294  
295      /* Shared between thread.c and synch.c. */
296      list_elem elem;                     /* List element. */
297 @@ -118,6 +125,8 @@ const char *thread_name (void);
298  
299  void thread_exit (void) NO_RETURN;
300  void thread_yield (void);
301 +void thread_yield_to_higher_priority (void);
302 +bool thread_recompute_priority (struct thread *);
303  
304  /* This function will be implemented in problem 1-2. */
305  void thread_join (tid_t);