
์ธํธ๋ก
ํฌ๋ํํค ์ ๊ธ 9์ฃผ์ฐจ, Pintos ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉฐ ๋ฐฐ์ฐ๊ณ ๋๋ ์ ๋ค์ ๊ณต์ ํ๋ ์๋ฆฌ์ฆ์ ์ฒซ ๋ฒ์งธ ๊ธ์ ๋๋ค. Pintos ํ๋ก์ ํธ๋ ์ด๋ก ์ผ๋ก๋ง ๋ฐฐ์ฐ๋ ์ด์์ฒด์ ์ ํต์ฌ ๊ฐ๋ ๋ค์ ์ง์ ์ฝ๋๋ก ๊ตฌํํด๋ณด๋ฉด์ ๊น์ด ์ดํดํ ์์ฃผ ์ข์ ๊ธฐํ์ธ๋ฐ์. ๊ทธ ์ฒซ ๋ฒ์งธ ํํธ์ธ '์๋ ์๊ณ(Alarm Clock)' ๊ตฌํ์ ๋ํด ์ด์ผ๊ธฐํด ๋ณด๊ณ ์ ํฉ๋๋ค.
์ฐธ๊ณ : ์ ํฌ๋ ์คํ ํฌ๋๋ CS 112/212์ ์ค๋ฆฌ์ง๋ Pintos๊ฐ ์๋, x86-64์ ๋ง์ถ Pintos-KAIST๋ก ํ๋ก์ ํธ๋ฅผ ์ํํ๊ณ ์์ผ๋ฉฐ, ํฌ์คํธ ๋ํ ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค.
๊ณผ์ ๋ชฉํ: timer_sleep() ๊ฐ์
์ ํฌ๊ฐ ๋ค๋ฃฐ ํจ์๋ devices/timer.c์ ์ ์๋ void timer_sleep(int64_t ticks)์ ๋๋ค. ์ต์ด๋ก ๋ฐ์์ ๋น์ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ ์์ ๊ฐ์ต๋๋ค. ์ด ํจ์์ ์ญํ ์ ํ์ฌ ์ค๋ ๋์ ์คํ์ ticks๋งํผ์ ํ์ด๋จธ ํฑ(tick) ์๊ฐ ๋์ ์ค๋จ์ํค๋ ๊ฒ์ ๋๋ค. ์ปค์๋ฅผ ๊น๋นก์ด๊ฑฐ๋ ์ผ์ ์๊ฐ ๋๊ธฐํด์ผ ํ๋ ์์ ์ ์ ์ฉํ์ง์. ๋ฌธ์ ๋ timer_sleep()์ ๊ตฌํ ๋ฐฉ์์ ๋๋ค. ์๋ ์ฝ๋๋ฅผ ๋ด์ฃผ์ธ์.
/* Suspends execution for approximately TICKS timer ticks. */
void timer_sleep (int64_t ticks) {
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
while (timer_elapsed (start) < ticks)
thread_yield ();
}
์ด๊ฒ์ด ๋ฐ๋ก Busy Waiting (๋ฐ์ ๋๊ธฐ) ๋๋ Spin Waiting (์คํ ๋๊ธฐ)๋ผ๋ ๋นํจ์จ์ ์ธ ๋ฐฉ์์ ๋๋ค. ์ค๋ ๋๋ ์์ ์ด ๊นจ์ด๋์ผ ํ ์๊ฐ(start+ticks)์ด ๋ ๋๊น์ง while ๋ฃจํ๋ฅผ ๊ณ์ ๋๋ฉด์ ํ์ฌ ์๊ฐ์ ํ์ธํ๊ณ , ์๊ฐ์ด ๋์ง ์์์ผ๋ฉด thread_yield()๋ฅผ ํธ์ถํ์ฌ CPU๋ฅผ ๋ค๋ฅธ ์ค๋ ๋์๊ฒ ๋๊ฒจ์ค๋๋ค. ๋๊ฒจ์ฃผ๊ธฐ๋ ํ์ง๋ง, while๋ฌธ์ ๋๋ฉด์ ์ ๋ฌ๋, ๋ง์น ์ด๋ ํ ์ฌ๋์ 5๋ถ๊ฐ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ ๋, ๊ทธ๋ฅ ๊ฐ๋งํ ์๋ ๊ฒ ์๋๋ผ ๊ณ์ ์๊ณ๋ฅผ ์ณ๋ค๋ณด๊ฒ ๋ง๋๋ ๊ฒ์ ๋๋ค. CPU๋ ์๊พธ ์๊ณ๋ฅผ ์ณ๋ค๋ด์ผ ํ๋ ๋ค๋ฅธ ์ผ์ ํ ์๊ฐ ์์ต๋๋ค.
ํด๊ฒฐ์ฑ : ์ค๋ ๋๋ฅผ ์ฌ์๋๊ณ , ํ์ด๋จธ ์ธํฐ๋ฝํธ๋ก ๊นจ์ฐ๊ธฐ
Busy Waiting์ ํผํ๊ธฐ ์ํ ํต์ฌ ์์ด๋์ด๋ ์ค๋ ๋๋ฅผ ๋ธ๋ก(Block) ์ํ๋ก ๋ง๋ค์ด์ ์ค์ผ์ค๋ง ๋์์์ ์ ์ธ์ํค๊ณ , ์ ํด์ง ์๊ฐ์ด ๋์์ ๋ ๋๊ตฐ๊ฐ ์ด ์ค๋ ๋๋ฅผ ๊นจ์์(Unblock) ๋ค์ ์คํ ๊ฐ๋ฅํ ์ํ๋ก ๋ง๋ค์ด์ฃผ๋ ๊ฒ์ ๋๋ค. Pintos ํ๊ฒฝ์์ ์ด ์ญํ ์ ๋ด๋นํ๊ธฐ์ ๊ฐ์ฅ ์ ํฉํ ๊ฒ์ ๋ฐ๋ก ํ์ด๋จธ ์ธํฐ๋ฝํธ ํธ๋ค๋ฌ์ ๋๋ค. ํ์ด๋จธ ์ธํฐ๋ฝํธ๋ ์ผ์ ํ ๊ฐ๊ฒฉ(TIMER_FREQ, ๊ธฐ๋ณธ๊ฐ 100Hz)์ผ๋ก ๋ฐ์ํ๋ฉฐ, ์ด๋๋ง๋ค ํ์ฌ ์๊ฐ์ด 1ํฑ์ฉ ์ฆ๊ฐํฉ๋๋ค. ์ด ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ์ ๋ค์ด ์๋ ์ค๋ ๋๋ค ์ค ๊นจ์ด๋ ์๊ฐ์ด ๋ ์ค๋ ๋๊ฐ ์๋์ง ํ์ธํ๊ณ ๊นจ์์ฃผ๋ฉด ๋ฉ๋๋ค.
ํ์ด๋จธ ์ธํฐ๋ฝํธ๋?
ํ์ด๋จธ ์ธํฐ๋ฝํธ๋ OS์์ ์๊ฐ์ ๊ด๋ฆฌํ๊ณ ์๊ฐ ๊ธฐ๋ฐ ์์ ์ ์ํํ๋ ๋ฐ ํ์์ธ ๊ตฌ์ฑ์์์ ๋๋ค. ์ฃผ๋ก ํ๋์จ์ด ํ์ด๋จธ ์นฉ(๋๋ CPU ๋ด์ฅ ํ์ด๋จธ)์ด ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐ์์ํค๋ฉฐ, OS์ "์ฌ์ฅ ๋ฐ๋" ๊ฐ์ ์ญํ ์ ๋๋ค. ์ด ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค OS๋ ๋ฏธ๋ฆฌ ๋ฑ๋ก๋ ์ธํฐ๋ฝํธ ํธ๋ค๋ฌ(ISR, Interrupt Service Routine)๋ฅผ ์คํํ์ฌ ๋ค์ํ ์๊ฐ ๊ด๋ จ ์์ ์ ์ํํฉ๋๋ค. ์ด๋ฒ์ ์ ํฌ๊ฐ ๊ตฌํํ๋ alarm clock ๊ฐ์ ๊ฒ๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค.
์ค์ ์ฌ๋ก
ํ๋ OS์์ ํ์ด๋จธ ์ธํฐ๋ฝํธ๋ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ธํฐ๋ฝํธ ๋ฐ์ ์ฃผ๊ธฐ๋ ์ค์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง์ง๋ง ์ ํต์ ์ผ๋ก "Jiffy" ๋๋ "Tick" ์ด๋ผ๋ ์๊ฐ ๋จ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก Pintos์ ๋์ผํ๊ฒ 100 Hz, ์ฆ, 10 ms๋น 1์ฉ ์ค๋ฅด๋ ๊ตฌ์กฐ์ ๋๋ค. ํํธ, Windows 9x ๊ณ์ด (95, 98, Me ๋ฑ) ์ญ์ ์ด๋ฐ ๊ธฐ๋ฅ์ด ์์๋๋ฐ, ์ด ๊ณผ์ ์์ 32๋นํธ ์นด์ดํฐ ์ค๋ฒํ๋ก๋ก ์ธํ ์ ๋ช ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ผ๋, ๋ฐ๋ก ๊ทธ 49.7์ผ ๋ฌธ์ ์ ๋๋ค.
Windows 9x๋ ๋น์ ๊ฐ์ ์ฉ PC์ ์ต์ ํ๋ ๊ฐ๋ฒผ์ด ๊ตฌ์กฐ์ ํ์ํธํ์ผ๋ก ๋ง์ ์ฌ๋์ ๋ฐ์์ผ๋ ๋์์ ํ์ ํ ๊ด๋ฆฌ/๋ณดํธ, ๋ถ์์ ์ฑ, ์จ๋ํํฐ ๋๋ผ์ด๋ฒ๋ค์ ๋ถ์กฐํ๋ก ์ ๋ช ์ด ๋์์ต๋๋ค. ๊ทธ๋์ ์์ฆ์ PC์ผ ํ๋ฒ ์ผ๋๊ณ ๋ฉฐ์น ๋ช๋ฌ์ ์ผ๋๋ ๊ฒ ์ผ์์ด๋ผ์ง๋ง 9x๋ ํน์ ์ ๋ถ์์ ์ฑ์ผ๋ก ๊ณ ์ ์ ์๊ฐ๋ง ์ผ๋์๋ ๋ธ๋ฃจ ์คํฌ๋ฆฐ ๋๋ฌธ์ ์ฌ๋ถํ ์ด ํ์์์ง์. ๊ทธ๋ฌ๋ ์ค๋ น ๋ฒํด๋ค ์ณ๋ ๊ฒฐ๊ตญ uptime์ด 49.7์ผ์ ๋๊ธธ ์ ์์์ผ๋ฉฐ, ์ดํ ๋ฌด์กฐ๊ฑด ์ฌ๋ถํ ํด์ผ๋ง ํ์์ต๋๋ค.
- Windows 9x๋ ์์คํ ์ด ๋ถํ ๋ ์ดํ ๊ฒฝ๊ณผ๋ ์๊ฐ์ 1 ms ๋น 1์ฉ ์ฌ๋ผ ๋ถํธ ์๋(unsigned) 32๋นํธ ์ ์์ ์ ์ฅํ๊ณ , ์ด๋ฅผ GetTickCount()์ ๊ฐ์ API๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ณตํ์ต๋๋ค.
- ๋ถํธ ์๋ 32๋นํธ ์ ์๊ฐ ํํํ ์ ์๋ ์ต๋๊ฐ์ 4,294,967,295์
๋๋ค. ์ด ์นด์ดํฐ๊ฐ 1 ms๋น 1์ฉ ์ค๋ฅด๋ฏ๋ก, ์นด์ดํฐ๊ฐ ์ต๋๊ฐ์ ๋๋ฌํ์ฌ ๋ค์ 0์ผ๋ก ๋์์ค๊ธฐ๊น์ง ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ์๋์ ๊ฐ์ต๋๋ค.
- ์ต๋ ๋ฐ๋ฆฌ์ด ์:
- 1์ผ = 24 * 60 * 60 * 1000 = 86,400,000 ms
- ์นด์ดํฐ๊ฐ ์ค๋ฒํ๋กํ๊ธฐ๊น์ง ๊ฑธ๋ฆฌ๋ ์๊ฐ (์ผ)
์๋ฌดํผ, ํด๊ฒฐ์ฑ ์ ์ฐพ์์ผ๋ ์ด์ ์ค์ ๋ก ๊ตฌํํ ์ฐจ๋ก์ ๋๋ค. ์ฐ์ Pintos์ ์ค๋ ๋ ๊ด๋ จ ๋ถ๋ถ์ธ thread.h๋ถํฐ ๋ณด๊ฒ ์ต๋๋ค.
wakeup_tick ๋ณ์ ์ถ๊ฐ
์๋์ ๊ฐ์ด thread.h์ struct thread ์ ์ธ๋ถ์์, int64_t wakeup_tick;๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ด๋ ํด๋น ์ค๋ ๋์ ๊นจ์ธ ์๊ฐ์ ์ ์ฅํ๋ ๋ณ์์ ๋๋ค.
์ฌ๋ฆฝ ๋ฆฌ์คํธ ์ ์ญ ๋ณ์ ์ถ๊ฐ
๋ค์์ thread.c์ ๋๋ค. ์๋์ ๊ฐ์ด ๋ ๊ฐ์ ์ ์ญ ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค.
- static struct list sleep_list; ๊นจ์ธ ์์. insert ์, list_insert_ordered()๋ก wakeup_tick ๊ธฐ์ค ์ค๋ฆ์ฐจ์์ ์ ์งํฉ๋๋ค.
- static int64_t next_tick_to_awake; ์ต์ ํ ์์. ๋ชจ๋ ์ ๋ค์ด ์๋ ์ค๋ ๋๋ค ์ค ๊ฐ์ฅ ๋ค์์ ๊นจ์์ผ ํ ์ค๋ ๋์ ํฑ์ ๋ด๋ ๋ณ์์ ๋๋ค. ๊ฐ๋ น, ์ค๋ ๋ A, B, C, D๊ฐ ์ ๋ค์ด ์๊ณ , ๊ฐ๊ฐ ๋ค์ ๊นจ์์ผ ํ ์์ ์ด 1200ํฑ, 1220ํฑ, 1180ํฑ, 1370ํฑ์ด๋ผ๋ฉด, next_tick_to_awake์๋ 1180์ด๋ผ๋ ๊ฐ์ด ๋ค์ด๊ฐ ์์ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ํตํด, ๋งค ์ธํฐ๋ฝํธ๋ง๋ค ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ ๊ฒ ์๋๋ผ, ์ด๋๋ง ์ ๋ ์ค๋ ๋๋ค์ ํ์ธํ๊ฒ ๋ฉ๋๋ค.
ํจ์ ์ถ๊ฐ
์๋์ ๊ฐ์ด ํ์ํ ํจ์๋ค์ thread.c์ ์ถ๊ฐํฉ๋๋ค.
/**
* thread_sleep: Alarm clock ๊ณผ์ .
* Thread๋ฅผ sleep queue์ ์ฝ์
ํ๊ณ blocked ์ํ๋ก ๋ง๋ค์ด ๋๊ธฐ.
*
* @param ticks: ํด๋น ์ค๋ ๋์ ํฑ
*/
void thread_sleep(int64_t ticks){
struct thread* this;
this = thread_current();
if(this == idle_thread){
ASSERT(0);
}else{
enum intr_level old_level = intr_disable(); // ์ธํฐ๋ฝํธ ์ผ์์ค์ง
update_next_tick_to_awake(this->wakeup_tick = ticks); // Awake ticks ์
๋ฐ์ดํธ
list_push_back(&sleep_list, &this->elem); // sleep_list์ ๋ฃ์
thread_block(); // ํด๋น ์ค๋ ๋๋ฅผ ๋ธ๋ก
intr_set_level(old_level); // ์ธํฐ๋ฝํธ ์ฌ๊ฐ
}
}
/**
* thread_awake - Alarm Clock ๊ณผ์ . wakeup_tick๊ฐ์ด ์ธ์๋ก ๋ฐ์ ticks๋ณด๋ค ํฌ๊ฑฐ๋ ๊ฐ์ ์ค๋ ๋๋ฅผ ๊นจ์.
* ํ์ฌ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ค์ wakeup_tick ์ค ์ต์๊ฐ์ next_tick_to_awake ์ ์ญ๋ณ์์ ์ ์ฅ.
*/
void thread_awake(int64_t wakeup_tick){
next_tick_to_awake = INT64_MAX;
struct list_elem* sleeping = list_begin(&sleep_list); // ์๊ณ ์๋ ์ค๋ ๋ ์ ์ฒด๋ฅผ ๊ฐ์ ธ์ด.
while(sleeping != list_end(&sleep_list)){ // ๋ฆฌ์คํธ ๋๊น์ง
struct thread* thr = list_entry(sleeping, struct thread, elem);
if(thr->wakeup_tick <= wakeup_tick){ // ๊นจ์ธ ๋๋ฉด
sleeping = list_remove(&thr->elem); // ํด๋น ์ค๋ ๋๋ฅผ ์ญ์
thread_unblock(thr); // ํด๋น ์ค๋ ๋์ ๋ธ๋ก ํด์
}else{ // ์๋๋ฉด
sleeping = list_next(sleeping); // ๋ค์ ์๋ ์ค๋ ๋๋ก ๋์ด๊ฐ
update_next_tick_to_awake(thr->wakeup_tick); // wakeup_tick๋ฅผ ์
๋ฐ์ดํธ
}
}
}
/**
* update_next_tick_to_awake - Alarm Clock ๊ณผ์ .
* ์ ์ญ๋ณ์์ธ next_tick_to_awake๋ฅผ, ticks์ ๋น๊ตํ์ฌ, ๋ ์ค ๋ ์์ ๊ฐ์ผ๋ก ์
๋ฐ์ดํธ.
*/
void update_next_tick_to_awake(int64_t ticks) {
next_tick_to_awake = (next_tick_to_awake > ticks) ? ticks : next_tick_to_awake; // ์ต์๊ฐ ๊ฐ์ง ๋
์
}
/**
* get_next_tick_to_awake - Alarm Clock ๊ณผ์ .
* ์ ์ญ๋ณ์์ธ next_tick_to_awake๋ฅผ ๋ฆฌํด.
*/
int64_t get_next_tick_to_awake(void) {
return next_tick_to_awake;
}
ํจ์ ์์
void thread_init(void)๋ฅผ ์๋์ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
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);
/*-- Alarm Clock ๊ณผ์ --*/
list_init (&sleep_list);
/*-- 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 ();
}
์ฆ, thread.c์ ์ ์ญ ๋ณ์๋ก ๋ฃ์๋ ์ฌ๋ฆฝ ๋ฆฌ์คํธ์ ์ด๊ธฐํ๊ฐ ํฌํจ๋๋ ๊ฒ์ ๋๋ค.
๊ทธ ๋ค์, tid_t thread_create()๋ฅผ ์๋์ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
tid_t thread_create (const char *name, int priority,
thread_func *function, void *aux) {
struct thread *t;
tid_t tid;
ASSERT (function != NULL);
/* Allocate thread. */
t = palloc_get_page (PAL_ZERO);
if (t == NULL)
return TID_ERROR;
/* Initialize thread. */
init_thread (t, name, priority);
tid = t->tid = allocate_tid ();
/* Call the kernel_thread if it scheduled.
* Note) rdi is 1st argument, and rsi is 2nd argument. */
t->tf.rip = (uintptr_t) kernel_thread;
t->tf.R.rdi = (uint64_t) function;
t->tf.R.rsi = (uint64_t) aux;
t->tf.ds = SEL_KDSEG;
t->tf.es = SEL_KDSEG;
t->tf.ss = SEL_KDSEG;
t->tf.cs = SEL_KCSEG;
t->tf.eflags = FLAG_IF;
/* Add to run queue. */
thread_unblock (t);
/*-- Alarm clock ๊ตฌํ --*/
if(t->priority > thread_current()->priority)
thread_yield();
/*-- Alarm clock ๊ตฌํ --*/
return tid;
}
์ถ๊ฐํ ๋ด์ฉ ์์ฒด๋ ๋ ์ค์ ๋ถ๊ณผํ์ง๋ง ์ค๋ช ์ด ๋ค์ ํ์ํ ๋ถ๋ถ์ ๋๋ค. Pintos์ alarm clock ๋จ๊ณ์์๋ ๋จ์ํ sleep/wakeup ๊ธฐ๋ฅ๋ฟ๋ง ์๋๋ผ, ์ค๋ ๋ ์ฐ์ ์์ ๊ธฐ๋ฐ์ ์ค์ผ์ค๋ง์ด ๋์ํจ์ ์ ์ ๋ก ํฉ๋๋ค. ์ฆ, ํ์ฌ ์คํ ์ค์ธ ์ค๋ ๋๋ณด๋ค ๋ ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง ์ค๋ ๋๊ฐ ์๋ก ์์ฑ๋์์ ๊ฒฝ์ฐ, ํด๋น ์ค๋ ๋๊ฐ ์ฆ์ CPU๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์๋ณด(yield)ํด์ผ ํฉ๋๋ค.
๊ธฐ๋ณธ thread_create() ๋ก์ง์์๋ ์ ์ค๋ ๋๋ฅผ ready queue์ ์ถ๊ฐ(thread_unblock)ํ ๋ค ๋ฐ๋ก ํ์ฌ ์ค๋ ๋๊ฐ ๊ณ์ ์คํ๋์ง๋ง, ์์ ๊ฐ์ ์กฐ๊ฑด์ ์ถ๊ฐํจ์ผ๋ก์จ ์ค์ผ์ค๋ฌ๊ฐ ์ฆ์ context switch๋ฅผ ์ผ์ผํฌ ์ ์๋๋ก ํด์ค๋๋ค. ์ด๋ก์จ ์ฐ์ ์์ ๊ธฐ๋ฐ ์ ์ ์ค์ผ์ค๋ง(priority preemption)๋ ์์ฐ์ค๋ฝ๊ฒ ๊ตฌํ๋๋ ๊ฒ์ ๋๋ค.
์ฆ, ์ด ์ฝ๋๋ "์๋ก ์์ฑํ ์ค๋ ๋๊ฐ ํ์ฌ ์ค๋ ๋๋ณด๋ค ์ฐ์ ์์๊ฐ ๋๋ค๋ฉด, ์๋ฐ์ ์ผ๋ก ์๋ณด(thread_yield)"ํ๊ฒ ํ์ฌ ์ปค๋์ด ์๋ก ์์ฑํ high-priority thread๋ฅผ ๋น ๋ฅด๊ฒ ์คํํ ์ ์๊ฒ ๋์์ฃผ๋ ์ญํ ์ ํฉ๋๋ค. ๋ง์ฝ ์ด ๋ถ๋ถ์ด ์์ผ๋ฉด, thread_create() ์ดํ ๋ช ์์ ์ธ yield ๋๋ blocking์ด ์ผ์ด๋๊ธฐ ์ ๊น์ง๋ ์ ์ค๋ ๋๊ฐ ์คํ๋ ๊ธฐํ๋ฅผ ๊ฐ์ง ๋ชปํ๊ฒ ๋์ด, ์ ์ ํ ์ค์ผ์ค๋ง์ด ์ ๋๋ก ์๋ํ์ง ์๊ฒ ๋ฉ๋๋ค.
timer.c
timer_interrupt()๋ฅผ ์๋์ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
/* Timer interrupt handler. */
/* ๋งค tick๋ง๋ค timer ์ธํฐ๋ฝํธ ์ ํธ์ถ๋๋ ํจ์
sleep queue์์ ๊นจ์ด๋ thread๊ฐ ์๋์ง ํ์ธ.
*/
static void
timer_interrupt (struct intr_frame *args UNUSED) {
ticks++;
thread_tick ();
if (get_next_tick_to_awake() <= ticks)
thread_awake(ticks);
}
๋จผ์ , thread.c์์ ์ถ๊ฐํ๋ get_next_tick_to_awake()์ด ์ฌ๊ธฐ์๋ ํธ์ถ๋ฉ๋๋ค. ์ด๋ sleep list ์์์ ๊ฐ์ฅ ๋นจ๋ฆฌ ๊นจ์ด๋์ผ ํ ์ค๋ ๋์ wakeโup tick์ ๋ฐํํ๋ ํฌํผ์ ๋๋ค.
๊ทธ๋ฆฌํ์ฌ ๋งค tick๋ง๋ค ticks(๋ถํ
์ดํ ๋์ tick) ๊ฐ๊ณผ ๋น๊ตํด์, “์ง๊ธ ๊นจ์ธ ์ค๋ ๋๊ฐ ์๋?”๋ฅผ O(1)๋ก ํ๋ณํฉ๋๋ค. <=๋ฅผ ์ฐ๋ ์ด์ ๋ ๋์ผ tick์ ๊นจ์์ผ ํ๋ ์ค๋ ๋๋ ํฌํจํ๊ธฐ ์ํจ์
๋๋ค. ๊ทธ ๋ค์ sleep list์์ wake_up_tick <= ticks์ธ ๋
ธ๋๋ฅผ ์ ๋ถ ๋นผ์ ready list๋ก ์ฎ๊ธฐ๊ณ , ๊ทธ ๊ณผ์ ์์ next_tick_to_awake๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก, timer_sleep()๋ฅผ ์๋์ ๊ฐ์ด ๊ตฌ์ฑํฉ๋๋ค.
/* Suspends execution for approximately TICKS timer ticks. */
void timer_sleep(int64_t ticks) {
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
// while (timer_elapsed (start) < ticks)
// thread_yield ();
thread_sleep(start + ticks);
}
๊ธฐ์กด ๋ฐฉ์์ ์์ ์ธ๊ธํ ๋ฐ์ ๋์ผํฉ๋๋ค. ์์ ๋ ๋ฐฉ์์, โ thread_sleep()๋ก ํ์ฌ ์ค๋ ๋์ wake_up_tick ํ๋์ start + ticks ์ ์ฅ ==> โก ์์ ์ sleep list์ ์ฝ์ ==> โข next_tick_to_awake ๊ฐฑ์ ==> โฃ thread_block()์ผ๋ก ๋ธ๋กํ์ฌ, ์ค์ผ์ค๋ฌ๊ฐ ๋ค๋ฅธ ์ค๋ ๋์๊ฒ CPU๋ฅผ ๋๊ธฐ๋ ๊ณผ์ ์ ๊ฑฐ์น๊ฒ ๋ฉ๋๋ค.
๊ฒฐ๊ณผ ํ์ธ
Pintos์ thread ๋๋ ํ ๋ฆฌ์์ ๋ค์ ์ปดํ์ผ ๋ฐ ํ ์คํธํฉ๋๋ค. ์๋์ ๊ฐ์ด alarm ๊ด๋ จํ ๊ฒ๋ค ์ค alarm-priority๋ฅผ ์ ์ธํ ํญ๋ชฉ๋ค์์ ํต๊ณผ๋์ด์ผ ํฉ๋๋ค (alarm-priority๋ priority scheduling ๊ตฌํ์ ํตํด ์์ฐ์ค๋ฝ๊ฒ ํต๊ณผ๋๊ฒ ๋ฉ๋๋ค).
(... ์ค๋ต ...)
make[1]: Leaving directory '/home/mihnsurk2/gitp/Mugen-Houyou/pintos-kaist/threads/build'
pintos -v -k -T 60 -m 20 -- -q run alarm-single < /dev/null 2> tests/threads/alarm-single.errors > tests/threads/alarm-single.output
perl -I../.. ../../tests/threads/alarm-single.ck tests/threads/alarm-single tests/threads/alarm-single.result
pass tests/threads/alarm-single
pintos -v -k -T 60 -m 20 -- -q run alarm-multiple < /dev/null 2> tests/threads/alarm-multiple.errors > tests/threads/alarm-multiple.output
perl -I../.. ../../tests/threads/alarm-multiple.ck tests/threads/alarm-multiple tests/threads/alarm-multiple.result
pass tests/threads/alarm-multiple
pintos -v -k -T 60 -m 20 -- -q run alarm-simultaneous < /dev/null 2> tests/threads/alarm-simultaneous.errors > tests/threads/alarm-simultaneous.output
perl -I../.. ../../tests/threads/alarm-simultaneous.ck tests/threads/alarm-simultaneous tests/threads/alarm-simultaneous.result
pass tests/threads/alarm-simultaneous
pintos -v -k -T 60 -m 20 -- -q run alarm-priority < /dev/null 2> tests/threads/alarm-priority.errors > tests/threads/alarm-priority.output
perl -I../.. ../../tests/threads/alarm-priority.ck tests/threads/alarm-priority tests/threads/alarm-priority.result
pass tests/threads/alarm-priority
pintos -v -k -T 60 -m 20 -- -q run alarm-zero < /dev/null 2> tests/threads/alarm-zero.errors > tests/threads/alarm-zero.output
perl -I../.. ../../tests/threads/alarm-zero.ck tests/threads/alarm-zero tests/threads/alarm-zero.result
pass tests/threads/alarm-zero
pintos -v -k -T 60 -m 20 -- -q run alarm-negative < /dev/null 2> tests/threads/alarm-negative.errors > tests/threads/alarm-negative.output
perl -I../.. ../../tests/threads/alarm-negative.ck tests/threads/alarm-negative tests/threads/alarm-negative.result
pass tests/threads/alarm-negative
pintos -v -k -T 60 -m 20 -- -q run priority-change < /dev/null 2> tests/threads/priority-change.errors > tests/threads/priority-change.output
perl -I../.. ../../tests/threads/priority-change.ck tests/threads/priority-change tests/threads/priority-change.result
pass tests/threads/priority-change
(... ์ค๋ต ...)
๋ง์น๋ฉฐ
Alarm clock ํํธ๋ Pintos์ ์ค๋ ๋ ์ํ ์ ์ด(thread_block, thread_unblock), ์ค์ผ์ค๋ง, ์ธํฐ๋ฝํธ ํธ๋ค๋ง, ๊ทธ๋ฆฌ๊ณ ๋๊ธฐํ ๋ฉ์ปค๋์ฆ์ ๊ธฐ์ด๋ฅผ ์ดํดํ๋ ๋ฐ ๋งค์ฐ ์ค์ํ ๊ณผ์ ์์ต๋๋ค. Busy Waiting์ด๋ผ๋ ๋นํจ์จ์ ์ธ ๋ฐฉ์์ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ ํจ์จ์ ์ธ Sleep/Wakeup ๋ฉ์ปค๋์ฆ์ผ๋ก ๋ฐ๊พธ๋ ๊ณผ์ ์ ํตํด ์ด์์ฒด์ ๊ฐ ์๊ฐ์ ์ด๋ป๊ฒ ๊ด๋ฆฌํ๊ณ ์ค๋ ๋๋ฅผ ์ด๋ป๊ฒ ์ ์ดํ๋์ง ๊ฐ์ ์ก์ ์ ์์ต๋๋ค. ๋ค์ ๊ธ์์๋ ์ฐ์ ์์ ์ค์ผ์ค๋ง์ ๋ํด ์ด์ผ๊ธฐํด ๋ณด๊ฒ ์ต๋๋ค.
'IT > ์ปดํจํ ์ ์ฌ๊ณ ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Pintos Part 1-2. Priority Scheduling (0) | 2025.05.12 |
---|---|
๋ ๋-๋ธ๋ ํธ๋ฆฌ (Red-Black Tree) (1) | 2025.04.18 |
C์ธ์ด์ ํฌ์ธํฐ (๊ธฐ์ด) (0) | 2025.04.17 |
C์ธ์ด์ ๋ฐฐ์ด๊ณผ ํฌ์ธํฐ (0) | 2025.04.17 |
C์ธ์ด์ ํฌ์ธํฐ ์ดํด: ์๋ฃํ์ผ๋ก์์ *์ ์ญ์ฐธ์กฐ ์ฐ์ฐ์๋ก์์ * (2) | 2025.04.14 |
C์ธ์ด์ ๋ค์ค ํฌ์ธํฐ (0) | 2025.04.13 |
์ด๋ถ ํ์๊ณผ Python์ bisect_left (0) | 2025.03.27 |
์๋ ํ์ธ์.
ํฌ์คํ ์ด ์ข์๋ค๋ฉด "์ข์์โค๏ธ" ๋๋ "๊ตฌ๋ ๐๐ป" ํด์ฃผ์ธ์!