diff --git a/src/threads/synch.c b/src/threads/synch.c index b588656..35fee7c 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -125,11 +125,7 @@ sema_up (struct semaphore *sema) sema->value++; intr_set_level (old_level); - - /* If the unblocked thread has higher priority than the current running thread - then yield the CPU to the unblocked thread */ - if (!intr_context() && t != NULL && t->priority > thread_get_priority ()) - thread_yield (); + thread_yield (); } static void sema_test_helper (void *sema_); @@ -324,6 +320,38 @@ cond_init (struct condition *cond) list_init (&cond->waiters); } +/* Returns true iff the priority of the only thread in the first singleton + semaphore is greater than the priority of the only thread in the second + singleton semaphore. + + Where this function is used for insertion in a singleton semaphore list, the + third argument may specify a list_elem * to assume corresponds to the thread + waiting for the inserting semaphore. For correctness, ensure this thread + calls sema_down () for this semaphore before future list accesses. */ + +static bool +singleton_sema_priority_greater (const struct list_elem *a, + const struct list_elem *b, + void *insertingThread) +{ + struct list_elem *te_a, *te_b; + + te_b = list_front ( + &list_entry (b, struct semaphore_elem, elem)->semaphore.waiters); + + if (insertingThread == NULL) + { + te_a = list_front ( + &list_entry (a, struct semaphore_elem, elem)->semaphore.waiters); + } + else + { + te_a = insertingThread; + } + + return thread_priority_greater (te_a, te_b, NULL); +} + /* Atomically releases LOCK and waits for COND to be signaled by some other piece of code. After COND is signaled, LOCK is reacquired before returning. LOCK must be held before calling @@ -355,7 +383,14 @@ cond_wait (struct condition *cond, struct lock *lock) ASSERT (lock_held_by_current_thread (lock)); sema_init (&waiter.semaphore, 0); - list_push_back (&cond->waiters, &waiter.elem); + + /* Insert the semaphore_elem into the waiters list in order of priority. + We pass the priority of the current thread as aux to sema_priority_more + because the thread has not been sema'd down yet (See sema_priority_more) */ + int priority = thread_current ()->priority; + list_insert_ordered (&cond->waiters, &waiter.elem, sema_priority_more, + &priority); + lock_release (lock); sema_down (&waiter.semaphore); lock_acquire (lock); diff --git a/src/threads/thread.c b/src/threads/thread.c index 67d08d1..fab20bd 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -219,6 +219,7 @@ thread_create (const char *name, int priority, /* Add to run queue. */ thread_unblock (t); + thread_yield (); /* Yield if the new thread has a higher priority than the current thread. */ if (priority > thread_get_priority ()) @@ -377,40 +378,12 @@ priority_more (const struct list_elem *a_, const struct list_elem *b_, void thread_set_priority (int new_priority) { - ASSERT (new_priority >= PRI_MIN); - ASSERT (new_priority <= PRI_MAX); - + ASSERT (PRI_MIN <= new_priority && new_priority <= PRI_MAX); int old_priority = thread_get_priority (); - if (new_priority == old_priority) - return; thread_current ()->priority = new_priority; - - enum intr_level old_level = intr_disable (); - - /* If the thread is in the ready list, the list must be reordered to maintain - the priority order. */ - if (thread_current ()->status == THREAD_READY) { - /* Remove from the ready list and reinsert it in priority order. */ - list_remove (&thread_current ()->elem); - list_insert_ordered (&ready_list, &thread_current ()->elem, priority_more, - NULL); - } - - if (new_priority < old_priority && !list_empty (&ready_list)) { - /* If the new priority is lower than the old priority, check if the current - thread no longer has the highest priority. If it doesn't, yield the CPU. - */ - - struct thread *next_thread = - list_entry (list_front (&ready_list), struct thread, elem); - - if (next_thread->priority > new_priority) { - thread_yield(); - } - } - - intr_set_level (old_level); + if (new_priority < old_priority) + thread_yield (); } /* Returns the current thread's priority. */ @@ -654,6 +627,17 @@ allocate_tid (void) return tid; } +/* Returns true iff the priority of the first list element's thread is greater + than that of the second list element's thread. */ +bool +thread_priority_greater (const struct list_elem *a, const struct list_elem *b, + void *aux UNUSED) +{ + struct thread *ta = list_entry (a, struct thread, elem); + struct thread *tb = list_entry (b, struct thread, elem); + return ta->priority > tb->priority; +} + /* Offset of `stack' member within `struct thread'. Used by switch.S, which can't figure it out on its own. */ uint32_t thread_stack_ofs = offsetof (struct thread, stack); diff --git a/src/threads/thread.h b/src/threads/thread.h index 1cde088..a4a2439 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -141,4 +141,7 @@ void thread_set_nice (int); int thread_get_recent_cpu (void); int thread_get_load_avg (void); +/* Returns true iff the priority of the first list element's thread is greater + than that of the second list element's thread. */ +list_less_func thread_priority_greater; #endif /* threads/thread.h */