diff --git a/devices/timer.c b/devices/timer.c index 796f5a8..50c308e 100644 --- a/devices/timer.c +++ b/devices/timer.c @@ -90,11 +90,15 @@ timer_elapsed (int64_t then) { /* Suspends execution for approximately TICKS timer ticks. */ void timer_sleep (int64_t ticks) { - int64_t start = timer_ticks (); + int64_t start = timer_ticks (); // current time (in ticks : 1ms) ASSERT (intr_get_level () == INTR_ON); - while (timer_elapsed (start) < ticks) - thread_yield (); + /* busy waiting */ + // while (timer_elapsed (start) < ticks) + // thread_yield (); + /* sleep & awake */ + // if (timer_elapsed(start) < ticks) + thread_sleep(start+ticks); // alarm-multiple 관련 변경 // current time + ticks(required) = time to be awaken => local ticks } /* Suspends execution for approximately MS milliseconds. */ @@ -126,6 +130,19 @@ static void timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); + if (thread_mlfqs){ + mlfqs_increment(); + if (timer_ticks() % 4 == 0){ + mlfqs_priority(thread_current()); + if (timer_ticks() % TIMER_FREQ == 0){ + mlfqs_load_avg(); + mlfqs_recalc(); + } + } + } + /* per every tick(1ms), check if there are any threads to be awaken */ + if(get_next_tick_to_awake() <= ticks) // if the first candidate of sleep list needds to be awaken (== if there's at least 1 thread to be awaken) + thread_awake(ticks); // alarm-multiple 관련 변경 // by calling thread_awake(), check every threads in the sleep list and wakeup if necessary } /* Returns true if LOOPS iterations waits for more than one timer diff --git a/include/threads/fixed_point.h b/include/threads/fixed_point.h new file mode 100644 index 0000000..3ef2545 --- /dev/null +++ b/include/threads/fixed_point.h @@ -0,0 +1,73 @@ +#define F (1 << 14) //fixed point 1 (in 17.14 format) +#define INT_MAX ((1 << 31) - 1) +#define INT_MIN (-(1 << 31)) + +/* x and y denote fixed_point numbers in 17.14 format +* n is an integer +* int = integer +* fp = fixed point numbers +*/ + +/* Prototypes */ +int int_to_fp(int n); +int fp_to_int_round(int x); +int fp_to_int(int x); +int add_fp(int x, int y); +int add_mixed(int x, int n); +int sub_fp(int x, int y); +int sub_mixed(int x, int n); +int mult_fp(int x, int y); +int mult_mixed(int x, int y); +int div_fp(int x, int y); +int div_mixed(int x, int n); + +/* convert int to fp */ +int int_to_fp (int n) { + return n * F; +} + +/* convert fp to int (rounding toward zero) */ +int fp_to_int (int x) { + return x / F; +} + +/* convert fp to int (rounding to nearest int) */ +int fp_to_int_round (int x) { + if (x >= 0) return (x + F / 2) / F; + else return (x - F / 2) / F; +} + +/* fp + fp */ +int add_fp (int x, int y) { + return x + y; +} + +/* fp - fp */ +int sub_fp (int x, int y) { + return x - y; +} + +/* */ +int add_mixed (int x, int n) { + return x + n * F; +} + +int sub_mixed (int x, int n) { + return x - n * F; +} + +int mult_fp (int x, int y) { + return ((int64_t) x) * y / F; +} + +int mult_mixed (int x, int n) { + return x * n; +} + +int div_fp (int x, int y) { + return ((int64_t) x) * F / y; +} + +int div_mixed (int x, int n) { + return x / n; +} \ No newline at end of file diff --git a/include/threads/synch.h b/include/threads/synch.h index 3d089fd..3687fff 100644 --- a/include/threads/synch.h +++ b/include/threads/synch.h @@ -38,6 +38,9 @@ void cond_wait (struct condition *, struct lock *); void cond_signal (struct condition *, struct lock *); void cond_broadcast (struct condition *, struct lock *); +/* priority-sema,condvar 관련 변경 */ +bool cmp_sem_priority (const struct list_elem *a, const struct list_elem *b, void *aux); + /* Optimization barrier. * * The compiler will not reorder operations across an diff --git a/include/threads/thread.h b/include/threads/thread.h index 33b46e6..a1c2a9c 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -91,9 +91,17 @@ struct thread { enum thread_status status; /* Thread state. */ char name[16]; /* Name (for debugging purposes). */ int priority; /* Priority. */ - /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ + struct list_elem all_elem; /* List element for all_list */ // 변경사항 + + + int init_priority; /* default priority (to initialize after return donated priority) */ // priority-donate 관련 변경 + struct lock *wait_on_lock; /* Address of lock that this thread is waiting for */ // priority-donate 관련 변경 + struct list donations; /* donors list (multiple donation) */ //priority-donate 관련 변경 + struct list_elem donation_elem; /* multiple donation case */ //priority-donate 관련 변경 + int nice; /* nice value of thread */// 변경사항 + int recent_cpu; /* recent_cpu which estimates how much CPU time earned recently */// 변경사항 #ifdef USERPROG /* Owned by userprog/process.c. */ @@ -107,6 +115,7 @@ struct thread { /* Owned by thread.c. */ struct intr_frame tf; /* Information for switching */ unsigned magic; /* Detects stack overflow. */ + int64_t wakeup_tick; /* Local ticks (minimum ticks required before awakened ) */ /* alarm-multiple 관련 변경 */ }; /* If false (default), use round-robin scheduler. @@ -143,4 +152,28 @@ int thread_get_load_avg (void); void do_iret (struct intr_frame *tf); +/* alarm-multiple 관련 변경 */ +void thread_sleep(int64_t ticks); +void thread_awake(int64_t ticks); +void update_next_tick_to_awake(int64_t ticks); +int64_t get_next_tick_to_awake(void); + +/* alarm-priority, priority-fifo/preempt 관련 변경 */ +void check_curr_max_priority(void); +bool cmp_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED); + +/* priority-donate 관련 변경 */ +void donate_priority(void); +void remove_donors_on_released_lock(struct lock *lock); +void refresh_priority(void); +bool cmp_donation_priority(const struct list_elem *a, const struct list_elem *b, void *aux); + +/* 변경사항 */ +void mlfqs_priority (struct thread *t); +void mlfqs_recent_cpu (struct thread *t); +void mlfqs_load_avg (void); +void mlfqs_increment (void); +void mlfqs_recalc(void); + + #endif /* threads/thread.h */ diff --git a/threads/synch.c b/threads/synch.c index 8ca3230..ca6604d 100644 --- a/threads/synch.c +++ b/threads/synch.c @@ -57,6 +57,7 @@ sema_init (struct semaphore *sema, unsigned value) { interrupts disabled, but if it sleeps then the next scheduled thread will probably turn interrupts back on. This is sema_down function. */ +/* priority-sema,condvar 관련 변경 */ void sema_down (struct semaphore *sema) { enum intr_level old_level; @@ -66,7 +67,8 @@ sema_down (struct semaphore *sema) { old_level = intr_disable (); while (sema->value == 0) { - list_push_back (&sema->waiters, &thread_current ()->elem); + // list_push_back (&sema->waiters, &thread_current ()->elem); + list_insert_ordered(&sema->waiters, &thread_current()->elem, cmp_priority, NULL); // priority-sema,condvar 관련 변경 // instead Round-Robin scheduling, insert into waiters list based on priority. thread_block (); } sema->value--; @@ -102,6 +104,7 @@ sema_try_down (struct semaphore *sema) { and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. */ +/* priority-sema,condvar 관련 변경 */ void sema_up (struct semaphore *sema) { enum intr_level old_level; @@ -109,10 +112,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)){ + list_sort (&sema->waiters, cmp_priority, NULL); //priority-sema,condvar 관련 변경 // there might be some priority changes while waiting for the sema, therefore sort the waiters list again + thread_unblock (list_entry (list_pop_front (&sema->waiters), struct thread, elem)); + } sema->value++; + check_curr_max_priority(); // priority-sema,condvar 관련 변경 // there's a new UNBLOCKED thread, so let's check if the current thread is still the thread with highest priority. if not, yield ! intr_set_level (old_level); } @@ -182,14 +187,24 @@ lock_init (struct lock *lock) { interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ + +/* priority-donate 관련 변경 */ void lock_acquire (struct lock *lock) { + struct thread *curr = thread_current(); ASSERT (lock != NULL); ASSERT (!intr_context ()); - ASSERT (!lock_held_by_current_thread (lock)); - + ASSERT (!lock_held_by_current_thread (lock)); // no recursive acquisition (cannot acquire lock while already holding the same lock) + if(!thread_mlfqs){ + if (lock->holder){ // if holder of the target lock exists, (already held by other thread) + curr->wait_on_lock = lock; // save the target lock's address on current holder's wait_on_lock field. + list_insert_ordered(&lock->holder->donations, &curr->donation_elem, cmp_donation_priority, NULL); // insert current thread's donation_elem into lock holder's donations list + donate_priority(); + } + } sema_down (&lock->semaphore); - lock->holder = thread_current (); + curr->wait_on_lock = NULL; // after acquired the lock, set NULL on wait_on_lock field + lock->holder = curr; } /* Tries to acquires LOCK and returns true if successful or false @@ -205,8 +220,8 @@ lock_try_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!lock_held_by_current_thread (lock)); - success = sema_try_down (&lock->semaphore); - if (success) + success = sema_try_down (&lock->semaphore); // sucess = true(acquire successed) or false(acquire failed) + if (success) // if sucess = true lock->holder = thread_current (); return success; } @@ -217,13 +232,18 @@ lock_try_acquire (struct lock *lock) { An interrupt handler cannot acquire a lock, so it does not make sense to try to release a lock within an interrupt handler. */ + +/* priority-donate 관련 변경 */ void lock_release (struct lock *lock) { ASSERT (lock != NULL); - ASSERT (lock_held_by_current_thread (lock)); - - lock->holder = NULL; - sema_up (&lock->semaphore); + ASSERT (lock_held_by_current_thread (lock)); // check if current thread is the lock holder + lock->holder = NULL; // make lock's holder field NULL. time to release + if (!thread_mlfqs){ + remove_donors_on_released_lock(lock); // remove the donors on released lock from current thread's donations + refresh_priority(); // refresh current thread's priority + } + sema_up (&lock->semaphore); // allow other threads to acquire that lock, by sema up } /* Returns true if the current thread holds LOCK, false @@ -272,6 +292,7 @@ cond_init (struct condition *cond) { interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ +/* priority-sema,condvar 관련 변경 */ void cond_wait (struct condition *cond, struct lock *lock) { struct semaphore_elem waiter; @@ -282,7 +303,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_push_back (&cond->waiters, &waiter.elem); + list_insert_ordered (&cond->waiters, &waiter.elem, cmp_sem_priority, NULL); // priority-sema,condvar 관련 변경 // instead Round-Robin scheduling, insert into waiters list based on priority. lock_release (lock); sema_down (&waiter.semaphore); lock_acquire (lock); @@ -295,6 +317,7 @@ cond_wait (struct condition *cond, struct lock *lock) { An interrupt handler cannot acquire a lock, so it does not make sense to try to signal a condition variable within an interrupt handler. */ +/* priority-sema,condvar 관련 변경 */ void cond_signal (struct condition *cond, struct lock *lock UNUSED) { ASSERT (cond != NULL); @@ -302,9 +325,10 @@ 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)){ + list_sort (&cond->waiters, cmp_sem_priority, NULL); // priority-sema,condvar 관련 변경 (추가사항) // there might be some priority changes while waiting for the condvar, therefore sort the waiters list again + sema_up (&list_entry (list_pop_front (&cond->waiters), struct semaphore_elem, elem)->semaphore); + } } /* Wakes up all threads, if any, waiting on COND (protected by @@ -321,3 +345,18 @@ cond_broadcast (struct condition *cond, struct lock *lock) { while (!list_empty (&cond->waiters)) cond_signal (cond, lock); } + +/* priority-sema,condvar 관련 변경 */ +/* Sort the condvar's waiters list which is the list of semaphores waiting for the condvar, based on the priority of thread (the first one in the semaphore's waiters list) */ +bool cmp_sem_priority (const struct list_elem *a, const struct list_elem *b, void *aux){ + struct semaphore_elem *sema_a = list_entry(a, struct semaphore_elem, elem); + struct semaphore_elem *sema_b = list_entry(b, struct semaphore_elem, elem); + struct list *sema_a_waiters = &(sema_a->semaphore.waiters); + struct list *sema_b_waiters = &(sema_b->semaphore.waiters); + struct thread *sema_a_waiters_front = list_entry(list_begin(sema_a_waiters), struct thread, elem); + struct thread *sema_b_waiters_front = list_entry(list_begin(sema_b_waiters), struct thread, elem); + if (sema_a_waiters_front->priority > sema_b_waiters_front->priority) + return true; + else + return false; +} diff --git a/threads/thread.c b/threads/thread.c index bc9e260..61a77cf 100644 --- a/threads/thread.c +++ b/threads/thread.c @@ -11,6 +11,7 @@ #include "threads/synch.h" #include "threads/vaddr.h" #include "intrinsic.h" +#include "threads/fixed_point.h" // mlfqs 관련 변경 #ifdef USERPROG #include "userprog/process.h" #endif @@ -24,10 +25,29 @@ Do not modify this value. */ #define THREAD_BASIC 0xd42df210 +/* Set reasonable depth limit (max level 8) */ +#define NICE_DEFAULT 0 +#define RECENT_CPU_DEFAULT 0 +#define LOAD_AVG_DEFAULT 0 +#define MAXDEPTH 8 + +// /* Set default for nice, recent_cpu, and load_avg */ +// #define NICE_DEFAULT 0 +// #define RECENT_CPU_DEFAULT 0 +// #define LOAD_AVG_DEFAULT 0 + +/* List of all process */ +static struct list all_list; // mlfqs 관련 변경 + /* List of processes in THREAD_READY state, that is, processes that are ready to run but not actually running. */ static struct list ready_list; +/* List of processes in THREAD_BLOCKED state, that is, processes + that are bloked and sleeping now */ +static struct list sleep_list; // alarm-multiple 관련 변경 +static int64_t next_tick_to_awake; /* alarm-multiple 관련 변경 */ + /* Idle thread. */ static struct thread *idle_thread; @@ -53,6 +73,7 @@ static unsigned thread_ticks; /* # of timer ticks since last yield. */ If true, use multi-level feedback queue scheduler. Controlled by kernel command-line option "-o mlfqs". */ bool thread_mlfqs; +int load_avg; // mlfqs 관련 변경 static void kernel_thread (thread_func *, void *aux); @@ -108,7 +129,10 @@ thread_init (void) { /* Init the globla thread context */ lock_init (&tid_lock); list_init (&ready_list); + list_init (&all_list); // mlfqs 관련 변경 list_init (&destruction_req); + list_init (&sleep_list); // alarm-multiple 관련 변경 // initialize sleep_list + next_tick_to_awake = INT64_MAX; // alarm-multiple 관련 변경 // initialize next_tick_to_awake /* Set up a thread structure for the running thread. */ initial_thread = running_thread (); @@ -125,6 +149,7 @@ thread_start (void) { struct semaphore idle_started; sema_init (&idle_started, 0); thread_create ("idle", PRI_MIN, idle, &idle_started); + load_avg = LOAD_AVG_DEFAULT; // mlfqs 관련 변경 /* Start preemptive thread scheduling. */ intr_enable (); @@ -176,6 +201,7 @@ thread_print_stats (void) { The code provided sets the new thread's `priority' member to PRIORITY, but no actual priority scheduling is implemented. Priority scheduling is the goal of Problem 1-3. */ +/* alarm-priority, priority-fifo/preempt 관련 변경 */ tid_t thread_create (const char *name, int priority, thread_func *function, void *aux) { @@ -207,6 +233,11 @@ thread_create (const char *name, int priority, /* Add to run queue. */ thread_unblock (t); + /* after the unblocked thread added to ready list, check if current thread is still the thread with highest priority. + (check if new inserted thread has higher priority than current one) */ + check_curr_max_priority(); // alarm-priority, priority-fifo/preempt 관련 변경 + + return tid; } @@ -232,6 +263,7 @@ thread_block (void) { be important: if the caller had disabled interrupts itself, it may expect that it can atomically unblock a thread and update other data. */ +/* alarm-priority, priority-fifo/preempt 관련 변경 */ void thread_unblock (struct thread *t) { enum intr_level old_level; @@ -240,7 +272,8 @@ thread_unblock (struct thread *t) { old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); - list_push_back (&ready_list, &t->elem); + // list_push_back (&ready_list, &t->elem); + list_insert_ordered(&ready_list, &t->elem, cmp_priority, NULL); // alarm-priority, priority-fifo/preempt 관련 변경 // instead Round-Robin scheduling, insert into ready_list base on priority. t->status = THREAD_READY; intr_set_level (old_level); } @@ -280,7 +313,7 @@ thread_tid (void) { void thread_exit (void) { ASSERT (!intr_context ()); - +/* executed by process_exit in Project 2 */ #ifdef USERPROG process_exit (); #endif @@ -294,6 +327,7 @@ thread_exit (void) { /* Yields the CPU. The current thread is not put to sleep and may be scheduled again immediately at the scheduler's whim. */ +/* alarm-priority, priority-fifo/preempt 관련 변경 */ void thread_yield (void) { struct thread *curr = thread_current (); @@ -303,15 +337,77 @@ thread_yield (void) { old_level = intr_disable (); if (curr != idle_thread) - list_push_back (&ready_list, &curr->elem); + list_insert_ordered(&ready_list, &curr->elem, cmp_priority, NULL); // alarm-priority, priority-fifo/preempt 관련 변경 // instead Round-Robin scheduling, insert into ready_list base on priority. + // list_push_back (&ready_list, &curr->elem); do_schedule (THREAD_READY); intr_set_level (old_level); } +/* alarm-multiple 관련 변경 */ +/* block current thread, and insert it into sleep list */ +void +thread_sleep (int64_t ticks) { + struct thread *curr = thread_current(); + enum intr_level old_level; + ASSERT (!intr_context ()); + old_level = intr_disable (); + + ASSERT(curr != idle_thread); // check that current thread is not IDLE thread + + curr->wakeup_tick = ticks; // set current thread's local tick = ticks + update_next_tick_to_awake(ticks); // update next thread to be awakened which has minimal ticks (update_next_tick_to_awake) + list_push_back (&sleep_list, &curr->elem); // insert into sleep list + + thread_block(); // change state to BLOCKED + intr_set_level (old_level); +} + +/* alarm-multiple 관련 변경 */ +/* check every threads in the sleep list and wakeup if necessary */ +void +thread_awake(int64_t ticks){ + struct list_elem *e = list_begin(&sleep_list); + next_tick_to_awake = INT64_MAX; // initialize next_tick_to_awake + while (e != list_end(&sleep_list)){ + struct thread * t = list_entry(e, struct thread, elem); + if (t->wakeup_tick <= ticks){ + e = list_remove(&t->elem); + thread_unblock(t); // wakeup (awake) ! + } + else{ + e = list_next(e); + update_next_tick_to_awake(t->wakeup_tick); // update next_tick_to_awake if needed + } + } +} + +/* alarm-multiple 관련 변경 */ +/* update the next_tick_to_awake value if needed. + parameter 'ticks' is the local tick(wakeup_tick field) of the new thread inserted into sleep list */ +void +update_next_tick_to_awake(int64_t ticks){ + next_tick_to_awake = (next_tick_to_awake > ticks) ? ticks : next_tick_to_awake; +} + +/* alarm-multiple 관련 변경 */ +/* return the next_tick_to_awake value, in order to check which thread(in the sleep list) to awake next */ +int64_t +get_next_tick_to_awake(void){ + return next_tick_to_awake; +} + +/* alarm-priority, priority-fifo/preempt 관련 변경 */ +/* priority-donate 관련 변경 */ /* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) { - thread_current ()->priority = new_priority; + if (thread_mlfqs) // if mlfqs activated, return // mlfqs 관련 변경 + return; + struct thread *curr = thread_current(); + curr->init_priority = new_priority; + refresh_priority(); // priority-donate 관련 변경 // after apply new_priority, refresh current thread's priority + donate_priority(); // priority-donate 관련 변경 // if the current thread's priority changed due to refresh function, adjust donation (by donate again with new priority). + check_curr_max_priority(); // alarm-priority, priority-fifo/preempt 관련 변경 // check if current thread is still thread with the highest priority anymore. if not, yield ! } /* Returns the current thread's priority. */ @@ -320,33 +416,190 @@ thread_get_priority (void) { return thread_current ()->priority; } +/* alarm-priority, priority-fifo/preempt 관련 변경 */ +/* check if current thread is still the highest priority thread. if not, yield. */ +void +check_curr_max_priority(void){ + // 검증중 // 되네 + // alarm-priority, priority-fifo/preempt 관련 변경 // checking list_empty is necessary (if not, list_front: ASSERT (!list_empty (list)); FAILS and return debug-panic) + if (!list_empty(&ready_list) && thread_get_priority() < list_entry(list_front(&ready_list), struct thread, elem)->priority) // empty 확인 필요없이 begin으로만 해주면 가능. empty+front는? + thread_yield(); + + //되는거 + // alarm-priority, priority-fifo/preempt 관련 변경 + // if (thread_get_priority() < list_entry(list_begin(&ready_list), struct thread, elem)->priority) // empty 확인 필요없이 begin으로만 해주면 가능. empty+front는? + // thread_yield(); +} + +/* alarm-priority, priority-fifo/preempt 관련 변경 */ +/* compare priority of two threads. check if a has higher priority than b. */ +bool +cmp_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED){ + struct thread * t_a = list_entry(a, struct thread, elem); + struct thread * t_b = list_entry(b, struct thread, elem); + if (t_a->priority > t_b->priority) + return true; // return true, and at the called spot, a will be inserted into the list, right in front of b. list(- - - - (insert a here) b - - ) + else + return false; +} + +/* priority-donate 관련 변경 */ +/* inherit(donate) current thread's priority to the lock holder. (nested donation is limited by MAXDEPTH 8 ) */ +void +donate_priority(void){ + struct thread *target_lock_caller = thread_current(); + struct lock *target_lock = target_lock_caller->wait_on_lock; + int depth; /* impose a reasonable limit on depth of nested priority donation */ + + for (depth = 0; depth < MAXDEPTH; depth++){ + if (!target_lock) // if caller is not waiting for a lock, end of the loop + return; + target_lock->holder->priority = target_lock_caller->priority; /* donation */ + target_lock_caller = target_lock->holder; // update caller to check if further donation is needed + target_lock = target_lock_caller->wait_on_lock; // update target lock (the lock which new caller is waiting for) + } +} + +/* priority-donate 관련 변경 */ +/* remove the donors who donated its priority in order to get the lock which is now released by current thread. */ +void +remove_donors_on_released_lock(struct lock *lock){ + struct thread *curr = thread_current(); + struct list_elem *e = list_begin(&curr->donations); // list_front is not working : assertion !list_empty(list) error. (the case when current thread got 0 donations) + while (e != list_end(&curr->donations)){ + struct thread *t = list_entry(e, struct thread, donation_elem); // need to use donation_elem, instead of elem. (elem is for ready_list, sleep_list, destruction_req.) + if (t->wait_on_lock == lock) + e = list_remove(&t->donation_elem); + else + e = list_next(e); + } +} + +/* priority-donate 관련 변경 */ +/* refresh current thread's priority, after release a lock */ +void refresh_priority(void){ + struct thread *curr = thread_current(); + curr->priority = curr->init_priority; // initialize to the init_priority (its own default priority) + if (list_empty(&curr->donations)) // if there isn't any donor, return (no need to check the highest donation priority) + return; + list_sort(&curr->donations, cmp_donation_priority, NULL); // sort the donations list based on donation priority + struct thread *p = list_entry(list_front(&curr->donations), struct thread, donation_elem); // thread with the higest priority from the donations + if (p->priority > curr->init_priority) // if the highest donation priority is higher than default priority (init_priority) + curr->priority = p->priority; // boost current thread's priority to degree of the highest donation priority +} + +/* priority-donate 관련 변경 */ +/* compare donor's donation priority, in order to check who donated higher priority. + if the priority of donor a is higher than donor b, return true */ +bool cmp_donation_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED){ + struct thread * t_a = list_entry(a, struct thread, donation_elem); + struct thread * t_b = list_entry(b, struct thread, donation_elem); + if (t_a->priority > t_b->priority) + return true; + else + return false; +} + +/* mlfqs 관련 변경 */ /* Sets the current thread's nice value to NICE. */ void thread_set_nice (int nice UNUSED) { + enum intr_level old_level = intr_disable(); + struct thread *curr = thread_current(); + curr->nice = nice; + mlfqs_priority(curr); + check_curr_max_priority(); + intr_set_level(old_level); /* TODO: Your implementation goes here */ } +/* mlfqs 관련 변경 */ /* Returns the current thread's nice value. */ int thread_get_nice (void) { /* TODO: Your implementation goes here */ - return 0; + enum intr_level old_level = intr_disable(); + int nice_value = thread_current() -> nice; + intr_set_level(old_level); + return nice_value; } -/* Returns 100 times the system load average. */ +/* mlfqs 관련 변경 */ +/* Returns 100 times the system load average. rounded to the nearest integer. */ int thread_get_load_avg (void) { /* TODO: Your implementation goes here */ - return 0; + enum intr_level old_level = intr_disable(); + int load_avg_value = fp_to_int_round(mult_mixed(load_avg, 100)); + intr_set_level(old_level); + return load_avg_value; } -/* Returns 100 times the current thread's recent_cpu value. */ +/* mlfqs 관련 변경 */ +/* Returns 100 times the current thread's recent_cpu value. rounded to the nearest integer. */ int thread_get_recent_cpu (void) { /* TODO: Your implementation goes here */ - return 0; + enum intr_level old_level = intr_disable(); + struct thread *curr = thread_current(); + int recent_cpu_value = fp_to_int_round(mult_mixed(curr->recent_cpu, 100)); + intr_set_level(old_level); + return recent_cpu_value; +} + +// mlfqs 관련 변경 +/* set target thread's priority on mlfqs */ +void mlfqs_priority (struct thread *t){ + if (t == idle_thread) + return; + t->priority = fp_to_int(add_mixed(div_mixed(t->recent_cpu, -4), PRI_MAX - t->nice * 2)); } +// mlfqs 관련 변경 +/* calculate recent_cpu field for target thread, which is not idle thread */ +void mlfqs_recent_cpu (struct thread *t){ + if(t == idle_thread) // make sure that current thread is not idle thread + return; + t->recent_cpu = add_mixed(mult_fp(div_fp(mult_mixed(load_avg, 2), add_mixed(mult_mixed(load_avg, 2),1)), t->recent_cpu), t->nice); +} + +// mlfqs 관련 변경 +/* caculate load_avg which is used system-wide (not thread specific) */ +void mlfqs_load_avg (void){ + int ready_threads = list_size(&ready_list); + struct thread *curr = thread_current(); + if (curr != idle_thread) + ready_threads ++; + // ready_threads += list_size(&ready_list); + /* if current thread is not idle thread, ready_threads should include the running thread. therefore, ready_threads ++ */ + // if (curr != idle_thread) + // ready_threads ++; + load_avg = add_fp(mult_fp(div_fp(int_to_fp(59), int_to_fp(60)), load_avg), mult_mixed(div_fp(int_to_fp(1), int_to_fp(60)), ready_threads)); + if (load_avg < 0){ // load_avg는 0보다 작아질 수 없다. + load_avg = LOAD_AVG_DEFAULT; + } +} + +// mlfqs 관련 변경 +/* if current thread is not idle thread, recent_cpu ++ */ +void mlfqs_increment (void){ + struct thread *curr = thread_current(); + if (curr != idle_thread) + curr->recent_cpu = add_mixed(curr->recent_cpu, 1); +} + +// mlfqs 관련 변경 +// recalculate every thread's recent_cpu & priority +void mlfqs_recalc(void) +{ + struct list_elem *e; + for(e = list_begin(&all_list); e != list_end(&all_list); e = list_next(e)){ + mlfqs_recent_cpu(list_entry(e, struct thread, all_elem)); + mlfqs_priority(list_entry(e, struct thread, all_elem)); + } +} + + /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by @@ -409,6 +662,18 @@ init_thread (struct thread *t, const char *name, int priority) { t->tf.rsp = (uint64_t) t + PGSIZE - sizeof (void *); t->priority = priority; t->magic = THREAD_MAGIC; + + /* priority-donate 관련 변경 */ + /* initialize fields for priority donation */ + t->init_priority = priority; + t->wait_on_lock = NULL; + list_init(&t->donations); + /* mlfqs 관련 변경 */ + t->nice = NICE_DEFAULT; + t->recent_cpu = RECENT_CPU_DEFAULT; + if(t!= idle_thread){ + list_push_back (&all_list, &t->all_elem); + } } /* Chooses and returns the next thread to be scheduled. Should @@ -552,6 +817,7 @@ schedule (void) { /* Start new time slice. */ thread_ticks = 0; +/* schedule willbe execute by process_activate() in Project 2*/ #ifdef USERPROG /* Activate the new address space. */ process_activate (next); @@ -567,6 +833,7 @@ schedule (void) { schedule(). */ if (curr && curr->status == THREAD_DYING && curr != initial_thread) { ASSERT (curr != next); + list_remove(&curr->all_elem); //mlfqs 관련 변경 // 여기가 6 FAIL의 원인이었음 list_push_back (&destruction_req, &curr->elem); }