diff --git a/.gitignore b/.gitignore index 9546b0d..8d2540f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,12 @@ #ignore pdf files (just keep source files) *.pdf -#ignore shell scripts (only used for testing) -*.sh +#ignore Mac OS generated files +.DS_Store + +#ignore code editor generated directories +.idea +.vscode #ignore junk files from latex output *.out diff --git a/src/threads/synch.c b/src/threads/synch.c index 12fdf11..35fee7c 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -68,8 +68,8 @@ sema_down (struct semaphore *sema) old_level = intr_disable (); while (sema->value == 0) { - list_insert_ordered (&sema->waiters, &thread_current ()->elem, - &thread_priority_greater, NULL); + list_insert_ordered(&sema->waiters, &thread_current ()->elem, + priority_more, NULL); thread_block (); } sema->value--; @@ -114,9 +114,15 @@ sema_up (struct semaphore *sema) ASSERT (sema != NULL); old_level = intr_disable (); - if (!list_empty (&sema->waiters)) - thread_unblock (list_entry (list_pop_front (&sema->waiters), - struct thread, elem)); + + /* Wake up (unblock) the highest priority thread from the waiters list */ + struct thread *t = NULL; + if (!list_empty (&sema->waiters)) + { + t = list_entry (list_pop_front (&sema->waiters), struct thread, elem); + thread_unblock (t); + } + sema->value++; intr_set_level (old_level); thread_yield (); @@ -255,6 +261,54 @@ struct semaphore_elem struct semaphore semaphore; /* This semaphore. */ }; +/* Function that compares the two *semaphores* associated with the provided + list_elem structures. [i.e., takes list_elem of semaphore_elem, and] + Returns true if the thread associated with the semaphore associated with a_ + has a higher priority than that of b_. + + If aux is provided, then it is a pointer to an integer representing the + priority of the first semaphore. This is useful when the thread has not been + sema'd down yet. */ +static bool +sema_priority_more(const struct list_elem *a_, const struct list_elem *b_, + void *aux) +{ + int a_priority, b_priority; + + /* If an aux is provided, then use it as the priority of the first semaphore. + Otherwise, get the priority of the first semaphore. */ + if (aux != NULL) + a_priority = *(int *) aux; + else + { + struct semaphore_elem *a = list_entry(a_, struct semaphore_elem, elem); + + /* If waiters list is empty, return false (i.e., a has lower priority) */ + if (list_empty(&a->semaphore.waiters)) + return false; + + /* Otherwise, get the thread with the highest priority from the waiters + list. By design, this is the first one in the list (See sema_down). */ + struct thread *a_thread = + list_entry(list_front(&a->semaphore.waiters), struct thread, elem); + + a_priority = a_thread->priority; + } + + struct semaphore_elem *b = list_entry(b_, struct semaphore_elem, elem); + + /* If waiters list is empty, return true (i.e., a has higher priority) */ + if (list_empty(&b->semaphore.waiters)) + return true; + + struct thread *b_thread = + list_entry(list_front(&b->semaphore.waiters), struct thread, elem); + + b_priority = b_thread->priority; + + return a_priority > b_priority; +} + /* Initializes condition variable COND. A condition variable allows one piece of code to signal a condition and cooperating code to receive the signal and act upon it. */ @@ -329,9 +383,14 @@ cond_wait (struct condition *cond, struct lock *lock) ASSERT (lock_held_by_current_thread (lock)); sema_init (&waiter.semaphore, 0); - list_insert_ordered (&cond->waiters, &waiter.elem, - singleton_sema_priority_greater, - &thread_current ()->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 3a428f1..fab20bd 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -221,6 +221,10 @@ thread_create (const char *name, int priority, thread_unblock (t); thread_yield (); + /* Yield if the new thread has a higher priority than the current thread. */ + if (priority > thread_get_priority ()) + thread_yield (); + return tid; } @@ -257,7 +261,10 @@ thread_unblock (struct thread *t) old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); - list_insert_ordered (&ready_list, &t->elem, &thread_priority_greater, NULL); + + /* Insert the thread back into the ready list in priority order. */ + list_insert_ordered(&ready_list, &t->elem, priority_more, NULL); + t->status = THREAD_READY; intr_set_level (old_level); } @@ -327,9 +334,11 @@ thread_yield (void) ASSERT (!intr_context ()); old_level = intr_disable (); + + /* Insert the thread back into the ready list in priority order. */ if (cur != idle_thread) - list_insert_ordered (&ready_list, &cur->elem, thread_priority_greater, - NULL); + list_insert_ordered(&ready_list, &cur->elem, priority_more, NULL); + cur->status = THREAD_READY; schedule (); intr_set_level (old_level); @@ -352,6 +361,19 @@ thread_foreach (thread_action_func *func, void *aux) } } +/* Function that compares the two threads associated with the provided + list_elem structures. Returns true if the thread associated with a_ has + a higher priority than that of b_. */ +bool +priority_more (const struct list_elem *a_, const struct list_elem *b_, + void *aux UNUSED) +{ + struct thread *a = list_entry (a_, struct thread, elem); + struct thread *b = list_entry (b_, struct thread, elem); + + return a->priority > b->priority; +} + /* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) diff --git a/src/threads/thread.h b/src/threads/thread.h index 0503af9..a4a2439 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -131,6 +131,8 @@ void thread_yield (void); typedef void thread_action_func (struct thread *t, void *aux); void thread_foreach (thread_action_func *, void *); +bool priority_more (const struct list_elem *a_, const struct list_elem *b_, + void *aux UNUSED); int thread_get_priority (void); void thread_set_priority (int);