From 4ed64cf173966d447b9851717a0013bd122d242c Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 10:47:38 +0100 Subject: [PATCH 01/64] Add guard in thread_set_priority ensuring priority values are within correct range --- src/threads/thread.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 30ca2bd..ed305ad 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -354,6 +354,7 @@ thread_foreach (thread_action_func *func, void *aux) void thread_set_priority (int new_priority) { + ASSERT (PRI_MIN <= new_priority && new_priority <= PRI_MAX); thread_current ()->priority = new_priority; } From 1821d73b09616e61e5d8344db49ad42b7492723d Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 11:50:04 +0100 Subject: [PATCH 02/64] Add comparison function for thread list elements based on thread priority --- src/threads/thread.c | 11 +++++++++++ src/threads/thread.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index ed305ad..8e18ca9 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -599,6 +599,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) +{ + 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 f36d7ac..0503af9 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -139,4 +139,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 */ From f1fa7d2ffbfba3a562f60542171bed75d85fc2a0 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 11:51:40 +0100 Subject: [PATCH 03/64] Reformat thread_priority_greater to fit code style --- 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 8e18ca9..dfc70df 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -603,7 +603,7 @@ allocate_tid (void) 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) + void *aux) { struct thread *ta = list_entry (a, struct thread, elem); struct thread *tb = list_entry (b, struct thread, elem); From d4d5a7a937ecefa53915e6c82538d73fa015123f Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 12:01:03 +0100 Subject: [PATCH 04/64] Update thread_priority_greater function signature to explicitly signal unused parameter --- 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 dfc70df..146a430 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -603,7 +603,7 @@ allocate_tid (void) 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) + void *aux UNUSED) { struct thread *ta = list_entry (a, struct thread, elem); struct thread *tb = list_entry (b, struct thread, elem); From 79061fcb9b45219af33d2439fc91af9a5a10d463 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 13:51:41 +0100 Subject: [PATCH 05/64] Update thread module to maintain list of ready threads in descending order of priority --- src/threads/thread.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 146a430..709fcef 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -256,7 +256,7 @@ thread_unblock (struct thread *t) old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); - list_push_back (&ready_list, &t->elem); + list_insert_ordered (&ready_list, &t->elem, &thread_priority_greater, NULL); t->status = THREAD_READY; intr_set_level (old_level); } @@ -327,7 +327,8 @@ thread_yield (void) old_level = intr_disable (); if (cur != idle_thread) - list_push_back (&ready_list, &cur->elem); + list_insert_ordered (&ready_list, &cur->elem, thread_priority_greater, + NULL); cur->status = THREAD_READY; schedule (); intr_set_level (old_level); From 6855a48603ac6a53b4b55d390f49b396f6623013 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 13:53:48 +0100 Subject: [PATCH 06/64] Update semaphore code to wake highest priority thread, and run if required --- src/threads/synch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 7776cb0..e1bcf9f 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, + &thread_priority_greater, NULL); thread_block (); } sema->value--; @@ -118,6 +119,7 @@ sema_up (struct semaphore *sema) struct thread, elem)); sema->value++; intr_set_level (old_level); + thread_yield (); } static void sema_test_helper (void *sema_); From 54b46806babf9412e8c5b22d9fb28cd7ccc868ca Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 15:12:01 +0100 Subject: [PATCH 07/64] Update thread creation to yield thread in case it's no longer the highest priority --- src/threads/thread.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 709fcef..6b48788 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 (); return tid; } From 3c1a26b668c38b8a205194f2c52d47b57e7d9f5a Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 15:14:05 +0100 Subject: [PATCH 08/64] Update setting of thread priorities to yield in case a higher priority thread requires control --- src/threads/thread.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 6b48788..6c1dcca 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -358,6 +358,7 @@ thread_set_priority (int new_priority) { ASSERT (PRI_MIN <= new_priority && new_priority <= PRI_MAX); thread_current ()->priority = new_priority; + thread_yield (); } /* Returns the current thread's priority. */ From 163b7f9016162f976090c172f9dba655b0f54aaa Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 15:38:31 +0100 Subject: [PATCH 09/64] Update setting of priority of threads to only yield when current thread's priority has been lowered --- 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 6c1dcca..3a428f1 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -357,8 +357,11 @@ void thread_set_priority (int new_priority) { ASSERT (PRI_MIN <= new_priority && new_priority <= PRI_MAX); + int old_priority = thread_get_priority (); + thread_current ()->priority = new_priority; - thread_yield (); + if (new_priority < old_priority) + thread_yield (); } /* Returns the current thread's priority. */ From c32a69a368e6539c5791d3d69e0bb088ff41d237 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 15 Oct 2024 17:00:02 +0100 Subject: [PATCH 10/64] Update repository settings to ignore shell scripts --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5d8d05c..9546b0d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ #ignore pdf files (just keep source files) *.pdf +#ignore shell scripts (only used for testing) +*.sh + #ignore junk files from latex output *.out *.log From 9f71c989a93a45d95524a5853094f3718af604b7 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 16 Oct 2024 07:10:31 +0100 Subject: [PATCH 11/64] 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 12/64] 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 13/64] 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 14/64] 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 15/64] 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 16/64] 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 17/64] 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 18/64] 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 19/64] 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 20/64] 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 21/64] 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 22/64] 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 23/64] 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 24/64] 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 25/64] 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 26/64] 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 27/64] 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); From 711efdc78ab1960074a5e0283b900861d21fc590 Mon Sep 17 00:00:00 2001 From: Themis Date: Thu, 17 Oct 2024 19:43:35 +0100 Subject: [PATCH 28/64] Implement priority scheduling for condition variables --- src/threads/synch.c | 47 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 387f060..374817f 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -265,43 +265,25 @@ struct semaphore_elem 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) +sema_priority_more(const struct list_elem *a, const struct list_elem *b, + void *inserting_telem) { - int a_priority, b_priority; + struct list_elem *te_a, *te_b; + + te_b = list_front ( + &list_entry (b, struct semaphore_elem, elem)->semaphore.waiters); - /* 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; + if (inserting_telem == NULL) + { + te_a = list_front ( + &list_entry (a, struct semaphore_elem, elem)->semaphore.waiters); + } 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; + te_a = inserting_telem; } - 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; + return priority_more (te_a, te_b, NULL); } /* Initializes condition variable COND. A condition variable @@ -346,7 +328,8 @@ 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); + list_insert_ordered (&cond->waiters, &waiter.elem, sema_priority_more, + &thread_current ()->elem); lock_release (lock); sema_down (&waiter.semaphore); lock_acquire (lock); From bfdedc53e263fc0b80b86c587bad053f5c5cd38c Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 17 Oct 2024 19:46:10 +0100 Subject: [PATCH 29/64] Update set priority so not to yield if no ready threads --- 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 e587626..3e5d15c 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -383,7 +383,7 @@ thread_set_priority (int new_priority) thread_current ()->priority = new_priority; - if (new_priority < old_priority) + if (new_priority < old_priority && !list_empty (&ready_list)) thread_yield (); } From 6b9b671368faeb19e4fab0bd0b3e3c66e782727d Mon Sep 17 00:00:00 2001 From: Themis Date: Thu, 17 Oct 2024 20:01:39 +0100 Subject: [PATCH 30/64] Update sema_up to properly yield during execution of an interrupt handler --- src/threads/synch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 374817f..d773824 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -120,7 +120,10 @@ sema_up (struct semaphore *sema) sema->value++; intr_set_level (old_level); - thread_yield (); + if (intr_context ()) + intr_yield_on_return (); + else + thread_yield (); } static void sema_test_helper (void *sema_); From 8b1e0b9559164cc198d26b7745805bb836db68bf Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 20 Oct 2024 17:04:14 +0100 Subject: [PATCH 31/64] Add donation-related information to the thread structure, w/ T --- src/threads/thread.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/threads/thread.h b/src/threads/thread.h index a4a2439..4e719a7 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -90,6 +90,15 @@ struct thread int priority; /* Priority. */ struct list_elem allelem; /* List element for all threads list. */ + /* Donation Related */ + int base_priority; /* Base priority of the thread. */ + struct list donors_list; /* List of threads that have donated + to this thread. */ + struct lock *waiting_lock; /* The lock that the current thread is + waiting for. */ + struct list_elem donor_elem; /* List element so that thread can be + enlisted in other donors list. */ + /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ From fcc8cbb71e9a05b0b3a0561d5ef80e7420e82587 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 17:11:44 +0100 Subject: [PATCH 32/64] Implement initialization of new threads to track donation information, w/ S --- src/threads/thread.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 3e5d15c..3fcfe1e 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -510,9 +510,13 @@ init_thread (struct thread *t, const char *name, int priority) t->status = THREAD_BLOCKED; strlcpy (t->name, name, sizeof t->name); t->stack = (uint8_t *) t + PGSIZE; - t->priority = priority; + t->base_priority = priority; t->magic = THREAD_MAGIC; + list_init (&t->donors_list); + t->priority = t->base_priority; + t->waiting_lock = NULL; + old_level = intr_disable (); list_push_back (&all_list, &t->allelem); intr_set_level (old_level); From 5a651f12794dc5fb04febe6ccc21159656a154fe Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 20 Oct 2024 18:06:07 +0100 Subject: [PATCH 33/64] Update implementation of thread set priority to account for donations, w/ T --- src/threads/thread.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 3fcfe1e..d65d7c4 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -370,21 +370,35 @@ priority_more (const struct list_elem *a_, const struct list_elem *b_, return a->priority > b->priority; } -/* Sets the current thread's priority to NEW_PRIORITY. */ +/* Sets the current thread's base priority to new_base_priority. + Updates the current thread's effective priority if necessary. */ void -thread_set_priority (int new_priority) +thread_set_priority (int new_base_priority) { - ASSERT (new_priority >= PRI_MIN); - ASSERT (new_priority <= PRI_MAX); + ASSERT (new_base_priority >= PRI_MIN); + ASSERT (new_base_priority <= PRI_MAX); + struct thread *t = thread_current (); + + int old_base_priority = t->base_priority; int old_priority = thread_get_priority (); - if (new_priority == old_priority) + if (new_base_priority == old_base_priority) return; - thread_current ()->priority = new_priority; - if (new_priority < old_priority && !list_empty (&ready_list)) - thread_yield (); + t->base_priority = new_base_priority; + t->priority = new_base_priority; + + if (!list_empty (&t->donors_list) && new_base_priority < old_priority) { + int max_donated_priority = + list_entry (list_max (&t->donors_list, priority_more, NULL), + struct thread, donor_elem)->priority; + + if(new_base_priority < max_donated_priority) + t->priority = new_base_priority; + } + + thread_yield (); } /* Returns the current thread's priority. */ From f98e4bc81c70ee4e0ec90536d9f02329ff702210 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 19:19:43 +0100 Subject: [PATCH 34/64] Update lock_acquire to attempt donation of priorities, w/ S --- src/threads/synch.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index d773824..4bf54a6 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -187,6 +187,9 @@ lock_init (struct lock *lock) sema_init (&lock->semaphore, 1); } +static void +donate_priority (struct thread *donor, struct thread *donee); + /* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. @@ -202,8 +205,18 @@ lock_acquire (struct lock *lock) ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); + struct thread *t = thread_current (); + + /* TODO: If a high-priority thread holding a lock sleeps, this may cause a + race condition here or break the assumption that donation must occur. */ + if (lock->holder != NULL) + { + t->waiting_lock = lock; + } + sema_down (&lock->semaphore); lock->holder = thread_current (); + t->waiting_lock = NULL; } /* Tries to acquires LOCK and returns true if successful or false From 343ac55d372f6f6d93c2c7e6a96d46e2ae889a44 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 20 Oct 2024 19:42:35 +0100 Subject: [PATCH 35/64] Implement priority donation helper function with propagation, w/ T --- src/threads/synch.c | 16 +++++++++++++++- src/threads/thread.c | 6 ++++++ src/threads/thread.h | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 4bf54a6..3495ca8 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -188,7 +188,21 @@ lock_init (struct lock *lock) } static void -donate_priority (struct thread *donor, struct thread *donee); +donate_priority (struct thread *donor, struct thread *donee) { + while (donee != NULL) + { + if (donor->priority <= donee->priority) + break; + + donee->priority = donor->priority; + if (donee->waiting_lock == NULL) + donee = NULL; + else + donee = donee->waiting_lock->holder; + } + + ready_list_reorder (); +} /* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current diff --git a/src/threads/thread.c b/src/threads/thread.c index d65d7c4..b7bab5b 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -439,6 +439,12 @@ thread_get_recent_cpu (void) return 0; } +void +ready_list_reorder (void) +{ + list_sort (&ready_list, priority_more, NULL); +} + /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by diff --git a/src/threads/thread.h b/src/threads/thread.h index 4e719a7..083a5ab 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -150,6 +150,8 @@ void thread_set_nice (int); int thread_get_recent_cpu (void); int thread_get_load_avg (void); +void ready_list_reorder (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; From ee0cf632b9018b021c9393b5474a5232948bb2e4 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 19:45:05 +0100 Subject: [PATCH 36/64] Fix attempt to donate priority within lock acquisition w/ S --- src/threads/synch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index 3495ca8..6d71c83 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -226,6 +226,7 @@ lock_acquire (struct lock *lock) if (lock->holder != NULL) { t->waiting_lock = lock; + donate_priority (t, lock->holder); } sema_down (&lock->semaphore); From 8e20884a23c857f18e756b2b19445c196919091c Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 20:17:27 +0100 Subject: [PATCH 37/64] Update releasing of locks to update donation information w/ S --- src/threads/synch.c | 12 ++++++++++++ src/threads/thread.c | 7 +++++++ src/threads/thread.h | 1 + 3 files changed, 20 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index 6d71c83..027018e 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -265,6 +265,18 @@ lock_release (struct lock *lock) ASSERT (lock != NULL); ASSERT (lock_held_by_current_thread (lock)); + struct thread *current_thread = thread_current (); + struct list_elem *tail = list_tail (¤t_thread->donors_list); + for (struct list_elem *e = list_begin (¤t_thread->donors_list); + e != tail; e = e->next) + { + struct thread *donor = list_entry (e, struct thread, donor_elem); + if (donor->waiting_lock == lock) + list_remove (e); + } + + thread_recalculate_priority (); + lock->holder = NULL; sema_up (&lock->semaphore); } diff --git a/src/threads/thread.c b/src/threads/thread.c index b7bab5b..ed717e3 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -408,6 +408,13 @@ thread_get_priority (void) return thread_current ()->priority; } +/* Recalculates the effective priority of the current thread. */ +void +thread_recalculate_priority (void) +{ + barrier (); +}; + /* Sets the current thread's nice value to NICE. */ void thread_set_nice (int nice UNUSED) diff --git a/src/threads/thread.h b/src/threads/thread.h index 083a5ab..b3c1006 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -144,6 +144,7 @@ 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); +void thread_recalculate_priority (void); int thread_get_nice (void); void thread_set_nice (int); From b1dba1a0bd522c2c7ec35eaa184fcae78b35d683 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 20 Oct 2024 20:37:03 +0100 Subject: [PATCH 38/64] Add implementation for recalculate effective priority, w/ T --- src/threads/thread.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index ed717e3..1f2d273 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -389,14 +389,8 @@ thread_set_priority (int new_base_priority) t->base_priority = new_base_priority; t->priority = new_base_priority; - if (!list_empty (&t->donors_list) && new_base_priority < old_priority) { - int max_donated_priority = - list_entry (list_max (&t->donors_list, priority_more, NULL), - struct thread, donor_elem)->priority; - - if(new_base_priority < max_donated_priority) - t->priority = new_base_priority; - } + if (new_base_priority < old_priority) + thread_recalculate_priority (); thread_yield (); } @@ -412,8 +406,17 @@ thread_get_priority (void) void thread_recalculate_priority (void) { - barrier (); -}; + struct thread *t = thread_current (); + + if (!list_empty (&t->donors_list)) { + int max_donated_priority = + list_entry (list_max (&t->donors_list, priority_more, NULL), + struct thread, donor_elem)->priority; + + if(max_donated_priority > t->priority) + t->priority = max_donated_priority; + } +} /* Sets the current thread's nice value to NICE. */ void From afcb12cef0b48755118a61fee0f706c5058b7a0d Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 20:38:28 +0100 Subject: [PATCH 39/64] Reformat thread priority changing functions to follow style w/ S --- src/threads/thread.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 1f2d273..d85e05a 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -385,7 +385,6 @@ thread_set_priority (int new_base_priority) if (new_base_priority == old_base_priority) return; - t->base_priority = new_base_priority; t->priority = new_base_priority; @@ -413,7 +412,7 @@ thread_recalculate_priority (void) list_entry (list_max (&t->donors_list, priority_more, NULL), struct thread, donor_elem)->priority; - if(max_donated_priority > t->priority) + if (max_donated_priority > t->priority) t->priority = max_donated_priority; } } From 44de31c0ff26b83d88369e4005e79e8e7e717b7c Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 20 Oct 2024 20:54:48 +0100 Subject: [PATCH 40/64] Fix Bug in Implementation of recalculate priority setting base priority, w/ T --- src/threads/thread.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index d85e05a..b626a96 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -386,10 +386,7 @@ thread_set_priority (int new_base_priority) return; t->base_priority = new_base_priority; - t->priority = new_base_priority; - - if (new_base_priority < old_priority) - thread_recalculate_priority (); + thread_recalculate_priority (); thread_yield (); } @@ -406,6 +403,7 @@ void thread_recalculate_priority (void) { struct thread *t = thread_current (); + t->priority = t->base_priority; if (!list_empty (&t->donors_list)) { int max_donated_priority = From 7f7b1648cd6d31a5c032b6cedbbfc8748b296bcb Mon Sep 17 00:00:00 2001 From: sBubshait Date: Sun, 20 Oct 2024 22:28:29 +0100 Subject: [PATCH 41/64] Fix indentation in recalculate priority to match pintos style, w/ T --- src/threads/thread.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index b626a96..f937aca 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -405,14 +405,15 @@ thread_recalculate_priority (void) struct thread *t = thread_current (); t->priority = t->base_priority; - if (!list_empty (&t->donors_list)) { - int max_donated_priority = - list_entry (list_max (&t->donors_list, priority_more, NULL), - struct thread, donor_elem)->priority; + if (!list_empty (&t->donors_list)) + { + int max_donated_priority = + list_entry (list_max (&t->donors_list, priority_more, NULL), + struct thread, donor_elem)->priority; - if (max_donated_priority > t->priority) - t->priority = max_donated_priority; - } + if (max_donated_priority > t->priority) + t->priority = max_donated_priority; + } } /* Sets the current thread's nice value to NICE. */ From 840df8af78bc6e343cf69fb0866d110fefcda26b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 22:29:20 +0100 Subject: [PATCH 42/64] Fix bug in donate_priority that wouldn't update the list of donors w/ S --- src/threads/synch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index 027018e..cdfb2dc 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -189,6 +189,8 @@ lock_init (struct lock *lock) static void donate_priority (struct thread *donor, struct thread *donee) { + list_push_back (&donee->donors_list, &donor->donor_elem); + while (donee != NULL) { if (donor->priority <= donee->priority) From dae5b0d097f6424867ecfde3a6a5a3f38f740c36 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Sun, 20 Oct 2024 22:50:31 +0100 Subject: [PATCH 43/64] Update semaphore priority scheduling to use linear search on unordered list w/ S --- src/threads/synch.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index cdfb2dc..b74303d 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -68,8 +68,7 @@ sema_down (struct semaphore *sema) old_level = intr_disable (); while (sema->value == 0) { - list_insert_ordered(&sema->waiters, &thread_current ()->elem, - priority_more, NULL); + list_push_back (&sema->waiters, &thread_current ()->elem); thread_block (); } sema->value--; @@ -114,9 +113,12 @@ 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)); + if (!list_empty (&sema->waiters)) + { + struct list_elem *e = list_min (&sema->waiters, priority_more, NULL); + list_remove (e); + thread_unblock (list_entry (e, struct thread, elem)); + } sema->value++; intr_set_level (old_level); From f10514f4cc8b8aa810a25472ec1c74859a6bafdf Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 18:59:19 +0100 Subject: [PATCH 44/64] Update priority_more comment description to specify which list_elem member it is compatible with --- src/threads/thread.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index f937aca..ff5686e 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -358,8 +358,8 @@ 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_. */ + pointers to their 'elem' member. 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) From a19d40bcca62abe891e3f18b9de9c02aad097c41 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 19:01:55 +0100 Subject: [PATCH 45/64] Reformat priority_more to obey code style --- 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 ff5686e..379c6d7 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -362,7 +362,7 @@ thread_foreach (thread_action_func *func, void *aux) 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) + void *aux UNUSED) { struct thread *a = list_entry (a_, struct thread, elem); struct thread *b = list_entry (b_, struct thread, elem); From d9b957263140170fb38b41d8dccd35e593ce2711 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Oct 2024 19:49:53 +0100 Subject: [PATCH 46/64] Fix Bug in recalculating priority, uses 'elem' instead of 'donor_elem', w/ T --- src/threads/thread.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 379c6d7..c4722a9 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -70,6 +70,8 @@ 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 donor_priority_less (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 @@ -370,6 +372,19 @@ priority_more (const struct list_elem *a_, const struct list_elem *b_, return a->priority > b->priority; } +/* Function that compares the two threads associated with the provided + pointers to their 'donor_elem' member. Returns true if the thread associated + with a_ has a lower priority than that of b_. */ +static bool +donor_priority_less (const struct list_elem *a_, const struct list_elem *b_, + void *aux UNUSED) +{ + struct thread *a = list_entry (a_, struct thread, donor_elem); + struct thread *b = list_entry (b_, struct thread, donor_elem); + + return a->priority < b->priority; +} + /* Sets the current thread's base priority to new_base_priority. Updates the current thread's effective priority if necessary. */ void @@ -408,7 +423,7 @@ thread_recalculate_priority (void) if (!list_empty (&t->donors_list)) { int max_donated_priority = - list_entry (list_max (&t->donors_list, priority_more, NULL), + list_entry (list_max (&t->donors_list, donor_priority_less, NULL), struct thread, donor_elem)->priority; if (max_donated_priority > t->priority) From 21cbfc9fe0dfa22f20380f2258b0031cbfc2065a Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 20:06:21 +0100 Subject: [PATCH 47/64] Implement transfer of orphaned donors when releasing lock w/ S --- src/threads/synch.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index b74303d..4ec2266 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -270,15 +270,53 @@ lock_release (struct lock *lock) ASSERT (lock_held_by_current_thread (lock)); struct thread *current_thread = thread_current (); + struct thread *max_donor = NULL; + + struct list orphan_list; + list_init (&orphan_list); + + /* Loop through current thread's donors, removing the ones waiting for the + lock being released and keeping track of them (within orphan_list). + Also identifies the highest priority donor thread among them. */ struct list_elem *tail = list_tail (¤t_thread->donors_list); - for (struct list_elem *e = list_begin (¤t_thread->donors_list); - e != tail; e = e->next) + struct list_elem *e = list_begin (¤t_thread->donors_list); + while (e != tail) { struct thread *donor = list_entry (e, struct thread, donor_elem); + struct list_elem *next = list_next (e); + + /* Excludes donors that aren't waiting for the lock being released, + and tracks the rest. */ if (donor->waiting_lock == lock) + { list_remove (e); + list_push_back (&orphan_list, e); + + /* Identify highest priority donor. */ + if (max_donor == NULL || donor->priority > max_donor->priority) + max_donor = donor; + } + + e = next; } + /* If there exists a maximum donor thread waiting for this lock to be + released, transfer the remaining orphaned donors to its donor list. */ + if (max_donor != NULL) + { + tail = list_tail (&orphan_list); + e = list_begin (&orphan_list); + while (e != tail) + { + struct list_elem *next = list_next (e); + list_push_back (&max_donor->donors_list, e); + + e = next; + } + } + + /* Removal of donors to this thread may change its effective priority, + so recalculate. */ thread_recalculate_priority (); lock->holder = NULL; From 244db41434d6f627bb471188f95bfbe278d57145 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Oct 2024 20:25:13 +0100 Subject: [PATCH 48/64] Update condvar to use linear search due to changes in priority from donations, w/ T --- src/threads/synch.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 4ec2266..73dceba 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -413,8 +413,7 @@ 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, sema_priority_more, - &thread_current ()->elem); + list_push_back (&cond->waiters, &waiter.elem); lock_release (lock); sema_down (&waiter.semaphore); lock_acquire (lock); @@ -435,9 +434,13 @@ cond_signal (struct condition *cond, struct lock *lock UNUSED) ASSERT (!intr_context ()); ASSERT (lock_held_by_current_thread (lock)); - if (!list_empty (&cond->waiters)) - sema_up (&list_entry (list_pop_front (&cond->waiters), - struct semaphore_elem, elem)->semaphore); + if (!list_empty (&cond->waiters)) + { + struct list_elem *e = list_min (&cond->waiters, sema_priority_more, NULL); + list_remove (e); + sema_up (&list_entry (e, struct semaphore_elem, elem)->semaphore); + } + } /* Wakes up all threads, if any, waiting on COND (protected by From fc1691f9945990826d73f043d06b784cddb6a8d8 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 20:36:28 +0100 Subject: [PATCH 49/64] Refactor thread.h to remove superfluous thread priority comparison function w/ S --- src/threads/thread.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/threads/thread.h b/src/threads/thread.h index b3c1006..de9df61 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -153,7 +153,4 @@ int thread_get_load_avg (void); void ready_list_reorder (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 */ From 6983ccdd3b2161426590e6b3d92d7a670b609235 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 20:41:44 +0100 Subject: [PATCH 50/64] Update thread_get_priority description comment to be more specific w/ S --- 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 c4722a9..1cf40af 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -406,7 +406,7 @@ thread_set_priority (int new_base_priority) thread_yield (); } -/* Returns the current thread's priority. */ +/* Returns the current thread's effective priority. */ int thread_get_priority (void) { From bf6104200ce5539d34257c9b74fe7c7982fd63aa Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Oct 2024 20:47:34 +0100 Subject: [PATCH 51/64] Refactor thread set priority to remove unused variable and add comment, w/ T --- src/threads/thread.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index 1cf40af..79dd339 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -395,9 +395,8 @@ thread_set_priority (int new_base_priority) struct thread *t = thread_current (); - int old_base_priority = t->base_priority; - int old_priority = thread_get_priority (); - if (new_base_priority == old_base_priority) + /* If the base priority is unchanged, do nothing. */ + if (new_base_priority == t->base_priority) return; t->base_priority = new_base_priority; From 5549b9c0cb73d2c652566f737674e23bd61d5f44 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Oct 2024 20:52:52 +0100 Subject: [PATCH 52/64] Refactor thread recalculate priority to add comments for clarity, w/ T --- src/threads/thread.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 79dd339..ff66100 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -419,12 +419,16 @@ thread_recalculate_priority (void) struct thread *t = thread_current (); t->priority = t->base_priority; + /* If there are no donors to the current thread, then the effective + priority is just the base priority. */ if (!list_empty (&t->donors_list)) { int max_donated_priority = list_entry (list_max (&t->donors_list, donor_priority_less, NULL), struct thread, donor_elem)->priority; + /* The effective priority is the max donated priority if this is + higher than the base priority. */ if (max_donated_priority > t->priority) t->priority = max_donated_priority; } From 48104b3a410862b4a942d6c1e2e089988b52b247 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 20:57:18 +0100 Subject: [PATCH 53/64] Refactor cond_signal to add comment clarifying the logic w/ S --- 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 73dceba..655e014 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -436,11 +436,12 @@ cond_signal (struct condition *cond, struct lock *lock UNUSED) if (!list_empty (&cond->waiters)) { + /* Enforce wake-up of highest priority thread within the singleton + semaphores waiting for condvar. */ struct list_elem *e = list_min (&cond->waiters, sema_priority_more, NULL); list_remove (e); sema_up (&list_entry (e, struct semaphore_elem, elem)->semaphore); } - } /* Wakes up all threads, if any, waiting on COND (protected by From 78c6fd36e3db13cbb2db8586d69636ddff09a727 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Oct 2024 21:04:14 +0100 Subject: [PATCH 54/64] Refactor sema_up to add comments for clarity, w/ T --- src/threads/synch.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 655e014..9900748 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -106,7 +106,7 @@ sema_try_down (struct semaphore *sema) This function may be called from an interrupt handler. */ void -sema_up (struct semaphore *sema) +sema_up (struct semaphore *sema) { enum intr_level old_level; @@ -114,14 +114,19 @@ sema_up (struct semaphore *sema) old_level = intr_disable (); if (!list_empty (&sema->waiters)) - { - struct list_elem *e = list_min (&sema->waiters, priority_more, NULL); - list_remove (e); - thread_unblock (list_entry (e, struct thread, elem)); - } + { + /* Enforces wake-up of the highest priority thread waiting for the + semaphore. */ + struct list_elem *e = list_min (&sema->waiters, priority_more, NULL); + list_remove (e); + thread_unblock (list_entry (e, struct thread, elem)); + } sema->value++; intr_set_level (old_level); + /* Yields the CPU in case the thread that has been woken up has a higher + priority that the current running thread, including the case when called + within an interrupt handler. */ if (intr_context ()) intr_yield_on_return (); else From 7aec2e6862d74a7e864063d504097e3c278f1fea Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Tue, 22 Oct 2024 21:15:30 +0100 Subject: [PATCH 55/64] Refactor donate_priority to include comments explaining its purpose and logic w/ S --- src/threads/synch.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index 9900748..3dc15cd 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -194,16 +194,25 @@ lock_init (struct lock *lock) sema_init (&lock->semaphore, 1); } +/* Allows for the donor to donate 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) { list_push_back (&donee->donors_list, &donor->donor_elem); while (donee != NULL) { + /* Stop propagation of donation once a donee is reached that has + a higher effective priority (as its donees can't have less + priority than that being donated). */ 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; else From d82176a2e25013281e949abd949849959440c2c2 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Tue, 22 Oct 2024 22:52:29 +0100 Subject: [PATCH 56/64] Refactor lock release to follow PintOS indent style and use list functoins, w/ T --- src/threads/synch.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 3dc15cd..1123249 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -302,14 +302,14 @@ lock_release (struct lock *lock) /* Excludes donors that aren't waiting for the lock being released, and tracks the rest. */ if (donor->waiting_lock == lock) - { - list_remove (e); - list_push_back (&orphan_list, e); + { + list_remove (e); + list_push_back (&orphan_list, e); - /* Identify highest priority donor. */ - if (max_donor == NULL || donor->priority > max_donor->priority) - max_donor = donor; - } + /* Identify highest priority donor. */ + if (max_donor == NULL || donor->priority > max_donor->priority) + max_donor = donor; + } e = next; } @@ -317,17 +317,10 @@ lock_release (struct lock *lock) /* If there exists a maximum donor thread waiting for this lock to be released, transfer the remaining orphaned donors to its donor list. */ if (max_donor != NULL) - { - tail = list_tail (&orphan_list); - e = list_begin (&orphan_list); - while (e != tail) - { - struct list_elem *next = list_next (e); - list_push_back (&max_donor->donors_list, e); - - e = next; - } - } + { + while (!list_empty (&orphan_list)) + list_push_back (&max_donor->donors_list, list_pop_front (&orphan_list)); + } /* Removal of donors to this thread may change its effective priority, so recalculate. */ From a875d5fcb4eec1aeb97b5ab47ae963a9f8f3e5ae Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 23 Oct 2024 13:29:45 +0100 Subject: [PATCH 57/64] Update donate_priority to only attempt to sort position of the donee that isn't waiting for a lock --- src/threads/synch.c | 11 ++++++++--- src/threads/thread.c | 18 +++++++++++++++--- src/threads/thread.h | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 1123249..462bda7 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -214,12 +214,17 @@ donate_priority (struct thread *donor, struct thread *donee) { /* 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. */ + ready_list_reinsert (donee); + donee = NULL; + } else donee = donee->waiting_lock->holder; } - - ready_list_reorder (); } /* Acquires LOCK, sleeping until it becomes available if diff --git a/src/threads/thread.c b/src/threads/thread.c index ff66100..178cdf9 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -465,10 +465,22 @@ 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. */ void -ready_list_reorder (void) +ready_list_reinsert (struct thread *t) { - list_sort (&ready_list, priority_more, NULL); + enum intr_level old_level = intr_disable (); + + /* If the thread isn't ready to run, do nothing. */ + if (t->status == THREAD_READY) + { + list_remove (&t->elem); + list_insert_ordered (&ready_list, &t->elem, priority_more, NULL); + } + + intr_set_level (old_level); } /* Idle thread. Executes when no other thread is ready to run. @@ -558,7 +570,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 */ From 2cd4da17a4e158a3023790aa3d14f01ffb1bfbc0 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 23 Oct 2024 13:42:36 +0100 Subject: [PATCH 58/64] Refactor donate_priority to only allow for the current thread to donate its priority --- src/threads/synch.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 462bda7..0649772 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) @@ -249,7 +250,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); From b0074c80f014ca24763dc2f561bd185f62b6c983 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 23 Oct 2024 13:51:07 +0100 Subject: [PATCH 59/64] Refactor ready_list_reinsert to require being called with interrupts disabled --- src/threads/synch.c | 2 ++ src/threads/thread.c | 14 ++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 0649772..7dc6eaa 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -220,7 +220,9 @@ donate_priority (struct thread *donee) { /* 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 (); ready_list_reinsert (donee); + intr_set_level (old_level); donee = NULL; } else diff --git a/src/threads/thread.c b/src/threads/thread.c index 178cdf9..8731b3b 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -467,20 +467,18 @@ thread_get_recent_cpu (void) /* 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. */ + may have changed. Must be called with interrupts disabled. */ void ready_list_reinsert (struct thread *t) { - enum intr_level old_level = intr_disable (); + ASSERT (intr_get_level () == INTR_OFF); /* If the thread isn't ready to run, do nothing. */ - if (t->status == THREAD_READY) - { - list_remove (&t->elem); - list_insert_ordered (&ready_list, &t->elem, priority_more, NULL); - } + if (t->status != THREAD_READY) + return; - intr_set_level (old_level); + 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. From 5f8dea21befb9bf5688383796eb510770ddb2d0b Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 23 Oct 2024 14:10:48 +0100 Subject: [PATCH 60/64] Fix donate_priority to disable interrupts for entire update of possibly-ready donatee's priority --- src/threads/synch.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 7dc6eaa..b99332e 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -210,23 +210,25 @@ donate_priority (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) { - /* 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; + } } } From f9d82c92dec012832f16113269b11e0bdfe09d05 Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 23 Oct 2024 16:16:25 +0100 Subject: [PATCH 61/64] Update thread_recalculate_priority to disable interrupts preventing race conditions for access to donors and priorities w/ S --- src/threads/thread.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/threads/thread.c b/src/threads/thread.c index 8731b3b..dd594d9 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -417,6 +417,8 @@ void thread_recalculate_priority (void) { struct thread *t = thread_current (); + + enum intr_level old_level = intr_disable (); t->priority = t->base_priority; /* If there are no donors to the current thread, then the effective @@ -432,6 +434,7 @@ thread_recalculate_priority (void) if (max_donated_priority > t->priority) t->priority = max_donated_priority; } + intr_set_level (old_level); } /* Sets the current thread's nice value to NICE. */ From 6223846fdeabaa5028c0d06c1ac2fd69ea4b8911 Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 23 Oct 2024 16:30:38 +0100 Subject: [PATCH 62/64] Update lock_acquire to disable interrupts to eliminate race-conditions, w/ T --- src/threads/synch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index b99332e..7831774 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -248,15 +248,16 @@ lock_acquire (struct lock *lock) ASSERT (!lock_held_by_current_thread (lock)); struct thread *t = thread_current (); + enum intr_level old_level = intr_disable (); - /* TODO: If a high-priority thread holding a lock sleeps, this may cause a - race condition here or break the assumption that donation must occur. */ if (lock->holder != NULL) { t->waiting_lock = lock; donate_priority (lock->holder); } + intr_set_level (old_level); + sema_down (&lock->semaphore); lock->holder = thread_current (); t->waiting_lock = NULL; From 4879775d0b07f3d86af6d7b579e86bb01a7cc61c Mon Sep 17 00:00:00 2001 From: sBubshait Date: Wed, 23 Oct 2024 16:32:40 +0100 Subject: [PATCH 63/64] Update donate priority to add an assertion that intrrupts are disabled, w/ T --- src/threads/synch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 7831774..940faa5 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -196,9 +196,12 @@ lock_init (struct lock *lock) /* 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. */ + Also keeps track of the donation by updating the donors list. Expects + interrupts to be disabled. */ static void donate_priority (struct thread *donee) { + ASSERT (intr_get_level () == INTR_OFF); + struct thread *donor = thread_current (); list_push_back (&donee->donors_list, &donor->donor_elem); From 95386971e2dd07bd20ee1280d47e85a8c85eccfa Mon Sep 17 00:00:00 2001 From: Themis Demetriades Date: Wed, 23 Oct 2024 16:45:42 +0100 Subject: [PATCH 64/64] Update lock_release to disable interrupts in critical sections w/ S --- src/threads/synch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index 940faa5..1246206 100644 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -303,6 +303,7 @@ lock_release (struct lock *lock) struct list orphan_list; list_init (&orphan_list); + enum intr_level old_level = intr_disable (); /* Loop through current thread's donors, removing the ones waiting for the lock being released and keeping track of them (within orphan_list). Also identifies the highest priority donor thread among them. */ @@ -336,6 +337,7 @@ lock_release (struct lock *lock) list_push_back (&max_donor->donors_list, list_pop_front (&orphan_list)); } + intr_set_level (old_level); /* Removal of donors to this thread may change its effective priority, so recalculate. */ thread_recalculate_priority ();