diff --git a/src/threads/synch.c b/src/threads/synch.c index 1123249..b99332e 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -194,11 +194,12 @@ lock_init (struct lock *lock) sema_init (&lock->semaphore, 1); } -/* Allows for the donor to donate its priority to donee, iteratively +/* Current thread donates its priority to donee, iteratively propagating the donation in the case of chains in the wait-for graph. Also keeps track of the donation by updating the donors list. */ static void -donate_priority (struct thread *donor, struct thread *donee) { +donate_priority (struct thread *donee) { + struct thread *donor = thread_current (); list_push_back (&donee->donors_list, &donor->donor_elem); while (donee != NULL) @@ -209,17 +210,26 @@ donate_priority (struct thread *donor, struct thread *donee) { if (donor->priority <= donee->priority) break; - donee->priority = donor->priority; - /* Also stop propagation of donation once a donee is reached with no donees of its own (sink node in WFG). */ if (donee->waiting_lock == NULL) - donee = NULL; + { + /* Only the sink node of the WFG isn't waiting for a lock and + could be on the ready list. Thus, as its priority changed, + it must be reinserted into the list. */ + enum intr_level old_level = intr_disable (); + donee->priority = donor->priority; + ready_list_reinsert (donee); + intr_set_level (old_level); + + donee = NULL; + } else - donee = donee->waiting_lock->holder; + { + donee->priority = donor->priority; + donee = donee->waiting_lock->holder; + } } - - ready_list_reorder (); } /* Acquires LOCK, sleeping until it becomes available if @@ -244,7 +254,7 @@ lock_acquire (struct lock *lock) if (lock->holder != NULL) { t->waiting_lock = lock; - donate_priority (t, lock->holder); + donate_priority (lock->holder); } sema_down (&lock->semaphore); diff --git a/src/threads/thread.c b/src/threads/thread.c index ff66100..8731b3b 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -465,10 +465,20 @@ thread_get_recent_cpu (void) return 0; } +/* Reinsert thread t into the ready list at its correct position + in descending order of priority. Used when this thread's priority + may have changed. Must be called with interrupts disabled. */ void -ready_list_reorder (void) +ready_list_reinsert (struct thread *t) { - list_sort (&ready_list, priority_more, NULL); + ASSERT (intr_get_level () == INTR_OFF); + + /* If the thread isn't ready to run, do nothing. */ + if (t->status != THREAD_READY) + return; + + list_remove (&t->elem); + list_insert_ordered (&ready_list, &t->elem, priority_more, NULL); } /* Idle thread. Executes when no other thread is ready to run. @@ -558,7 +568,7 @@ init_thread (struct thread *t, const char *name, int priority) t->stack = (uint8_t *) t + PGSIZE; t->base_priority = priority; t->magic = THREAD_MAGIC; - + list_init (&t->donors_list); t->priority = t->base_priority; t->waiting_lock = NULL; diff --git a/src/threads/thread.h b/src/threads/thread.h index de9df61..ffeb2b3 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -151,6 +151,6 @@ void thread_set_nice (int); int thread_get_recent_cpu (void); int thread_get_load_avg (void); -void ready_list_reorder (void); +void ready_list_reinsert (struct thread *t); #endif /* threads/thread.h */