๐ฉ๐ปโ๐ป GITHUB ๋ ํฌ์งํ ๋ฆฌ
๐ฉ๐ปโ๐ป GITHUB alarm clock ์ด์
๊ธฐ๋ณธ์ ์ธ ์๋ฃ๋ค์ ์ ๊ธ ํ์ด์ง๋ฅผ ์ฐธ๊ณ ํ์๊ณ , ๋ถ๊ฐ์ ์ธ ์๋ฃ๋ฅผ ๊ณต์ ๋๋ฆฌ๊ฒ ์ต๋๋ค!
์ง์ ์กฐ์ฐจ ๋ชปํ๊ฒ ์๋... ๋ง์ด ๋์ ๋ฐ์ ์ ๋ฐฐ๋๋ค์ ์๋ฃ์ ๋๋ค (๊ฐ์ฌํฉ๋๋ค๐)
์ ๋ ์ด ์์๋ก ์ฐธ๊ณ ํ๋ฉด์ ํ๋ก์ ํธ์ ์ง์ ํ์์ต๋๋ค!
์ด์์ฒด์ ์๋ ์คํ์ค์ธ ์ค๋ ๋๋ฅผ ์ ์ ์ฌ์ ๋ค๊ฐ ์ผ์ ์๊ฐ์ด ์ง๋๋ฉด ๋ค์ ๊นจ์ฐ๋๋ก ํ๋ ๊ธฐ๋ฅ์ด ์๋๋ฐ, ์ด ๊ธฐ๋ฅ์ Alarm Clock ์ด๋ผ๊ณ ํ๋ค.
ํ์ฌ ํํ ์ค์ ๊ตฌํ๋์ด ์๋ Alarm Clock ๊ธฐ๋ฅ์ busy-waiting ๋ฐฉ์์ผ๋ก ๊ตฌํ๋์ด ์๋ค. ์ด๋ ๋งค์ฐ ๋นํจ์จ์ ์ผ๋ก ๋ง์ CPU ์๊ฐ์ ๋ญ๋นํ๊ฒ ํ๋ค. ๋ฐ๋ผ์ ์ด ๋ฐฉ์์ ๊ฐ์ ํ๋ ๊ฒ์ด ๊ณผ์ ์ ๋ชฉํ์ด๋ค.
busy-waiting ๋ฐฉ์์์ sleep ๋ช
๋ น์ ๋ฐ์ ์ค๋ ๋์ ์งํ ํ๋ฆ์ ์๋์ ๊ฐ์ด ์งํ๋๋ค.
์ ์ด๋ฌ
-> ๊นจ์ด๋จ
-> ์๊ฐํ์ธ
-> ๋ค์์
-> ๊นจ์ด๋จ
-> ์๊ฐํ์ธ
-> ... -> ๊นจ์ด๋จ
-> ์๊ฐํ์ธ(์ผ์ด๋ ์๊ฐ)
-> ๊นจ์ด๋จ
Ex) Thread A๊ฐ 5tick ๋ค์ ํน์ ์์ ์ ์คํํ๊ธธ ์ํ๋ค๊ณ ํ์. ๋งค Tick๋ง๋ค Thread A๊ฐ ์คํ๋์ด 5tick์ด ๋์๋์ง๋ฅผ ํ์ธํ๋ค.
์ค๋ ๋์ ์ํ๊ฐ running state
์ ready state
๋ฅผ ๋ฐ๋ณตํจ์ ๋ณผ ์ ์๋ค. running state ์์ sleep ๋ช
๋ น์ ๋ฐ์ ์ค๋ ๋๋ ready state ๊ฐ ๋์ด ready queue ์ ์ถ๊ฐ๋๊ณ ready queue ์ ์๋ ์ค๋ ๋๋ค์ ์์ ์ ์ฐจ๋ก๊ฐ ๋๋ฉด ์ผ์ด๋ ์๊ฐ์ด ๋์๋์ง์ ์๊ด์์ด ๊นจ์์ ธ running state ๊ฐ ๋๋ค. ์ด๋ ๊ฒ running state ๊ฐ ๋ ์ค๋ ๋๋ ์์ ์ด ์ผ์ด๋ ์๊ฐ์ด ๋์๋์ง ํ์ธํ๊ณ ์์ง ์ผ์ด๋ ์๊ฐ์ด ์ ๋๋ค๋ฉด ๋ค์ ready state ๋ก ์ ํํ๋ค.
=> ์ด๋ฌํ ๋ฐฉ์์ CPU ์์์ ๋ญ๋นํ๊ณ , ๋ค๋ฅธ ์ค๋ ๋๊ฐ ์คํ๋๋ ๊ธฐํ๋ฅผ ์ค์ฌ ์ฑ๋ฅ ์ ํ๋ฅผ ์ผ๊ธฐํ ์ ์๋ค.
๋ณ๊ฒฝ ๋ฐฉ์
ํ์ฌ
=> busy-waiting
์ค๋ ๋๋ฅผ ๊นจ์ด ํ ์ผ์ด๋ ์๊ฐ์ธ์ง ํ์ธํ๋ค. ๊ทธ๋ฆฌ๊ณ ์์ง ์ผ์ด๋ ์๊ฐ์ด ์๋๋ผ๋ฉด ๋ค์ ready state๋ก ๋ณด๋ธ๋ค.
๋ณ๊ฒฝ์
=> sleep-awake
์ด๋ฌํ ๋นํจ์จ์ ํด๊ฒฐํ๋ ค๋ฉด ์ ์ด ๋ ์ค๋ ๋๋ฅผ ready state
๊ฐ ์๋ block state
๋ก ๋์ด์ ๊นจ์ด๋ ์๊ฐ์ด ๋๊ธฐ ์ ๊น์ง๋ ์ค์ผ์ค๋ง์ ํฌํจ๋์ง ์๋๋ก ํ๊ณ , ๊นจ์ด๋ ์๊ฐ์ด ๋์์ ๋ ready state ๋ก ๋ฐ๊พธ์ด ์ฃผ๋ฉด ๋๋ค.
void timer_sleep (int64_t ticks)
: ์ธ์๋ก ์ฃผ์ด์ง ticks ๋์ ์ค๋ ๋๋ฅผ block
void thread_sleep(int64_t ticks)
: Thread๋ฅผ blocked ์ํ๋ก ๋ง๋ค๊ณ sleep queue์ ์ฝ์
ํ์ฌ ๋๊ธฐ
void thread_awake(int64_t ticks)
: Sleep queue์์ ๊นจ์์ผ ํ thread๋ฅผ ์ฐพ์์ wake
void update_next_tick_to_awake(int64_t ticks)
: Thread๋ค์ด ๊ฐ์ง tick ๊ฐ์์ ์ต์ ๊ฐ์ ์ ์ฅ
int64_t get_next_tick_to_awake(void)
: ์ต์ tick๊ฐ์ ๋ฐํ
struct thread
static struct list sleep_list;
int64_t next_tick_to_awake = INT64_MAX;
๋์ ์์ ์ค
Source ./activate
์์น๊ฒ ํ๋๋ฒ!!
๋ฃจํธ ๋๋ ํ ๋ฆฌ๋ก ์ด๋
code .bashrc
์
๋ ฅ
ํ์ผ ์ ์ผ ๋ฐ์ ๋ณธ์ธ์ source activate ๊ฒฝ๋ก ์ถ๊ฐ
/pintos ๊ฒฝ๋ก์์ source ./activate
(์ฌ์ ํ๊ฒฝ ์ค์ ์ ํ๋ค๋ฉด ์ํด์ค๋ ๋๋ค!)
threads ํด๋ ๋ค์ด๊ฐ์ make clean
make check
๋ฅผ ์ํํ๋ฉด Test Case๋ค์ ๋ํด์ ์ฑ์ ์ ์ํํ๋ค.
Test Case ํ๊ฐ์ง๋ง ๋๋ฆฌ๊ณ ์ถ๋ค๋ฉด, pintos/(ํ๋ก์ ํธ๋ช
)/build์ ๋ค์ด๊ฐ์ ์๋ ๋ช
๋ น์ด๋ฅผ ์ํํ๋ฉด ๋๋ค.
pintos -T (Timout์ด ๊ฑธ๋ฆฌ๋ ์๊ฐ) -- -q -run (Test case ์ด๋ฆ)
ex) pintos -T 30 -- -q run alarm-multiple
โถ๏ธ Thread ์์ ์ด ๊นจ์ด๋์ผ ํ tick์ ์ ์ฅํ๋ wakeup_tick ๋ณ์๋ฅผ ์ถ๊ฐ
struct thread {
/* Owned by thread.c. */
tid_t tid; /* Thread identifier. */
enum thread_status status; /* Thread state. */
char name[16]; /* Name (for debugging purposes). */
int priority; /* Priority. */
int64_t wakeup_tick; /** project1-Alarm Clock */
.
.
.
โถ๏ธ Sleep queue ์๋ฃ๊ตฌ์กฐ ์ถ๊ฐ
โถ๏ธ next_tick_to_awake ์ ์ญ ๋ณ์ ์ถ๊ฐ
โ sleep_list์์ ๋๊ธฐ์ค์ธ ์ค๋ ๋๋ค์ wakeup_tick ๊ฐ ์ค ์ต์๊ฐ์ ์ ์ฅ
.
.
.
/* Random value for basic thread
Do not modify this value. */
#define THREAD_BASIC 0xd42df210
/** project1-Alarm Clock */
static struct list sleep_list;
static int64_t next_tick_to_awake;
/* List of processes in THREAD_READY state, that is, processes
that are ready to run but not actually running. */
static struct list ready_list;
.
.
.
.
.
.
/** project1-Alarm Clock */
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);
void thread_init (void);
void thread_start (void);
void thread_tick (void);
void thread_print_stats (void);
.
.
.
โถ๏ธ
main()
ํจ์์์ ํธ์ถ๋๋ ์ฐ๋ ๋ ๊ด๋ จ ์ด๊ธฐํ ํจ์
โถ๏ธ Sleep queue ์๋ฃ๊ตฌ์กฐ ์ด๊ธฐํ ์ฝ๋ ์ถ๊ฐ
void
thread_init (void) {
ASSERT (intr_get_level () == INTR_OFF);
/* Reload the temporal gdt for the kernel
* This gdt does not include the user context.
* The kernel will rebuild the gdt with user context, in gdt_init (). */
struct desc_ptr gdt_ds = {
.size = sizeof (gdt) - 1,
.address = (uint64_t) gdt
};
lgdt (&gdt_ds);
/* Init the globla thread context */
lock_init (&tid_lock);
list_init (&ready_list);
list_init (&destruction_req);
list_init (&sleep_list); /** project1-Alarm Clock */
/* Set up a thread structure for the running thread. */
initial_thread = running_thread ();
init_thread (initial_thread, "main", PRI_DEFAULT);
initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid ();
}
โถ๏ธ ๊ธฐ์กด์ busy waiting์ ์ ๋ฐํ๋ ์ฝ๋ ์ญ์
โถ๏ธ Sleep queue๋ฅผ ์ด์ฉํ๋๋ก ํจ์ ์์
โ ๋ฐ์์ ๊ตฌํํ๋thread_sleep()
ํจ์ ์ฌ์ฉ
void
timer_sleep (int64_t ticks) {
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
/** project1-Alarm Clock
while (timer_elapsed (start) < ticks)
thread_yield (); */
thread_sleep (start + ticks);
}
โถ๏ธ thread๋ฅผ sleep queue์ ์ฝ์ ํ๊ณ blocked ์ํ๋ก ๋ง๋ค์ด ๋๊ธฐ
โถ๏ธ ํด๋น ๊ณผ์ ์ค์๋ ์ธํฐ๋ฝํธ๋ฅผ ๋ฐ์๋ค์ด์ง ์๋๋ค.
โถ๏ธtimer_sleep()
ํจ์์ ์ํด ํธ์ถ
/** project1-Alarm Clock */
void
thread_sleep (int64_t ticks)
{
struct thread *this;
this = thread_current();
if (this == idle_thread) // idle -> stop
{
ASSERT(0);
} else
{
enum intr_level old_level;
old_level = intr_disable(); // pause interrupt
update_next_tick_to_awake(this->wakeup_tick = ticks); // update awake ticks
list_push_back(&sleep_list, &this->elem); // push to sleep_list
thread_block(); // block this thread
intr_set_level(old_level); // continue interrupt
}
}
โถ๏ธ ๋งค tick๋ง๋ค timer ์ธํฐ๋ฝํธ ์ ํธ์ถ๋๋ ํจ์
โถ๏ธ sleep queue์์ ๊นจ์ด๋ thread๊ฐ ์๋์ง ํ์ธโ sleep queue์์ ๊ฐ์ฅ ๋นจ๋ฆฌ ๊นจ์ด๋ ์ฐ๋ ๋์ tick๊ฐ ํ์ธ
โ ์๋ค๋ฉด sleep queue๋ฅผ ์ํํ๋ฉฐ ์ฐ๋ ๋ ๊นจ์ ( ๋ฐ์์ ๊ตฌํํ๋thread_awake()
ํจ์ ์ฌ์ฉ )
static void
timer_interrupt (struct intr_frame *args UNUSED) {
ticks++;
thread_tick ();
/** project1-Alarm Clock */
if (get_next_tick_to_awake() <= ticks)
{
thread_awake(ticks);
}
}
โถ๏ธ wakeup_tick๊ฐ์ด ์ธ์๋ก ๋ฐ์ ticks๋ณด๋ค ํฌ๊ฑฐ๋ ๊ฐ์ ์ค๋ ๋๋ฅผ ๊นจ์
โถ๏ธ ํ์ฌ ๋๊ธฐ์ค์ธ ์ค๋ ๋๋ค์ wakeup_tick๋ณ์ ์ค ๊ฐ์ฅ์์ ๊ฐ์ next_tick_to_awake ์ ์ญ ๋ณ์์ ์ ์ฅ
/** project1-Alarm Clock */
void
thread_awake (int64_t wakeup_tick)
{
next_tick_to_awake = INT64_MAX;
struct list_elem *sleeping;
sleeping = list_begin(&sleep_list); // take sleeping thread
while (sleeping != list_end(&sleep_list)) { // for all sleeping threads
struct thread *th = list_entry(sleeping, struct thread, elem);
if (wakeup_tick >= th->wakeup_tick)
{
sleeping = list_remove(&th->elem); // delete thread
thread_unblock(th); // unblock thread
}
else
{
sleeping = list_next(sleeping); // move to next sleeping thread
update_next_tick_to_awake(th->wakeup_tick); // update wakeup_tick
}
}
}
โถ๏ธ next_tick_to_awake ๋ณ์๋ฅผ ์ ๋ฐ์ดํธ
/** project1-Alarm Clock */
void
update_next_tick_to_awake (int64_t ticks)
{
// find smallest tick
next_tick_to_awake = (next_tick_to_awake > ticks) ? ticks : next_tick_to_awake;
}
/** project1-Alarm Clock */
int64_t
get_next_tick_to_awake(void)
{
return next_tick_to_awake;
}
idle tick์ด 550์ผ๋ก ์ฆ๊ฐ