From 9f71c989a93a45d95524a5853094f3718af604b7 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 07:10:31 +0100 Subject: [PATCH 01/17] Update gitignore to ignore temporary Mac OS files and code editor folders --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 5d8d05c..8d2540f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,13 @@ #ignore pdf files (just keep source files) *.pdf +#ignore Mac OS generated files +.DS_Store + +#ignore code editor generated directories +.idea +.vscode + #ignore junk files from latex output *.out *.log From 83910f945c416d4d11c33f5b9d77c46c6404356b Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 07:26:02 +0100 Subject: [PATCH 02/17] Add priority comparator function for thread list sorting --- src/threads/thread.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 30ca2bd..2d931e2 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -70,6 +70,9 @@ static void *alloc_frame (struct thread *, size_t size); static void schedule (void); void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); +static bool priority_more (const struct list_elem *a_, + const struct list_elem *b_, + void *aux UNUSED) /* Initializes the threading system by transforming the code that's currently running into a thread. This can't work in @@ -350,6 +353,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_. */ +static 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) From 8b3f9e353f5724d345185442ddbfa42aaf2d34a1 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 07:33:24 +0100 Subject: [PATCH 03/17] Update creating thread to yield if the new thread has higher priority --- src/threads/thread.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 2d931e2..96d72be 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -223,6 +223,10 @@ thread_create (const char *name, int priority, /* Add to run queue. */ thread_unblock (t); + /* Yield if the new thread has a higher priority than the current thread. */ + if (priority > thread_get_priority ()) + thread_yield (); + return tid; } From 9bb0b758c819c22467db99260b3ff382c2c6c4d8 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 07:40:41 +0100 Subject: [PATCH 04/17] Fix Error missing semicolon after function signature --- src/threads/thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 96d72be..5bca536 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -72,7 +72,7 @@ void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); static bool priority_more (const struct list_elem *a_, const struct list_elem *b_, - void *aux UNUSED) + void *aux UNUSED); /* Initializes the threading system by transforming the code that's currently running into a thread. This can't work in From 1c53790ca7b8aebbae192668a28cdd4b965bd26f Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 07:58:35 +0100 Subject: [PATCH 05/17] Update set_priority to ensure that the new priority is within bounds --- src/threads/thread.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 5bca536..4ddee22 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -374,6 +374,9 @@ 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); + thread_current ()->priority = new_priority; } From fda79173c092e7eb7537557ae1cd19447dd1462b Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 08:00:50 +0100 Subject: [PATCH 06/17] Update thread_unblock to maintain priority order in ready_list --- src/threads/thread.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 4ddee22..0a66d65 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -263,7 +263,10 @@ thread_unblock (struct thread *t) old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); - list_push_back (&ready_list, &t->elem); + + /* 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); } From 62c8818c05d1d7ee79c35c39be73b0285b543ea1 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 08:18:51 +0100 Subject: [PATCH 07/17] Update thread_yield to add thread back in sorted order of priority --- src/threads/thread.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 0a66d65..e34d23e 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -336,8 +336,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_push_back (&ready_list, &cur->elem); + list_insert_ordered(&ready_list, &cur->elem, priority_more, NULL); + cur->status = THREAD_READY; schedule (); intr_set_level (old_level); From 9f53040d27a33168c2bc43f61a1e5b59253de9f3 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 06:00:34 +0100 Subject: [PATCH 08/17] Update thread_set_priority to not do anything if priority is unchanged --- src/threads/thread.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index e34d23e..f681f92 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -383,6 +383,10 @@ thread_set_priority (int new_priority) ASSERT (new_priority >= PRI_MIN); ASSERT (new_priority <= PRI_MAX); + int old_priority = thread_get_priority (); + if (new_priority == old_priority) + return; + thread_current ()->priority = new_priority; } From 5c09ff0149f937a95cd15d2d18558a27d447a1e5 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 06:27:59 +0100 Subject: [PATCH 09/17] Updated set priority to yield if priority is lowered --- src/threads/thread.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index f681f92..7366641 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -388,6 +388,19 @@ thread_set_priority (int new_priority) return; thread_current ()->priority = new_priority; + + 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(); + } + } } /* Returns the current thread's priority. */ From 949455aae581f6bee62c42365775a216d758d454 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 06:35:39 +0100 Subject: [PATCH 10/17] Update set priority to eliminate race condition when accessing ready list --- src/threads/thread.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 7366641..f364679 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -389,6 +389,8 @@ thread_set_priority (int new_priority) thread_current ()->priority = new_priority; + enum intr_level old_level = intr_disable (); + 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. @@ -401,6 +403,8 @@ thread_set_priority (int new_priority) thread_yield(); } } + + intr_set_level (old_level); } /* Returns the current thread's priority. */ From dbb7fd56e3b42369de23a3954b0007e8094fdd38 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 06:38:27 +0100 Subject: [PATCH 11/17] Update set priority to reorder the list if priority is changed --- src/threads/thread.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index f364679..52d8577 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -391,6 +391,15 @@ thread_set_priority (int 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. From fb268cdef0493b508eaeb44997e29a6da4421b41 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 06:47:58 +0100 Subject: [PATCH 12/17] Update thread make priority_more public --- src/threads/thread.c | 5 +---- src/threads/thread.h | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 52d8577..67d08d1 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -70,9 +70,6 @@ static void *alloc_frame (struct thread *, size_t size); static void schedule (void); void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); -static bool priority_more (const struct list_elem *a_, - const struct list_elem *b_, - void *aux UNUSED); /* Initializes the threading system by transforming the code that's currently running into a thread. This can't work in @@ -366,7 +363,7 @@ 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_. */ -static bool +bool priority_more (const struct list_elem *a_, const struct list_elem *b_, void *aux UNUSED) { diff --git a/src/threads/thread.h b/src/threads/thread.h index f36d7ac..1cde088 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); From 24900545d4718e28ab396562c9bb2c1bfffb428a Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 06:54:10 +0100 Subject: [PATCH 13/17] Update sema_down to insert into waiters list in priority sorted order --- src/threads/synch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 7776cb0..39575ca 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -68,7 +68,8 @@ sema_down (struct semaphore *sema) old_level = intr_disable (); while (sema->value == 0) { - list_push_back (&sema->waiters, &thread_current ()->elem); + list_insert_ordered(&sema->waiters, &thread_current ()->elem, + priority_more, NULL); thread_block (); } sema->value--; From 0d6fb2f1675d1dec50c8618e0751491c06edf939 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 07:15:10 +0100 Subject: [PATCH 14/17] Update sema_up to yield CPU if unblocked has higher priority --- src/threads/synch.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 39575ca..ffdb588 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -114,11 +114,22 @@ 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); + + /* 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 (); } static void sema_test_helper (void *sema_); From 53b296d6c4fab1ac436de6962733f4df7249d950 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 08:36:29 +0100 Subject: [PATCH 15/17] Add function to compare the priority of two semaphores --- src/threads/synch.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index ffdb588..078f142 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -265,6 +265,27 @@ 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_. */ +static bool +sema_priority_more(const struct list_elem *a_, const struct list_elem *b_, + void *aux UNUSED) +{ + struct semaphore_elem *a = list_entry(a_, struct semaphore_elem, elem); + struct semaphore_elem *b = list_entry(b_, struct semaphore_elem, elem); + + /* Get the highest priority thread from the waiters list of each semaphore. By + design, this is the first element in the list (See sema_down). */ + struct thread *a_thread = + list_entry(list_front(&a->semaphore.waiters), struct thread, elem); + struct thread *b_thread = + list_entry(list_front(&b->semaphore.waiters), struct thread, elem); + + return a_thread->priority > b_thread->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. */ From e74ee59e17a220143486a7d7b57f12f52efc761e Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 08:46:14 +0100 Subject: [PATCH 16/17] Update sema priority compare to take aux optionally as priority of first sema --- src/threads/synch.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 078f142..b588656 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -268,22 +268,49 @@ struct semaphore_elem /* 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_. */ + 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 UNUSED) + void *aux) { - struct semaphore_elem *a = list_entry(a_, struct semaphore_elem, elem); + 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); - /* Get the highest priority thread from the waiters list of each semaphore. By - design, this is the first element in the list (See sema_down). */ - struct thread *a_thread = - list_entry(list_front(&a->semaphore.waiters), struct thread, 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); - return a_thread->priority > b_thread->priority; + b_priority = b_thread->priority; + + return a_priority > b_priority; } /* Initializes condition variable COND. A condition variable From 88967acdaa49de4b71294cce988687f06c192e19 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 08:53:53 +0100 Subject: [PATCH 17/17] Update cond_wait to insert into waiters list in sorted order of priority --- src/threads/synch.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index b588656..2431494 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -355,7 +355,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);