Compare commits

...

98 Commits

Author SHA1 Message Date
Saleh Bubshait
74efa5e652 Merge branch 'task1/themis/thread-create-refactor' into 'master'
Refactor thread_create () to call thread_get_priority in order to retrieve priority

See merge request lab2425_autumn/pintos_22!21
2024-10-25 16:56:31 +00:00
Themis Demetriades
4066354f8a Refactor thread_create () to call thread_get_priority in order to retrieve priority 2024-10-25 17:03:18 +01:00
Demetriades, Themis
4c33653369 Merge branch 'task1/saleh/priority-donation-refactoring' into 'master'
priority donation refactoring

See merge request lab2425_autumn/pintos_22!20
2024-10-25 15:57:22 +00:00
sBubshait
c2414ec54d Add priority_less for comparing threads based on priority and Refactor sema up to use list_max for clarity 2024-10-25 16:04:55 +01:00
sBubshait
30ab3ae861 Update thread_create to only yield CPU to the new thread if necessary 2024-10-25 15:47:19 +01:00
sBubshait
81309dcda9 Refactor sema_up to follow PintOS styling of if statements 2024-10-25 15:44:56 +01:00
Demetriades, Themis
bbb62d2ee7 Merge branch 'gleb/fix-non-busy-sleep-bug' into 'master'
Remove unnecassary inter_disable from non-busy sleep

See merge request lab2425_autumn/pintos_22!19
2024-10-25 14:19:36 +00:00
Demetriades, Themis
f8bdd30f09 Merge branch 'gleb/bsd-priority-donation' into 'master'
Allow priority donation with BSD scheduler.

See merge request lab2425_autumn/pintos_22!18
2024-10-25 14:19:18 +00:00
869571108d Remove from sleeping_threads immediately, instead of when thread is scheduled 2024-10-25 14:10:59 +01:00
6e072a557f Allow priority donation with BSD scheduler.
- Recalculate priority with donations after BSD priority updates
- Remove mlfqs checks from lock_acquire
2024-10-25 14:03:55 +01:00
Saleh Bubshait
af31968e67 Merge branch 'gleb/fix-bsd-ready-list-order' into 'master'
Re-sort ready_list when priorities update + PRI_UPDATE_FREQ

See merge request lab2425_autumn/pintos_22!17
2024-10-25 08:32:08 +00:00
093c6efd30 Re-sort ready_list when priorities update + PRI_UPDATE_FREQ
- PRI_UPDATE_FREQ is a separate value from TIME_SLICE, they just
  happen to be set the same.
2024-10-25 09:13:27 +01:00
sb3923
c4cefbc2d5 Merge branch 'merged-complete' into 'master'
Merge code refactors into main branch

See merge request lab2425_autumn/pintos_22!16
2024-10-24 22:15:24 +00:00
EDiasAlberto
b88baede64 rename recent_cpu update function 2024-10-24 22:45:49 +01:00
EDiasAlberto
7d196ffc57 adjust spacing around brackets to fit styling conventions 2024-10-24 22:30:38 +01:00
EDiasAlberto
39f4edd5e6 remove unnecessary curly brace in thread_tick () 2024-10-24 22:09:28 +01:00
EDiasAlberto
60acc2e58d refactor thread_mlfqs checks in synch.c 2024-10-24 21:46:39 +01:00
EDiasAlberto
a6a0c4ad25 remove empty lines in thread.c 2024-10-24 20:47:30 +01:00
EDiasAlberto
74657bbf9c reorder init_thread for clarity 2024-10-24 20:34:44 +01:00
EDiasAlberto
0b230131f1 refactor thread struct to keep all changes together 2024-10-24 20:17:39 +01:00
EDiasAlberto
49a9284f02 refactor fixed-point.h to match style standards 2024-10-24 20:16:40 +01:00
Dias Alberto, Ethan
e749936b1f Merge branch 'merged-complete' into 'master'
Merge complete code base into master

See merge request lab2425_autumn/pintos_22!15
2024-10-23 19:05:45 +00:00
EDiasAlberto
20be75748c replace thread_mlfqs checks in priority calculations with assertions 2024-10-23 19:57:17 +01:00
EDiasAlberto
d8c843f16a add mlfqs condition checking in synchronisation primitives 2024-10-23 19:37:27 +01:00
EDiasAlberto
1fb101c365 remove repeated comparator and reorder thread_init operations 2024-10-23 18:56:48 +01:00
EDiasAlberto
c357126cc1 fix missing curly brace 2024-10-23 17:51:48 +01:00
Dias Alberto, Ethan
176750282f Merge branch 'BSD-merged' into 'master'
BSD Scheduler implementation

See merge request lab2425_autumn/pintos_22!9
2024-10-23 16:34:39 +00:00
Dias Alberto, Ethan
ed11c61f87 Merge branch 'master' into 'BSD-merged', fixing merge conflicts
# Conflicts:
#   src/threads/thread.c
2024-10-23 16:30:24 +00:00
Dias Alberto, Ethan
0cbae2a2e5 Merge branch 'task1/priority-donation' into 'master'
Merge 'task1/priority-donation' into 'master'

See merge request lab2425_autumn/pintos_22!14
2024-10-23 16:15:44 +00:00
Themis Demetriades
95386971e2 Update lock_release to disable interrupts in critical sections w/ S 2024-10-23 16:45:42 +01:00
sBubshait
4879775d0b Update donate priority to add an assertion that intrrupts are disabled, w/ T 2024-10-23 16:32:40 +01:00
sBubshait
6223846fde Update lock_acquire to disable interrupts to eliminate race-conditions, w/ T 2024-10-23 16:30:38 +01:00
Themis Demetriades
f9d82c92de Update thread_recalculate_priority to disable interrupts preventing race conditions for access to donors and priorities w/ S 2024-10-23 16:16:25 +01:00
Demetriades, Themis
25ca7b6522 Merge branch 'task1/themis/priority-donation' into 'task1/priority-donation'
Merge task1/themis/priority-donation into task1/priority-donation

See merge request lab2425_autumn/pintos_22!13
2024-10-23 15:03:07 +00:00
Themis Demetriades
5f8dea21be Fix donate_priority to disable interrupts for entire update of possibly-ready donatee's priority 2024-10-23 14:10:48 +01:00
Themis Demetriades
b0074c80f0 Refactor ready_list_reinsert to require being called with interrupts disabled 2024-10-23 13:51:07 +01:00
Themis Demetriades
2cd4da17a4 Refactor donate_priority to only allow for the current thread to donate its priority 2024-10-23 13:42:36 +01:00
Themis Demetriades
a875d5fcb4 Update donate_priority to only attempt to sort position of the donee that isn't waiting for a lock 2024-10-23 13:37:43 +01:00
sBubshait
d82176a2e2 Refactor lock release to follow PintOS indent style and use list functoins, w/ T 2024-10-22 22:52:29 +01:00
Themis Demetriades
7aec2e6862 Refactor donate_priority to include comments explaining its purpose and logic w/ S 2024-10-22 21:15:30 +01:00
sBubshait
78c6fd36e3 Refactor sema_up to add comments for clarity, w/ T 2024-10-22 21:04:14 +01:00
Themis Demetriades
48104b3a41 Refactor cond_signal to add comment clarifying the logic w/ S 2024-10-22 20:57:18 +01:00
sBubshait
5549b9c0cb Refactor thread recalculate priority to add comments for clarity, w/ T 2024-10-22 20:52:52 +01:00
sBubshait
bf6104200c Refactor thread set priority to remove unused variable and add comment, w/ T 2024-10-22 20:47:34 +01:00
Themis Demetriades
6983ccdd3b Update thread_get_priority description comment to be more specific w/ S 2024-10-22 20:41:44 +01:00
Themis Demetriades
fc1691f994 Refactor thread.h to remove superfluous thread priority comparison function w/ S 2024-10-22 20:36:37 +01:00
sBubshait
244db41434 Update condvar to use linear search due to changes in priority from donations, w/ T 2024-10-22 20:25:13 +01:00
Themis Demetriades
21cbfc9fe0 Implement transfer of orphaned donors when releasing lock w/ S 2024-10-22 20:06:21 +01:00
sBubshait
d9b9572631 Fix Bug in recalculating priority, uses 'elem' instead of 'donor_elem', w/ T 2024-10-22 19:49:53 +01:00
Themis Demetriades
a19d40bcca Reformat priority_more to obey code style 2024-10-22 19:01:55 +01:00
Themis Demetriades
f10514f4cc Update priority_more comment description to specify which list_elem member it is compatible with 2024-10-22 18:59:19 +01:00
Themis Demetriades
dae5b0d097 Update semaphore priority scheduling to use linear search on unordered list w/ S 2024-10-20 22:50:31 +01:00
Themis Demetriades
840df8af78 Fix bug in donate_priority that wouldn't update the list of donors w/ S 2024-10-20 22:29:20 +01:00
sBubshait
7f7b1648cd Fix indentation in recalculate priority to match pintos style, w/ T 2024-10-20 22:28:29 +01:00
sBubshait
44de31c0ff Fix Bug in Implementation of recalculate priority setting base priority, w/ T 2024-10-20 20:54:48 +01:00
Themis Demetriades
afcb12cef0 Reformat thread priority changing functions to follow style w/ S 2024-10-20 20:38:28 +01:00
sBubshait
b1dba1a0bd Add implementation for recalculate effective priority, w/ T 2024-10-20 20:37:03 +01:00
Themis Demetriades
8e20884a23 Update releasing of locks to update donation information w/ S 2024-10-20 20:17:27 +01:00
Themis Demetriades
ee0cf632b9 Fix attempt to donate priority within lock acquisition w/ S 2024-10-20 19:45:05 +01:00
sBubshait
343ac55d37 Implement priority donation helper function with propagation, w/ T 2024-10-20 19:42:35 +01:00
Themis Demetriades
f98e4bc81c Update lock_acquire to attempt donation of priorities, w/ S 2024-10-20 19:20:26 +01:00
sBubshait
5a651f1279 Update implementation of thread set priority to account for donations, w/ T 2024-10-20 18:06:07 +01:00
Themis Demetriades
fcc8cbb71e Implement initialization of new threads to track donation information, w/ S 2024-10-20 17:11:44 +01:00
sBubshait
8b1e0b9559 Add donation-related information to the thread structure, w/ T 2024-10-20 17:04:14 +01:00
cbb9d52455 Recover removed comment 2024-10-17 20:09:43 +01:00
Themis
6b9b671368 Update sema_up to properly yield during execution of an interrupt handler 2024-10-17 20:01:55 +01:00
sBubshait
bfdedc53e2 Update set priority so not to yield if no ready threads 2024-10-17 19:46:10 +01:00
Themis
711efdc78a Implement priority scheduling for condition variables 2024-10-17 19:43:35 +01:00
sBubshait
c9a9d57019 Merge branch 'task1/priority-scheduling' into task1/merged/priority-scheduling
# Conflicts:
#	.gitignore
#	src/threads/synch.c
#	src/threads/thread.c
2024-10-17 19:30:19 +01:00
044c383a0f fix mlfqs tests, complete BSD scheduling 2024-10-17 18:31:09 +01:00
c5e41db9b0 Implement BSD calculations
- load_avg, recent_cpu, priority calculations
- reduce frac bits to 14
- ignore thread_set_priority when BSD enabled
2024-10-17 18:31:09 +01:00
a7a6d0b9d4 Fix fixed-point returns 2024-10-17 18:31:09 +01:00
EDiasAlberto
d5f913de2b implement recent_cpu 2024-10-17 18:31:09 +01:00
630fbaa3ab implement thread_get_nice & thread_get_recent_cpu 2024-10-17 18:31:09 +01:00
82cc108c38 inline funcs instead of macros for fixed-point 2024-10-17 18:31:09 +01:00
EDiasAlberto
337f8828d9 implement thread_get_nice, thread_set_nice and skeleton for calculate_priority 2024-10-17 18:31:09 +01:00
EDiasAlberto
4e4b5fb83c modify gitignore to ignore vscode files 2024-10-17 18:31:09 +01:00
EDiasAlberto
112432dde0 define basic fixed-point macros 2024-10-17 18:31:09 +01:00
EDiasAlberto
f969b02630 define fixed point arithmetic constants
gitignore clion files
2024-10-17 18:31:09 +01:00
62cca87322 Merge branch 'gitlab-ci' into 'master'
GitLab CI & testing image

See merge request lab2425_autumn/pintos_22!2
2024-10-17 17:30:41 +00:00
sBubshait
88967acdaa Update cond_wait to insert into waiters list in sorted order of priority 2024-10-17 08:53:53 +01:00
sBubshait
e74ee59e17 Update sema priority compare to take aux optionally as priority of first sema 2024-10-17 08:46:14 +01:00
sBubshait
53b296d6c4 Add function to compare the priority of two semaphores 2024-10-17 08:36:29 +01:00
sBubshait
0d6fb2f167 Update sema_up to yield CPU if unblocked has higher priority 2024-10-17 07:15:10 +01:00
sBubshait
24900545d4 Update sema_down to insert into waiters list in priority sorted order 2024-10-17 06:54:10 +01:00
sBubshait
fb268cdef0 Update thread make priority_more public 2024-10-17 06:47:58 +01:00
sBubshait
dbb7fd56e3 Update set priority to reorder the list if priority is changed 2024-10-17 06:38:27 +01:00
sBubshait
949455aae5 Update set priority to eliminate race condition when accessing ready list 2024-10-17 06:35:39 +01:00
sBubshait
5c09ff0149 Updated set priority to yield if priority is lowered 2024-10-17 06:27:59 +01:00
sBubshait
9f53040d27 Update thread_set_priority to not do anything if priority is unchanged 2024-10-17 06:00:34 +01:00
sBubshait
62c8818c05 Update thread_yield to add thread back in sorted order of priority 2024-10-16 08:18:51 +01:00
sBubshait
fda79173c0 Update thread_unblock to maintain priority order in ready_list 2024-10-16 08:14:00 +01:00
sBubshait
1c53790ca7 Update set_priority to ensure that the new priority is within bounds 2024-10-16 08:13:56 +01:00
sBubshait
9bb0b758c8 Fix Error missing semicolon after function signature 2024-10-16 07:40:41 +01:00
sBubshait
8b3f9e353f Update creating thread to yield if the new thread has higher priority 2024-10-16 07:33:24 +01:00
sBubshait
83910f945c Add priority comparator function for thread list sorting 2024-10-16 07:26:02 +01:00
sBubshait
9f71c989a9 Update gitignore to ignore temporary Mac OS files and code editor folders 2024-10-16 07:10:31 +01:00
d51648d7dc GitLab CI & testing image 2024-10-10 17:34:33 +01:00
8 changed files with 566 additions and 57 deletions

11
.gitignore vendored
View File

@@ -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
@@ -27,3 +31,6 @@
*.nav
*.toc
#ignore files from CLion/VSCode IDEs
.idea
.vscode

44
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,44 @@
stages:
- test
.pintos_tests:
stage: test
image: gitlab.doc.ic.ac.uk:4567/lab2425_autumn/pintos_22/pintos-testing:latest
artifacts:
when: always
paths:
- src/$DIR/build/tests/$DIR/
before_script:
- cd src/utils
- make
- export PATH=$PWD:$PATH
- cd ../..
script:
- cd src/$DIR
- make check | tee build.log
- grep -q "FAIL tests/$DIR" build.log && exit 1 || exit 0
test_devices:
extends: .pintos_tests
variables:
DIR: devices
test_filesys:
extends: .pintos_tests
variables:
DIR: filesys
test_threads:
extends: .pintos_tests
variables:
DIR: threads
test_userprog:
extends: .pintos_tests
variables:
DIR: userprog
test_vm:
extends: .pintos_tests
variables:
DIR: vm

3
Dockerfile.devel Normal file
View File

@@ -0,0 +1,3 @@
FROM debian:12-slim
RUN apt update && apt install gcc perl make qemu-system-i386 gdb -y

View File

@@ -119,9 +119,6 @@ timer_sleep (int64_t ticks)
NULL);
intr_set_level (old_level);
sema_down (&st.semaphore);
old_level = intr_disable ();
list_remove (&st.elem);
intr_set_level (old_level);
}
/* Sleeps for approximately MS milliseconds. Interrupts must be
@@ -204,7 +201,10 @@ timer_interrupt (struct intr_frame *args UNUSED)
{
struct asleep_thread *st = list_entry (e, struct asleep_thread, elem);
if (ticks >= st->end_at)
sema_up (&st->semaphore);
{
list_remove (&st->elem);
sema_up (&st->semaphore);
}
else
break;
}

100
src/threads/fixed-point.h Normal file
View File

@@ -0,0 +1,100 @@
#include <stdint.h>
#ifndef FIXED_POINT_H
#define FIXED_POINT_H
typedef struct
{
int32_t raw;
} fp32_t;
/* Fixed Point Arithmetic bit count constants */
#define NUM_FRAC_BITS 14
#define NUM_INT_BITS (31 - NUM_FRAC_BITS)
#define CONVERSION_FACTOR (1 << NUM_FRAC_BITS) /* f = 2^q, (2^14) */
/* Fixed Point Arithmetic conversion operations */
/* Converts an integer n to a fixed point number */
inline fp32_t
fp_from_int (int32_t n)
{
return (fp32_t){ n * CONVERSION_FACTOR };
}
/* Handles conversion of fixed point to integer,
with truncation */
inline int32_t
fp_floor (fp32_t x)
{
return x.raw / CONVERSION_FACTOR;
}
/* Handles conversion of fixed point to integer,
with rounding */
inline int32_t
fp_round (fp32_t x)
{
if (x.raw >= 0)
return (x.raw + CONVERSION_FACTOR / 2) / CONVERSION_FACTOR;
else
return (x.raw - CONVERSION_FACTOR / 2) / CONVERSION_FACTOR;
}
/* Add two fixed points */
inline fp32_t
fp_add (fp32_t x, fp32_t y)
{
return (fp32_t){ x.raw + y.raw };
}
/* Subtract two fixed points */
inline fp32_t
fp_sub (fp32_t x, fp32_t y)
{
return (fp32_t){ x.raw - y.raw };
}
/* Multiple two fixed points */
inline fp32_t
fp_mul (fp32_t x, fp32_t y)
{
return (fp32_t){ ((int64_t)x.raw) * y.raw / CONVERSION_FACTOR };
}
/* Divide two fixed points */
inline fp32_t
fp_div (fp32_t x, fp32_t y)
{
return (fp32_t){ ((int64_t)x.raw) * CONVERSION_FACTOR / y.raw };
}
/* Multiply fixed point and integer */
inline fp32_t
fp_mul_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw * n };
}
/* Divide fixed point by integer */
inline fp32_t
fp_div_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw / n };
}
/* Add fixed point to integer */
inline fp32_t
fp_add_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw + n * CONVERSION_FACTOR };
}
/* Subtract integer from fixed point */
inline fp32_t
fp_sub_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw - n * CONVERSION_FACTOR };
}
#endif //FIXED_POINT_H

View File

@@ -32,6 +32,10 @@
#include "threads/interrupt.h"
#include "threads/thread.h"
static bool
priority_less (const struct list_elem *a_, const struct list_elem *b_,
void *aux UNUSED);
/* Initializes semaphore SEMA to VALUE. A semaphore is a
nonnegative integer along with two atomic operators for
manipulating it:
@@ -68,8 +72,7 @@ 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_push_back (&sema->waiters, &thread_current ()->elem);
thread_block ();
}
sema->value--;
@@ -107,19 +110,31 @@ 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;
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))
{
/* Enforces wake-up of the highest priority thread waiting for the
semaphore. */
struct list_elem *e = list_max (&sema->waiters, priority_less, NULL);
list_remove (e);
thread_unblock (list_entry (e, struct thread, elem));
}
sema->value++;
intr_set_level (old_level);
thread_yield ();
/* 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
thread_yield ();
}
static void sema_test_helper (void *sema_);
@@ -183,6 +198,47 @@ lock_init (struct lock *lock)
sema_init (&lock->semaphore, 1);
}
/* 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. 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);
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;
/* 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->priority = donor->priority;
donee = donee->waiting_lock->holder;
}
}
}
/* Acquires LOCK, sleeping until it becomes available if
necessary. The lock must not already be held by the current
thread.
@@ -198,8 +254,19 @@ lock_acquire (struct lock *lock)
ASSERT (!intr_context ());
ASSERT (!lock_held_by_current_thread (lock));
struct thread *t = thread_current ();
enum intr_level old_level = intr_disable ();
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;
}
/* Tries to acquires LOCK and returns true if successful or false
@@ -233,8 +300,54 @@ lock_release (struct lock *lock)
ASSERT (lock != NULL);
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);
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. */
struct list_elem *tail = list_tail (&current_thread->donors_list);
struct list_elem *e = list_begin (&current_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)
{
while (!list_empty (&orphan_list))
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 ();
lock->holder = NULL;
sema_up (&lock->semaphore);
thread_yield ();
}
/* Returns true if the current thread holds LOCK, false
@@ -255,6 +368,49 @@ struct semaphore_elem
struct semaphore semaphore; /* This semaphore. */
};
/* Function that compares the two threads associated with the provided
pointers to their 'elem' member. Returns true if the thread associated
with a_ has a lower priority than that of b_. */
static bool
priority_less (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;
}
/* 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 *inserting_telem)
{
struct list_elem *te_a, *te_b;
te_b = list_front (
&list_entry (b, struct semaphore_elem, elem)->semaphore.waiters);
if (inserting_telem == NULL)
{
te_a = list_front (
&list_entry (a, struct semaphore_elem, elem)->semaphore.waiters);
}
else
{
te_a = inserting_telem;
}
return priority_more (te_a, te_b, NULL);
}
/* 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. */
@@ -318,9 +474,14 @@ 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))
{
/* 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

View File

@@ -4,6 +4,8 @@
#include <random.h>
#include <stdio.h>
#include <string.h>
#include "devices/timer.h"
#include "threads/fixed-point.h"
#include "threads/flags.h"
#include "threads/interrupt.h"
#include "threads/intr-stubs.h"
@@ -49,9 +51,11 @@ struct kernel_thread_frame
static long long idle_ticks; /* # of timer ticks spent idle. */
static long long kernel_ticks; /* # of timer ticks in kernel threads. */
static long long user_ticks; /* # of timer ticks in user programs. */
static fp32_t load_avg = { 0 }; /* System load average. */
/* Scheduling. */
#define TIME_SLICE 4 /* # of timer ticks to give each thread. */
#define PRI_UPDATE_FREQ 4 /* # of timer ticks to update priorities. */
static unsigned thread_ticks; /* # of timer ticks since last yield. */
/* If false (default), use round-robin scheduler.
@@ -64,12 +68,18 @@ static void kernel_thread (thread_func *, void *aux);
static void idle (void *aux UNUSED);
static struct thread *running_thread (void);
static struct thread *next_thread_to_run (void);
static void init_thread (struct thread *, const char *name, int priority);
static void init_thread (struct thread *, const char *name, int nice,
int priority, fp32_t recent_cpu);
static bool is_thread (struct thread *) UNUSED;
static void *alloc_frame (struct thread *, size_t size);
static int calculate_bsd_priority (fp32_t recent_cpu, int nice);
static void update_recent_cpu (struct thread *t, void *aux UNUSED);
static void recalculate_priority (struct thread *t);
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
@@ -95,7 +105,9 @@ thread_init (void)
/* Set up a thread structure for the running thread. */
initial_thread = running_thread ();
init_thread (initial_thread, "main", PRI_DEFAULT);
fp32_t initial_thread_recent_cpu = { 0 };
init_thread (initial_thread, "main", NICE_DEFAULT, PRI_DEFAULT,
initial_thread_recent_cpu);
initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid ();
}
@@ -145,6 +157,35 @@ thread_tick (void)
else
kernel_ticks++;
/* Update system load_avg and all threads recent_cpu every second. */
int64_t ticks = timer_ticks ();
if (thread_mlfqs)
{
if (t != idle_thread)
t->recent_cpu = fp_add_int (t->recent_cpu, 1);
if (ticks % TIMER_FREQ == 0)
{
size_t ready = threads_ready ();
if (t != idle_thread)
ready++;
fp32_t old_coeff = fp_div_int (fp_mul_int (load_avg, 59), 60);
fp32_t new_coeff = fp_div_int (fp_from_int (ready), 60);
load_avg = fp_add (old_coeff, new_coeff);
thread_foreach (update_recent_cpu, NULL);
/* Priorities have been updated, need to re-sort. */
list_sort (&ready_list, priority_more, NULL);
}
/* Recent cpu was updated, update priority. */
if (t != idle_thread && ticks % PRI_UPDATE_FREQ == 0)
{
t->base_priority = calculate_bsd_priority (t->recent_cpu, t->nice);
recalculate_priority (t);
}
}
/* Enforce preemption. */
if (++thread_ticks >= TIME_SLICE)
intr_yield_on_return ();
@@ -192,7 +233,8 @@ thread_create (const char *name, int priority,
return TID_ERROR;
/* Initialize thread. */
init_thread (t, name, priority);
struct thread *parent_thread = thread_current ();
init_thread (t, name, parent_thread->nice, priority, parent_thread->recent_cpu);
tid = t->tid = allocate_tid ();
/* Prepare thread for first run by initializing its stack.
@@ -219,7 +261,11 @@ thread_create (const char *name, int priority,
/* Add to run queue. */
thread_unblock (t);
thread_yield ();
/* Yield if the newly created thread has higher priority than the current
thread. */
if (t->priority > thread_get_priority ())
thread_yield ();
return tid;
}
@@ -257,7 +303,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 +376,13 @@ thread_yield (void)
ASSERT (!intr_context ());
old_level = intr_disable ();
if (cur != idle_thread)
list_insert_ordered (&ready_list, &cur->elem, thread_priority_greater,
NULL);
if (cur != idle_thread)
{
/* Insert the thread back into the ready list in priority order. */
list_insert_ordered (&ready_list, &cur->elem, priority_more, NULL);
}
cur->status = THREAD_READY;
schedule ();
intr_set_level (old_level);
@@ -352,54 +405,161 @@ thread_foreach (thread_action_func *func, void *aux)
}
}
/* Sets the current thread's priority to NEW_PRIORITY. */
void
thread_set_priority (int new_priority)
/* Function that compares the two threads associated with the provided
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)
{
ASSERT (PRI_MIN <= new_priority && new_priority <= PRI_MAX);
int old_priority = thread_get_priority ();
struct thread *a = list_entry (a_, struct thread, elem);
struct thread *b = list_entry (b_, struct thread, elem);
return a->priority > b->priority;
thread_current ()->priority = new_priority;
if (new_priority < old_priority)
thread_yield ();
}
/* Returns the current thread's 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
thread_set_priority (int new_base_priority)
{
if (thread_mlfqs)
return;
ASSERT (new_base_priority >= PRI_MIN);
ASSERT (new_base_priority <= PRI_MAX);
struct thread *t = thread_current ();
/* If the base priority is unchanged, do nothing. */
if (new_base_priority == t->base_priority)
return;
t->base_priority = new_base_priority;
recalculate_priority (t);
thread_yield ();
}
/* Returns the current thread's effective priority. */
int
thread_get_priority (void)
{
return thread_current ()->priority;
}
/* Updates recent_cpu for a thread. */
static void
update_recent_cpu (struct thread *t, void *aux UNUSED)
{
fp32_t curr_recent_cpu = t->recent_cpu;
fp32_t dbl_load_avg = fp_mul_int (load_avg, 2);
fp32_t recent_cpu_coeff
= fp_div (dbl_load_avg, fp_add_int (dbl_load_avg, 1));
t->recent_cpu
= fp_add_int (fp_mul (recent_cpu_coeff, curr_recent_cpu), t->nice);
// recent_cpu was updated, update priority.
t->base_priority = calculate_bsd_priority (t->recent_cpu, t->nice);
recalculate_priority (t);
}
/* Recalculates the effective priority of the current thread. */
void
thread_recalculate_priority (void)
{
struct thread *t = thread_current ();
recalculate_priority (t);
}
static void
recalculate_priority (struct thread *t)
{
enum intr_level old_level = intr_disable ();
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;
}
intr_set_level (old_level);
}
/* Sets the current thread's nice value to NICE. */
void
thread_set_nice (int nice UNUSED)
thread_set_nice (int nice)
{
/* Not yet implemented. */
ASSERT (NICE_MIN <= nice && nice <= NICE_MAX);
struct thread *t = thread_current ();
t->nice = nice;
t->base_priority = calculate_bsd_priority (t->recent_cpu, t->nice);
recalculate_priority (t);
struct thread *next_t
= list_entry (list_begin (&ready_list), struct thread, elem);
if (t->priority < next_t->priority)
thread_yield ();
}
/* Returns the current thread's nice value. */
int
thread_get_nice (void)
{
/* Not yet implemented. */
return 0;
return thread_current ()->nice;
}
/* Returns 100 times the system load average. */
int
thread_get_load_avg (void)
{
/* Not yet implemented. */
return 0;
return fp_round (fp_mul_int (load_avg, 100));
}
/* Returns 100 times the current thread's recent_cpu value. */
int
thread_get_recent_cpu (void)
{
/* Not yet implemented. */
return 0;
return fp_round (fp_mul_int (thread_current ()->recent_cpu, 100));
}
/* Reinsert thread t into the ready list at its correct position
in descending order of priority. Used when this thread's priority
may have changed. Must be called with interrupts disabled. */
void
ready_list_reinsert (struct thread *t)
{
ASSERT (intr_get_level () == INTR_OFF);
/* If the thread isn't ready to run, do nothing. */
if (t->status != THREAD_READY)
return;
list_remove (&t->elem);
list_insert_ordered (&ready_list, &t->elem, priority_more, NULL);
}
/* Idle thread. Executes when no other thread is ready to run.
@@ -475,7 +635,8 @@ is_thread (struct thread *t)
/* Does basic initialization of T as a blocked thread named
NAME. */
static void
init_thread (struct thread *t, const char *name, int priority)
init_thread (struct thread *t, const char *name, int nice, int priority,
fp32_t recent_cpu)
{
enum intr_level old_level;
@@ -487,9 +648,17 @@ 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->magic = THREAD_MAGIC;
t->base_priority
= thread_mlfqs ? calculate_bsd_priority (recent_cpu, nice) : priority;
list_init (&t->donors_list);
t->waiting_lock = NULL;
t->nice = nice;
t->recent_cpu = recent_cpu;
t->priority = t->base_priority;
old_level = intr_disable ();
list_push_back (&all_list, &t->allelem);
intr_set_level (old_level);
@@ -568,6 +737,21 @@ thread_schedule_tail (struct thread *prev)
}
}
/* Calculates BSD priority for a thread */
static int
calculate_bsd_priority (fp32_t recent_cpu, int nice)
{
ASSERT (thread_mlfqs);
int priority = PRI_MAX - (fp_round (recent_cpu) / 4) - (nice * 2);
if (priority < PRI_MIN)
return PRI_MIN;
if (priority > PRI_MAX)
return PRI_MAX;
return priority;
}
/* Schedules a new process. At entry, interrupts must be off and
the running process's state must have been changed from
running to some other state. This function finds another
@@ -605,17 +789,6 @@ allocate_tid (void)
return tid;
}
/* Returns true iff the priority of the first list element's thread is greater
than that of the second list element's thread. */
bool
thread_priority_greater (const struct list_elem *a, const struct list_elem *b,
void *aux UNUSED)
{
struct thread *ta = list_entry (a, struct thread, elem);
struct thread *tb = list_entry (b, struct thread, elem);
return ta->priority > tb->priority;
}
/* Offset of `stack' member within `struct thread'.
Used by switch.S, which can't figure it out on its own. */
uint32_t thread_stack_ofs = offsetof (struct thread, stack);

View File

@@ -4,6 +4,7 @@
#include <debug.h>
#include <list.h>
#include <stdint.h>
#include "threads/fixed-point.h"
/* States in a thread's life cycle. */
enum thread_status
@@ -24,6 +25,10 @@ typedef int tid_t;
#define PRI_DEFAULT 31 /* Default priority. */
#define PRI_MAX 63 /* Highest priority. */
#define NICE_MIN -20 /* Lowest niceness. */
#define NICE_DEFAULT 0 /* Default niceness. */
#define NICE_MAX 20 /* Highest niceness. */
/* A kernel thread or user process.
Each thread structure is stored in its own 4 kB page. The
@@ -90,9 +95,23 @@ 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. */
/* MLFQS items */
int nice; /* Nice value for this thread */
fp32_t recent_cpu; /* Amount of time this process received */
/* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */
#ifdef USERPROG
/* Owned by userprog/process.c. */
uint32_t *pagedir; /* Page directory. */
@@ -131,15 +150,17 @@ 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);
void thread_recalculate_priority (void);
int thread_get_nice (void);
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;
void ready_list_reinsert (struct thread *t);
#endif /* threads/thread.h */