From 15e726a158eab8432065dcc61bcc92bdb64019e1 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 24 May 2022 02:29:11 +0000 Subject: [PATCH 1/6] -- --- devices/timer.c | 3 ++ include/threads/thread.h | 8 +++++ threads/build/Makefile | 64 ++++++++++++++++++++++++++++++++++++++++ threads/thread.c | 52 ++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 threads/build/Makefile diff --git a/devices/timer.c b/devices/timer.c index 796f5a8..97e00eb 100644 --- a/devices/timer.c +++ b/devices/timer.c @@ -95,6 +95,8 @@ timer_sleep (int64_t ticks) { ASSERT (intr_get_level () == INTR_ON); while (timer_elapsed (start) < ticks) thread_yield (); + // if (timer_elapsed(start) < ticks) + // thread_sleep(start+ticks); // 변경사항 } /* Suspends execution for approximately MS milliseconds. */ @@ -126,6 +128,7 @@ static void timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); + // thread_awake(ticks); // 변경사항 } /* Returns true if LOOPS iterations waits for more than one timer diff --git a/include/threads/thread.h b/include/threads/thread.h index 33b46e6..fb9295e 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -91,6 +91,8 @@ struct thread { enum thread_status status; /* Thread state. */ char name[16]; /* Name (for debugging purposes). */ int priority; /* Priority. */ + int64_t wakeup_tick; /* 변경사항 */ + /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ @@ -143,4 +145,10 @@ int thread_get_load_avg (void); void do_iret (struct intr_frame *tf); +// /* 변경사항 */ +// 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); + #endif /* threads/thread.h */ diff --git a/threads/build/Makefile b/threads/build/Makefile new file mode 100644 index 0000000..b8a8503 --- /dev/null +++ b/threads/build/Makefile @@ -0,0 +1,64 @@ +# -*- makefile -*- + +SRCDIR = ../.. + +all: os.dsk + +include ../../Make.config +include ../Make.vars +include ../../tests/Make.tests + +# Compiler and assembler options. +os.dsk: CPPFLAGS += -I$(SRCDIR)/lib/kernel + +# Core kernel. +include ../../threads/targets.mk +# User process code. +include ../../userprog/targets.mk +# Virtual memory code. +include ../../vm/targets.mk +# Filesystem code. +include ../../filesys/targets.mk +# Library code shared between kernel and user programs. +include ../../lib/targets.mk +# Kernel-specific library code. +include ../../lib/kernel/targets.mk +# Device driver code. +include ../../devices/targets.mk + +SOURCES = $(foreach dir,$(KERNEL_SUBDIRS),$($(dir)_SRC)) +OBJECTS = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SOURCES))) +DEPENDS = $(patsubst %.o,%.d,$(OBJECTS)) + +threads/kernel.lds.s: CPPFLAGS += -P +threads/kernel.lds.s: threads/kernel.lds.S + +kernel.o: threads/kernel.lds.s $(OBJECTS) + $(LD) $(LDFLAGS) -T $< -o $@ $(OBJECTS) + +kernel.bin: kernel.o + $(OBJCOPY) -O binary -R .note -R .comment -S $< $@.tmp + dd if=$@.tmp of=$@ bs=4096 conv=sync + rm $@.tmp + +threads/loader.o: threads/loader.S kernel.bin + $(CC) -c $< -o $@ $(ASFLAGS) $(CPPFLAGS) $(DEFINES) -DKERNEL_LOAD_PAGES=`perl -e 'print +(-s "kernel.bin") / 4096;'` + +loader.bin: threads/loader.o + $(LD) $(LDFLAGS) -N -e start -Ttext 0x7c00 --oformat binary -o $@ $< + +os.dsk: loader.bin kernel.bin + cat $^ > $@ + +clean:: + rm -f $(OBJECTS) $(DEPENDS) + rm -f threads/loader.o threads/kernel.lds.s threads/loader.d + rm -f kernel.o kernel.lds.s + rm -f kernel.bin loader.bin os.dsk + rm -f bochsout.txt bochsrc.txt + rm -f results grade + +Makefile: $(SRCDIR)/Makefile.build + cp $< $@ + +-include $(DEPENDS) diff --git a/threads/thread.c b/threads/thread.c index bc9e260..f2fbbd9 100644 --- a/threads/thread.c +++ b/threads/thread.c @@ -28,6 +28,10 @@ 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; // 변경사항 + /* Idle thread. */ static struct thread *idle_thread; @@ -44,6 +48,7 @@ static struct list destruction_req; 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 int64_t next_tick_to_wakeup; /* 변경사항 */ /* Scheduling. */ #define TIME_SLICE 4 /* # of timer ticks to give each thread. */ @@ -109,6 +114,7 @@ thread_init (void) { lock_init (&tid_lock); list_init (&ready_list); list_init (&destruction_req); + // list_init (&sleep_list); // 변경사항 /* Set up a thread structure for the running thread. */ initial_thread = running_thread (); @@ -308,6 +314,52 @@ thread_yield (void) { intr_set_level (old_level); } +// /* 변경사항 */ +// void +// thread_sleep (int64_t ticks) { +// struct thread *curr; +// enum intr_level old_level; + +// // ASSERT (!intr_context ()); + +// old_level = intr_disable (); +// curr = thread_current(); +// ASSERT(curr != idle_thread); +// // if (curr != idle_thread) +// curr->wakeup_tick = ticks; +// list_push_back (&ready_list, &curr->elem); +// // do_schedule (THREAD_READY); +// thread_block(); +// intr_set_level (old_level); +// } + +// /* 변경사항 */ +// void +// thread_awake(int64_t ticks){ +// struct list_elem *e = list_begin(&sleep_list); +// while (e != list_end(&sleep_list)){ +// struct thread * now = list_entry(e, struct thread, elem); +// if (now->wakeup_tick <= ticks){ +// e = list_remove(e); // list_remove 함수가 remove 후에 list_next 역할도 해줌 +// thread_unblock(now); +// } +// else +// e = list_next(e); +// } +// } + +// /* 변경사항 */ +// void +// update_next_tick_to_wakeup(int64_t ticks){ +// next_tick_to_wakeup = ticks; +// } + +// /* 변경사항 */ +// int64_t +// get_next_tick_to_wakeup(void){ +// return next_tick_to_wakeup; +// } + /* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) { From ff92747578062edfb4ff304383c6afd974c1f137 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 24 May 2022 04:23:31 +0000 Subject: [PATCH 2/6] alarm-multiple complete --- devices/timer.c | 14 ++++-- include/threads/thread.h | 12 ++--- threads/build/Makefile | 64 -------------------------- threads/thread.c | 98 ++++++++++++++++++++-------------------- 4 files changed, 65 insertions(+), 123 deletions(-) delete mode 100644 threads/build/Makefile diff --git a/devices/timer.c b/devices/timer.c index 97e00eb..919057c 100644 --- a/devices/timer.c +++ b/devices/timer.c @@ -90,13 +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); // 변경사항 + thread_sleep(start+ticks); // alarm-multiple 관련 변경 // current time + ticks(required) = time to be awaken => local ticks } /* Suspends execution for approximately MS milliseconds. */ @@ -128,7 +130,9 @@ static void timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); - // thread_awake(ticks); // 변경사항 + /* 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/thread.h b/include/threads/thread.h index fb9295e..6b30882 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -91,7 +91,7 @@ struct thread { enum thread_status status; /* Thread state. */ char name[16]; /* Name (for debugging purposes). */ int priority; /* Priority. */ - int64_t wakeup_tick; /* 변경사항 */ + int64_t wakeup_tick; /* Local ticks (minimum ticks required before awakened ) */ /* alarm-multiple 관련 변경 */ /* Shared between thread.c and synch.c. */ @@ -145,10 +145,10 @@ int thread_get_load_avg (void); void do_iret (struct intr_frame *tf); -// /* 변경사항 */ -// 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-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); #endif /* threads/thread.h */ diff --git a/threads/build/Makefile b/threads/build/Makefile deleted file mode 100644 index b8a8503..0000000 --- a/threads/build/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# -*- makefile -*- - -SRCDIR = ../.. - -all: os.dsk - -include ../../Make.config -include ../Make.vars -include ../../tests/Make.tests - -# Compiler and assembler options. -os.dsk: CPPFLAGS += -I$(SRCDIR)/lib/kernel - -# Core kernel. -include ../../threads/targets.mk -# User process code. -include ../../userprog/targets.mk -# Virtual memory code. -include ../../vm/targets.mk -# Filesystem code. -include ../../filesys/targets.mk -# Library code shared between kernel and user programs. -include ../../lib/targets.mk -# Kernel-specific library code. -include ../../lib/kernel/targets.mk -# Device driver code. -include ../../devices/targets.mk - -SOURCES = $(foreach dir,$(KERNEL_SUBDIRS),$($(dir)_SRC)) -OBJECTS = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SOURCES))) -DEPENDS = $(patsubst %.o,%.d,$(OBJECTS)) - -threads/kernel.lds.s: CPPFLAGS += -P -threads/kernel.lds.s: threads/kernel.lds.S - -kernel.o: threads/kernel.lds.s $(OBJECTS) - $(LD) $(LDFLAGS) -T $< -o $@ $(OBJECTS) - -kernel.bin: kernel.o - $(OBJCOPY) -O binary -R .note -R .comment -S $< $@.tmp - dd if=$@.tmp of=$@ bs=4096 conv=sync - rm $@.tmp - -threads/loader.o: threads/loader.S kernel.bin - $(CC) -c $< -o $@ $(ASFLAGS) $(CPPFLAGS) $(DEFINES) -DKERNEL_LOAD_PAGES=`perl -e 'print +(-s "kernel.bin") / 4096;'` - -loader.bin: threads/loader.o - $(LD) $(LDFLAGS) -N -e start -Ttext 0x7c00 --oformat binary -o $@ $< - -os.dsk: loader.bin kernel.bin - cat $^ > $@ - -clean:: - rm -f $(OBJECTS) $(DEPENDS) - rm -f threads/loader.o threads/kernel.lds.s threads/loader.d - rm -f kernel.o kernel.lds.s - rm -f kernel.bin loader.bin os.dsk - rm -f bochsout.txt bochsrc.txt - rm -f results grade - -Makefile: $(SRCDIR)/Makefile.build - cp $< $@ - --include $(DEPENDS) diff --git a/threads/thread.c b/threads/thread.c index f2fbbd9..84c4ebe 100644 --- a/threads/thread.c +++ b/threads/thread.c @@ -30,7 +30,8 @@ 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; // 변경사항 +static struct list sleep_list; // alarm-multiple 관련 변경 +static int64_t next_tick_to_awake; /* alarm-multiple 관련 변경 */ /* Idle thread. */ static struct thread *idle_thread; @@ -48,7 +49,6 @@ static struct list destruction_req; 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 int64_t next_tick_to_wakeup; /* 변경사항 */ /* Scheduling. */ #define TIME_SLICE 4 /* # of timer ticks to give each thread. */ @@ -114,7 +114,8 @@ thread_init (void) { lock_init (&tid_lock); list_init (&ready_list); list_init (&destruction_req); - // list_init (&sleep_list); // 변경사항 + list_init (&sleep_list); // alarm-multiple 관련 변경 // initialize sleep_list + next_tick_to_awake = INT64_MAX; // alarm-multiple 관련 변경 /* Set up a thread structure for the running thread. */ initial_thread = running_thread (); @@ -314,51 +315,52 @@ thread_yield (void) { intr_set_level (old_level); } -// /* 변경사항 */ -// void -// thread_sleep (int64_t ticks) { -// struct thread *curr; -// enum intr_level old_level; - -// // ASSERT (!intr_context ()); - -// old_level = intr_disable (); -// curr = thread_current(); -// ASSERT(curr != idle_thread); -// // if (curr != idle_thread) -// curr->wakeup_tick = ticks; -// list_push_back (&ready_list, &curr->elem); -// // do_schedule (THREAD_READY); -// thread_block(); -// intr_set_level (old_level); -// } - -// /* 변경사항 */ -// void -// thread_awake(int64_t ticks){ -// struct list_elem *e = list_begin(&sleep_list); -// while (e != list_end(&sleep_list)){ -// struct thread * now = list_entry(e, struct thread, elem); -// if (now->wakeup_tick <= ticks){ -// e = list_remove(e); // list_remove 함수가 remove 후에 list_next 역할도 해줌 -// thread_unblock(now); -// } -// else -// e = list_next(e); -// } -// } - -// /* 변경사항 */ -// void -// update_next_tick_to_wakeup(int64_t ticks){ -// next_tick_to_wakeup = ticks; -// } - -// /* 변경사항 */ -// int64_t -// get_next_tick_to_wakeup(void){ -// return next_tick_to_wakeup; -// } +/* alarm-multiple 관련 변경 */ +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 + // if (curr != 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 관련 변경 */ +void +thread_awake(int64_t ticks){ + struct list_elem *e = list_begin(&sleep_list); /* begin?front? */ + 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); // list_remove 함수가 remove 후에 list_next 역할도 해줌 + thread_unblock(t); // wakeup (awake) ! + } + else{ + e = list_next(e); + update_next_tick_to_awake(t->wakeup_tick); // update : who's the first thread to be awaken in the sleep list? + } + } +} + +/* alarm-multiple 관련 변경 */ +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 관련 변경 */ +int64_t +get_next_tick_to_awake(void){ + return next_tick_to_awake; +} /* Sets the current thread's priority to NEW_PRIORITY. */ void From c5a005117a9c6f023b6072888a1d0d4aa8a91c75 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 24 May 2022 06:17:10 +0000 Subject: [PATCH 3/6] alarm-priority, priority-fifo, preempt done --- include/threads/thread.h | 4 ++++ threads/thread.c | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/threads/thread.h b/include/threads/thread.h index 6b30882..370215d 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -151,4 +151,8 @@ 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 test_max_priority(void); +bool cmp_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED); + #endif /* threads/thread.h */ diff --git a/threads/thread.c b/threads/thread.c index 84c4ebe..7448473 100644 --- a/threads/thread.c +++ b/threads/thread.c @@ -183,6 +183,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) { @@ -213,6 +214,9 @@ thread_create (const char *name, int priority, /* Add to run queue. */ thread_unblock (t); + test_max_priority(); // alarm-priority, priority-fifo/preempt 관련 변경 + // 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) return tid; } @@ -239,6 +243,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; @@ -247,7 +252,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); } @@ -301,6 +307,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 (); @@ -310,7 +317,8 @@ 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); } @@ -323,12 +331,12 @@ thread_sleep (int64_t ticks) { ASSERT (!intr_context ()); old_level = intr_disable (); - ASSERT(curr != idle_thread); // check that current thread is not IDLE thread - // if (curr != idle_thread) + // ASSERT(curr != idle_thread); // check that current thread is not IDLE thread + if (curr != 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); } @@ -363,9 +371,12 @@ get_next_tick_to_awake(void){ } /* Sets the current thread's priority to NEW_PRIORITY. */ +/* alarm-priority, priority-fifo/preempt 관련 변경 */ void thread_set_priority (int new_priority) { + // ready_list 가 비어있지 않은지 확인 thread_current ()->priority = new_priority; + test_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. */ @@ -401,6 +412,23 @@ thread_get_recent_cpu (void) { return 0; } +/* alarm-priority, priority-fifo/preempt 관련 변경 */ +void test_max_priority(void){ + if (!list_empty(&ready_list) && thread_current()->priority < list_entry(list_front(&ready_list), struct thread, elem)->priority) + thread_yield(); // alarm-priority, priority-fifo/preempt 관련 변경 // checking list_empty is necessary (if not, list_front: ASSERT (!list_empty (list)); FAILS and return debug-panic) +} + +/* 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; +} + /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by From b5ad1682f91e3609df3db69c21c0e0ab5c67130d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 24 May 2022 07:38:39 +0000 Subject: [PATCH 4/6] priority-sema,condvar --- include/threads/synch.h | 3 +++ threads/synch.c | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 8 deletions(-) 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/threads/synch.c b/threads/synch.c index 8ca3230..d77e8eb 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++; + test_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); } @@ -272,6 +277,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 +288,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 +302,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 +310,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 +330,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; +} From fc771e41d181d47a67273db19988db191e12dde5 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 25 May 2022 07:04:45 +0000 Subject: [PATCH 5/6] priority-donate complete --- include/threads/thread.h | 12 ++++- threads/synch.c | 30 +++++++---- threads/thread.c | 107 ++++++++++++++++++++++++++++++++++----- 3 files changed, 127 insertions(+), 22 deletions(-) diff --git a/include/threads/thread.h b/include/threads/thread.h index 370215d..8ebb266 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -92,6 +92,10 @@ struct thread { char name[16]; /* Name (for debugging purposes). */ int priority; /* Priority. */ int64_t wakeup_tick; /* Local ticks (minimum ticks required before awakened ) */ /* alarm-multiple 관련 변경 */ + 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 관련 변경 /* Shared between thread.c and synch.c. */ @@ -152,7 +156,13 @@ void update_next_tick_to_awake(int64_t ticks); int64_t get_next_tick_to_awake(void); /* alarm-priority, priority-fifo/preempt 관련 변경 */ -void test_max_priority(void); +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); + #endif /* threads/thread.h */ diff --git a/threads/synch.c b/threads/synch.c index d77e8eb..cb3a36a 100644 --- a/threads/synch.c +++ b/threads/synch.c @@ -117,7 +117,7 @@ sema_up (struct semaphore *sema) { thread_unblock (list_entry (list_pop_front (&sema->waiters), struct thread, elem)); } sema->value++; - test_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 ! + 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); } @@ -187,14 +187,22 @@ 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 (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 @@ -210,8 +218,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; } @@ -222,13 +230,17 @@ 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)); + ASSERT (lock_held_by_current_thread (lock)); // check if current thread is the lock holder - lock->holder = NULL; - sema_up (&lock->semaphore); + lock->holder = NULL; // make lock's holder field NULL. time to release + 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 diff --git a/threads/thread.c b/threads/thread.c index 7448473..704e474 100644 --- a/threads/thread.c +++ b/threads/thread.c @@ -24,6 +24,9 @@ Do not modify this value. */ #define THREAD_BASIC 0xd42df210 +/* Set reasonable depth limit (max level 8) */ +#define MAXDEPTH 8 + /* List of processes in THREAD_READY state, that is, processes that are ready to run but not actually running. */ static struct list ready_list; @@ -115,7 +118,7 @@ thread_init (void) { list_init (&ready_list); list_init (&destruction_req); list_init (&sleep_list); // alarm-multiple 관련 변경 // initialize sleep_list - next_tick_to_awake = INT64_MAX; // alarm-multiple 관련 변경 + 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 (); @@ -214,9 +217,11 @@ thread_create (const char *name, int priority, /* Add to run queue. */ thread_unblock (t); - test_max_priority(); // alarm-priority, priority-fifo/preempt 관련 변경 - // 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) + + /* 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; } @@ -324,6 +329,7 @@ thread_yield (void) { } /* alarm-multiple 관련 변경 */ +/* block current thread, and insert it into sleep list */ void thread_sleep (int64_t ticks) { struct thread *curr = thread_current(); @@ -342,46 +348,58 @@ thread_sleep (int64_t ticks) { } /* 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); /* begin?front? */ + struct list_elem *e = list_begin(&sleep_list); 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); // list_remove 함수가 remove 후에 list_next 역할도 해줌 + e = list_remove(&t->elem); thread_unblock(t); // wakeup (awake) ! } else{ e = list_next(e); - update_next_tick_to_awake(t->wakeup_tick); // update : who's the first thread to be awaken in the sleep list? + 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; } -/* Sets the current thread's priority to NEW_PRIORITY. */ /* alarm-priority, priority-fifo/preempt 관련 변경 */ +/* priority-donate 관련 변경 */ +/* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) { // ready_list 가 비어있지 않은지 확인 - thread_current ()->priority = new_priority; - test_max_priority(); // alarm-priority, priority-fifo/preempt 관련 변경 // check if current thread is still thread with the highest priority anymore. if not, yield ! + struct thread *curr = thread_current(); + int curr_priority_before_refresh = curr->priority; + curr->priority = new_priority; + curr->init_priority = new_priority; + refresh_priority(); // priority-donate 관련 변경 // after apply new_priority, refresh current thread's priority + if (curr_priority_before_refresh != curr->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. */ int thread_get_priority (void) { + /* if there's any priority donated by other thread, return higher one */ return thread_current ()->priority; } @@ -413,14 +431,17 @@ thread_get_recent_cpu (void) { } /* alarm-priority, priority-fifo/preempt 관련 변경 */ -void test_max_priority(void){ +/* check if current thread is still the highest priority thread. if not, yield. */ +void +check_curr_max_priority(void){ if (!list_empty(&ready_list) && thread_current()->priority < list_entry(list_front(&ready_list), struct thread, elem)->priority) thread_yield(); // alarm-priority, priority-fifo/preempt 관련 변경 // checking list_empty is necessary (if not, list_front: ASSERT (!list_empty (list)); FAILS and return debug-panic) } /* 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){ +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) @@ -429,6 +450,63 @@ bool cmp_priority(const struct list_elem *a, const struct list_elem *b, void *au 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; +} + /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by @@ -491,6 +569,11 @@ 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); } /* Chooses and returns the next thread to be scheduled. Should From 04b4bb97a9b228a467c8d376f4a314ddf9539535 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 26 May 2022 13:57:29 +0000 Subject: [PATCH 6/6] =?UTF-8?q?advanced=20=EC=98=AC=ED=8C=A8=EC=8A=A4=20!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devices/timer.c | 10 ++ include/threads/fixed_point.h | 73 ++++++++++++++ include/threads/thread.h | 21 +++- threads/synch.c | 17 ++-- threads/thread.c | 182 ++++++++++++++++++++++++++-------- 5 files changed, 251 insertions(+), 52 deletions(-) create mode 100644 include/threads/fixed_point.h diff --git a/devices/timer.c b/devices/timer.c index 919057c..50c308e 100644 --- a/devices/timer.c +++ b/devices/timer.c @@ -130,6 +130,16 @@ 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 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/thread.h b/include/threads/thread.h index 8ebb266..a1c2a9c 100644 --- a/include/threads/thread.h +++ b/include/threads/thread.h @@ -91,15 +91,17 @@ struct thread { enum thread_status status; /* Thread state. */ char name[16]; /* Name (for debugging purposes). */ int priority; /* Priority. */ - int64_t wakeup_tick; /* Local ticks (minimum ticks required before awakened ) */ /* alarm-multiple 관련 변경 */ + /* 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 관련 변경 - - - /* Shared between thread.c and synch.c. */ - struct list_elem elem; /* List element. */ + 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. */ @@ -113,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. @@ -165,4 +168,12 @@ 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 cb3a36a..ca6604d 100644 --- a/threads/synch.c +++ b/threads/synch.c @@ -195,10 +195,12 @@ lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); // no recursive acquisition (cannot acquire lock while already holding the same lock) - 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(); + 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); curr->wait_on_lock = NULL; // after acquired the lock, set NULL on wait_on_lock field @@ -236,10 +238,11 @@ void lock_release (struct lock *lock) { ASSERT (lock != NULL); 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 - remove_donors_on_released_lock(lock); // remove the donors on released lock from current thread's donations - refresh_priority(); // refresh current thread's priority + 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 } diff --git a/threads/thread.c b/threads/thread.c index 704e474..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 @@ -25,8 +26,19 @@ #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; @@ -61,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); @@ -116,6 +129,7 @@ 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 @@ -135,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 (); @@ -298,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 @@ -337,12 +352,12 @@ thread_sleep (int64_t ticks) { ASSERT (!intr_context ()); old_level = intr_disable (); - // ASSERT(curr != idle_thread); // check that current thread is not IDLE thread - if (curr != idle_thread){ + 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); } @@ -351,7 +366,8 @@ thread_sleep (int64_t ticks) { /* 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); + 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){ @@ -385,57 +401,34 @@ get_next_tick_to_awake(void){ /* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) { - // ready_list 가 비어있지 않은지 확인 + if (thread_mlfqs) // if mlfqs activated, return // mlfqs 관련 변경 + return; struct thread *curr = thread_current(); - int curr_priority_before_refresh = curr->priority; - curr->priority = new_priority; curr->init_priority = new_priority; refresh_priority(); // priority-donate 관련 변경 // after apply new_priority, refresh current thread's priority - if (curr_priority_before_refresh != curr->priority) - donate_priority(); // priority-donate 관련 변경 // if the current thread's priority changed due to refresh function, adjust donation (by donate again with new 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. */ int thread_get_priority (void) { - /* if there's any priority donated by other thread, return higher one */ return thread_current ()->priority; } -/* Sets the current thread's nice value to NICE. */ -void -thread_set_nice (int nice UNUSED) { - /* TODO: Your implementation goes here */ -} - -/* Returns the current thread's nice value. */ -int -thread_get_nice (void) { - /* TODO: Your implementation goes here */ - return 0; -} - -/* Returns 100 times the system load average. */ -int -thread_get_load_avg (void) { - /* TODO: Your implementation goes here */ - return 0; -} - -/* Returns 100 times the current thread's recent_cpu value. */ -int -thread_get_recent_cpu (void) { - /* TODO: Your implementation goes here */ - return 0; -} - /* alarm-priority, priority-fifo/preempt 관련 변경 */ /* check if current thread is still the highest priority thread. if not, yield. */ void check_curr_max_priority(void){ - if (!list_empty(&ready_list) && thread_current()->priority < list_entry(list_front(&ready_list), struct thread, elem)->priority) - thread_yield(); // alarm-priority, priority-fifo/preempt 관련 변경 // checking list_empty is necessary (if not, list_front: ASSERT (!list_empty (list)); FAILS and return debug-panic) + // 검증중 // 되네 + // 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 관련 변경 */ @@ -507,6 +500,106 @@ bool cmp_donation_priority(const struct list_elem *a, const struct list_elem *b, 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 */ + enum intr_level old_level = intr_disable(); + int nice_value = thread_current() -> nice; + intr_set_level(old_level); + return nice_value; +} + +/* mlfqs 관련 변경 */ +/* Returns 100 times the system load average. rounded to the nearest integer. */ +int +thread_get_load_avg (void) { + /* TODO: Your implementation goes here */ + 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; +} + +/* 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 */ + 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 @@ -569,11 +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 @@ -717,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); @@ -732,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); }