summaryrefslogtreecommitdiffstats
path: root/threads/synch.c
diff options
context:
space:
mode:
Diffstat (limited to 'threads/synch.c')
-rw-r--r--threads/synch.c67
1 files changed, 36 insertions, 31 deletions
diff --git a/threads/synch.c b/threads/synch.c
index 2cb4805..6ffe1de 100644
--- a/threads/synch.c
+++ b/threads/synch.c
@@ -73,9 +73,8 @@ sema_down (struct semaphore *sema)
73 old_level = intr_disable (); 73 old_level = intr_disable ();
74 while (sema->value == 0) 74 while (sema->value == 0)
75 { 75 {
76 /* add thread to our ordered waiters list */ 76 /* sorting the list here isn't useful. see sema_up() for more details */
77 list_insert_ordered (&sema->waiters, &thread_current ()->elem, 77 list_push_back (&sema->waiters, &thread_current ()->elem);
78 &thread_priority_cmp_greater, NULL);
79 thread_block (); 78 thread_block ();
80 } 79 }
81 sema->value--; 80 sema->value--;
@@ -116,21 +115,27 @@ void
116sema_up (struct semaphore *sema) 115sema_up (struct semaphore *sema)
117{ 116{
118 enum intr_level old_level; 117 enum intr_level old_level;
119 struct thread *t = NULL; 118 bool yield = false;
120 119
121 ASSERT (sema != NULL); 120 ASSERT (sema != NULL);
122 121
123 old_level = intr_disable (); 122 old_level = intr_disable ();
124 while (!list_empty (&sema->waiters)) 123 if (!list_empty (&sema->waiters))
125 { 124 {
126 t = list_entry (list_pop_front (&sema->waiters), struct thread, elem); 125 /* we can't sort the list during insertion that easily as the priority of
127 thread_unblock (t); 126 blocked/waiting threads may change due to priority donation.
128 } 127 we only need to unblock one thread thus we simply sort the list here */
128 list_sort (&sema->waiters, &thread_priority_cmp_greater, NULL);
129 struct thread *t = list_entry (list_pop_front (&sema->waiters), struct thread, elem);
130 /* thread_unblock() doesn't yield so check if there's a need */
131 if (t->priority > thread_current ()->priority)
132 yield = true;
133 thread_unblock (t);
134 }
129 sema->value++; 135 sema->value++;
130 intr_set_level (old_level); 136 intr_set_level (old_level);
131 137
132 /* thread_unblock() doesn't yield so check if there's a need */ 138 if (yield)
133 if (t != NULL && t->priority > thread_current ()->priority)
134 thread_yield(); 139 thread_yield();
135} 140}
136 141
@@ -224,22 +229,22 @@ lock_acquire (struct lock *lock)
224 ASSERT (!lock_held_by_current_thread (lock)); 229 ASSERT (!lock_held_by_current_thread (lock));
225 230
226 if (lock->holder != NULL) 231 if (lock->holder != NULL)
227 {
228 /* check for a possible priority donation */
229 if (cur->priority > lock->priority)
230 { 232 {
231 /* the new priority of this lock is our own priority */ 233 /* check for a possible priority donation */
232 lock->priority = cur->priority; 234 if (cur->priority > lock->priority)
233 235 {
234 /* the lock priority changed so we need to sort the lock list of the lock holder */ 236 /* the new priority of this lock is our own priority */
235 list_remove (&lock->elem); 237 lock->priority = cur->priority;
236 list_insert_ordered (&lock->holder->locks, &lock->elem, 238
237 lock_priority_cmp_greater, NULL); 239 /* the lock priority changed so we need to sort the lock list of the lock holder */
238 240 list_remove (&lock->elem);
239 /* finally donate our priority */ 241 list_insert_ordered (&lock->holder->locks, &lock->elem,
240 thread_donate_priority (cur, lock->holder); 242 lock_priority_cmp_greater, NULL);
243
244 /* finally donate our priority */
245 thread_donate_priority (cur, lock->holder);
246 }
241 } 247 }
242 }
243 248
244 sema_down (&lock->semaphore); 249 sema_down (&lock->semaphore);
245 lock->holder = cur; 250 lock->holder = cur;
@@ -296,12 +301,12 @@ lock_release (struct lock *lock)
296 /* we don't hold another lock so restore our base priority */ 301 /* we don't hold another lock so restore our base priority */
297 thread_donation_pass_back (); 302 thread_donation_pass_back ();
298 else 303 else
299 { 304 {
300 /* we still hold at least one lock so change our priority to the priority of the lock */ 305 /* we still hold at least one lock so change our priority to the priority of the lock */
301 struct lock *lock2 = list_entry (list_front (&cur->locks), struct lock, elem); 306 struct lock *lock2 = list_entry (list_front (&cur->locks), struct lock, elem);
302 /* (forced) priority change */ 307 /* (forced) priority change */
303 thread_other_set_priority (cur, lock2->priority); 308 thread_other_set_priority (cur, lock2->priority);
304 } 309 }
305} 310}
306 311
307/* Returns true if the current thread holds LOCK, false 312/* Returns true if the current thread holds LOCK, false