๐Ÿ‘จโ€๐Ÿ’ป Seungineer's GitHub Contribution

๐Ÿงญ KAIST JUNGLE/Pintos

[PintOS] Thread - Alarm Clock (Project 1)

seungineer = seungwoo + engineer 2024. 4. 29. 16:07

KAIST Jungle 7์ฃผ์ฐจ, OS ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

 

๋“ค์–ด๊ฐ€๊ธฐ ์ „์—

ํ”„๋กœ์„ธ์Šค๋Š” ๋ญ๊ณ  ์Šค๋ ˆ๋“œ๋Š” ๋ญ”๊ฐ€์š”? [์œ ํŠœ๋ธŒ ์˜์ƒ ๊ฐ•์˜]

  • CPU์˜ ๋™์‹œ์„ฑ์€ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์ผ๋ถ€๋ถ„์”ฉ context switching ํ•˜๋ฉด์„œ ์ง„ํ–‰๋จ
    • A, B, C ์ž‘์—… ๋™์‹œ ์ฒ˜๋ฆฌ ์‹œ ์ˆœ์„œ๋Œ€๋กœ A(5% ์ˆ˜ํ–‰)โ–ถ๏ธ B(5% ์ˆ˜ํ–‰) โ–ถ๏ธ C(5% ์ˆ˜ํ–‰) โ–ถ๏ธ A(10% ์ˆ˜ํ–‰)โ–ถ๏ธ B(10% ์ˆ˜ํ–‰) โ–ถ๏ธ C(10% ์ˆ˜ํ–‰) ... (๋ฐ˜๋ณต) โ–ถ๏ธ A(100% ์ˆ˜ํ–‰)โ–ถ๏ธ B(100% ์ˆ˜ํ–‰) โ–ถ๏ธC(100% ์ˆ˜ํ–‰)
  • ๋ณ‘๋ ฌ์„ฑ์€ ํ”„๋กœ์„ธ์Šค ํ•˜๋‚˜์— ์ฝ”์–ด ์—ฌ๋Ÿฌ ๊ฐœ๊ฐ€ ๋‹ฌ๋ ค์„œ ๊ฐ๊ฐ์ด ์ž‘์—…์„ ๋™์‹œ์— ์ง„ํ–‰ํ•˜๋Š” ๊ฒƒ(์ž‘์—…๋ถ„๋‹ด)
    • ์ฒซ ๋ฒˆ์งธ ์ฝ”์–ด์—์„œ A์ž‘์—…, ๋‘ ๋ฒˆ์งธ ์ฝ”์–ด์—์„œ B์ž‘์—…, ์„ธ ๋ฒˆ์งธ ์ฝ”์–ด์—์„œ C์ž‘์—…์„ ๊ฐ™์€ ์‹œ์ ์— ์ž‘์—…ํ•จ
  • ํ•œ ํ”„๋กœ์„ธ์Šค(ex. ํฌ๋กฌ) ๋‚ด์—์„œ ๋‹ค์–‘ํ•œ ์ž‘์—…์ด ์ง„ํ–‰๋˜์–ด์•ผ ํ•  ๋•Œ ๐Ÿ’ก Thread
    • Thread๋Š” ํ”„๋กœ์„ธ์Šค๋งˆ๋‹ค ์ฃผ์–ด์ง„ ์ „์ฒด ์ž์›์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ
      • ์žฅ์ : ์†๋„, ํšจ์œจ โฌ†๏ธ
      • ๋‹จ์ : Thread๊ฐ€ ๋™์‹œ์— ์ž์›์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ, ์ด๋กœ ์ธํ•œ error๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Œ
        • ์‹ฑํฌ๋กœ๋‚˜์ด์ฆˆ(synchronize) : ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ž์›์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชป ํ•˜๋„๋ก ํ•จ

์ปค๋„ ์Šค๋ ˆ๋“œ(Kernel Treads)

  • ์ปค๋„ ์Šค๋ ˆ๋“œ๋Š” ์šด์˜ ์ฒด์ œ์˜ ํ•ต์‹ฌ ๋ถ€๋ถ„์—์„œ ์‹คํ–‰๋˜๋Š” Thread
    • ์ด๋“ค์€ ํ•˜๋“œ์›จ์–ด์™€ ์ง์ ‘ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ณ , ์‹œ์Šคํ…œ ์ž์›์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž ์ˆ˜์ค€์˜ ์Šค๋ ˆ๋“œ ๋ฐ ํ”„๋กœ์„ธ์Šค์— ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•จ
  • PintOS ๊ตฌํ˜„์— ํ•„์ˆ˜์ ์ธ ์‚ฌํ•ญ: Thread ์Šค์ผ€์ค„๋ง, Thread ์ƒ์„ฑ ๋ฐ ์ข…๋ฃŒ,Thread ๊ฐ„ ๋™๊ธฐํ™”(์˜ˆ: ์„ธ๋งˆํฌ์–ด, ๋ฝ), ์šฐ์„  ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง์„ ์ง€์› โžก๏ธ ์ด๋ฅผ ํ†ตํ•ด ์šด์˜ ์ฒด์ œ๊ฐ€ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ

์‹ฑํฌ๋กœ๋‚˜์ด์ฆˆ(synchronization) - ๊ณผ์ œ ์„ค๋ช…์„œ ๊ธฐ๋ฐ˜ ์ •๋ฆฌ

ํŠนํžˆ๋‚˜ OS kernel์˜ Thread ๊ฐ„ ์ž์›์„ ๊ณต์œ ํ•  ๋•Œ ํ†ต์ œ๋œ ํ˜•์‹(controlled fashion)์„ ์ง€ํ‚ค์ง€ ์•Š๋Š”๋‹ค๋ฉด big messํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. PintOS์—์„œ๋Š” ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋‹ค์–‘ํ•œ synchronization ํ•จ์ˆ˜(primitives)๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

  • Disabling Interrupts
    • Synchronization์„ ํ•˜๋Š” ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์€ interrupts๋ฅผ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ
    • interrupts๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด, ์ง„ํ–‰ ์ค‘์ธ Thread๊ฐ€ ์–ธ์ œ๋“  ๋‹ค๋ฅธ Thread์— ์˜ํ•ด ์„ ์ (preempt)๋  ์ˆ˜ ์žˆ์Œ(error ๋ฐœ์ƒ ๊ฐ€๋Šฅ)
    • interrupts๋ฅผ ๋„๋ฉด, ์ง„ํ–‰์ค‘์ธ Thread ์„ ์ ์ด ๋ถˆ๊ฐ€๋Šฅํ•จ
      • Thread ์„ ์ ์€ time interrupts(์‹œ์Šคํ…œ ํƒ€์ด๋จธ๋กœ๋ถ€ํ„ฐ ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์— ๋”ฐ๋ผ interrupts ๋ฐœ์ƒ)์— ์˜ํ•ด ์ด๋ค„์ง€๊ธฐ ๋•Œ๋ฌธ
      • ๋‹ค๋งŒInterrupts ๋น„ํ™œ์„ฑํ™” ๋˜์–ด ์žˆ๋‹ค๋ฉด OS๋Š” ์‹œ์Šคํ…œ์˜ ์ œ์–ด๊ถŒ์„ ๋‹ค์‹œ ์–ป์„ ์ˆ˜ ์—†์Œ(์•…์˜์  ํ”„๋กœ๊ทธ๋žจ์ด ํ”„๋กœ์„ธ์Šค ๋…์ ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ)
    • ์ผ๋ฐ˜์ ์ธ Unix ์‹œ์Šคํ…œ์€ '์„ ์ ๋ถˆ๊ฐ€๋Šฅ(nonpreemptible)'์ด์ง€๋งŒ, PintOS๋Š” '์„ ์ ๊ฐ€๋Šฅํ•œ(preemptible)' Kernel์ž„
      • '์„ ์ ๊ฐ€๋Šฅํ•œ' Kernel์˜ ๊ฒฝ์šฐ ๋ช…์‹œ์ ์ธ synchronization์ด ๋”์šฑ ํ•„์š”ํ•จ
    • ์™ธ๋ถ€ interrupts handler์™€ kernel thread๋ฅผ ๋™๊ธฐํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•จ
      • ์™ธ๋ถ€ interrupts handler๋Š” ์ž ๋“ค๊ฒŒ ํ•  ์ˆ˜ ์—†๊ธฐ์— ๋น„ํ™œ์„ฑํ™” ์‹œํ‚ค์ง€ ์•Š๊ณ ๋Š” ๋™๊ธฐํ™”๊ฐ€ ๊ฑฐ์˜ ๋ถˆ๊ฐ€๋Šฅ ํ•จ

(์ฐธ๊ณ ) ์ˆ˜์ •ํ•ด์•ผ ํ•  ์ „์ฒด ์ฝ”๋“œ ๋ผ์ธ ์ˆ˜

๊ณผ์ œ ์„ค๋ช…์„œ ๋‚ด FAQ

Alarm Clock(OS, "Thread ์ผ์ • ์‹œ๊ฐ„ ์ดํ›„์— ์ผ์–ด๋‚˜")

Alarm Clock ๊ณผ์ œ๋Š” timer_sleep() ํ•จ์ˆ˜๋ฅผ ์žฌ๊ตฌํ˜„ํ•˜๋Š” ๊ณผ์ œ์ด๋‹ค. ๊ธฐ์กด์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๋ฐฉ์‹์€ busy-waiting ๋ฐฉ์‹์œผ๋กœ 'OS์—์„œ Thread๋ฅผ ์žฌ์› ๋‹ค๊ฐ€ ๊ณง๋ฐ”๋กœ ์‹œ๊ฐ„์„ ํ™•์ธํ•˜๊ณ  ์•„์ง ์ผ์–ด๋‚  ์‹œ๊ฐ„์ด ์•„๋‹ˆ๋ผ๋ฉด ๋‹ค์‹œ ์žฌ์šฐ๊ณ  ๋˜, ๊ณง๋ฐ”๋กœ ์‹œ๊ฐ„์„ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ'์ด๋‹ค. ์ด๋Š” Thread์˜ ์ƒํƒœ๊ฐ€ Running ↔๏ธ Ready๋ฅผ ๋ฐ˜๋ณตํ•œ๋‹ค.

์กฐ๊ธˆ ๋” ํ’€์–ด์„œ ๊ณผ์ •์„ ๋ณด๋ฉด, Running ์ƒํƒœ์—์„œ sleep ๋ช…๋ น์„ ๋ฐ›์€ Thread๋Š” Ready ์ƒํƒœ๊ฐ€ ๋˜๊ณ  ready queue์— ์ถ”๊ฐ€ ๋œ๋‹ค. Ready queue์— ์žˆ๋Š” Threads๋Š” ์ผ์–ด๋‚  ์‹œ๊ฐ„์ด ์•„๋‹˜์—๋„ ์ƒ๊ด€์—†์ด ๊นจ์›Œ์ ธ์„œ Running ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ์ผ์–ด๋‚  ์‹œ๊ฐ„์ด ์•„๋‹ˆ์—ˆ๊ธฐ์— ๋‹ค์‹œ Ready ์ƒํƒœ๊ฐ€ ๋˜๊ณ , ready queue์— ์ถ”๊ฐ€๋œ๋‹ค.

Sleep/Wake up ๊ธฐ๋ฐ˜์˜ Alarm Clock ๊ตฌํ˜„

๊ธฐ์กด ๋ฐฉ์‹์—์„œ Running ↔๏ธ Ready ์ƒํƒœ๊ฐ€  ๋ฐ˜๋ณต์ ์œผ๋กœ(while๋ฌธ ์•ˆ์—์„œ) ๊นจ์–ด๋‚  ์‹œ๊ฐ„๊นŒ์ง€ ์‹คํ–‰๋˜๋Š” ๋น„ํšจ์œจ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Ready ์ƒํƒœ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ Block ์ƒํƒœ๋กœ ์ „ํ™˜ํ•ด Block ์ƒํƒœ์ธ ๊ฒƒ์€ ๊นจ์–ด๋‚  ์‹œ๊ฐ„์ด ๋˜๊ธฐ ์ „์—” ์Šค์ผ€์ฅด๋ง์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ์ˆ˜์ •ํ•œ๋‹ค. ๊นจ์–ด๋‚  ์‹œ๊ฐ„์ด ๋˜์—ˆ์„ ๋•Œ, Block ์ƒํƒœ๋ฅผ โžก๏ธ Ready ์ƒํƒœ๋กœ ๋ฐ”๊พธ์–ด์ค€๋‹ค.

 

Sleep queue ์ž๋ฃŒ ๊ตฌ์กฐ ์ถ”๊ฐ€

/* List of processes in THREAD_READY state, that is, processes
   that are ready to run but not actually running. */
static struct list ready_list;
static struct list sleep_list;

...

void thread_init(void) {
	...
    /* Init the globla thread context */
    lock_init(&tid_lock);
    list_init(&ready_list);
    list_init(&sleep_list);
    list_init(&destruction_req);
   ...
}

Sleep ๋˜์–ด ์žˆ๋Š” Threads๋ฅผ ์ €์žฅํ•  queue ๊ตฌ์กฐ์ฒด๋ฅผ ์„ ์–ธํ•œ๋‹ค. ์ดํ›„ Thread ์ดˆ๊ธฐํ™” ์‹œ sleep_list๋ฅผ ํ•จ๊ป˜ ์ดˆ๊ธฐํ™”๋˜๋„๋ก ํ•œ๋‹ค. ์ด sleep_list๋Š” Block ์ƒํƒœ์˜ Threads๊ฐ€ ์ €์žฅ๋˜์–ด ๊นจ์–ด๋‚  ์‹œ๊ฐ„์ด ๋˜๊ธฐ ์ „๊นŒ์ง€ ๋จธ๋ฌด๋ฅด๋Š” ๊ณณ์ด๋‹ค.

 

Thread_sleep() ํ•จ์ˆ˜ ๊ตฌํ˜„

void thread_sleep(int64_t ticks) {
    struct thread *curr = thread_current();
    enum intr_level old_level;

    ASSERT(!intr_context());

     old_level = intr_disable(); // Disabling Interrupts
    if (curr != idle_thread) { 			// idle thread๋Š” sleep ๋˜์ง€ ์•Š์•„์•ผ ํ•จ
        curr->wakeup_tick = ticks;                // ํ˜„์žฌ thread์— ์ผ์–ด๋‚˜์•ผ ํ•˜๋Š” ์‹œ๊ฐ„ ์ €์žฅ
        list_push_back(&sleep_list, &curr->elem); // sleep queue์— push back
        thread_block();			        // thread block ์ƒํƒœ๋กœ ์ „ํ™˜
    }

    intr_set_level(old_level);   // Anabling Interrupts
}

Thread๋ฅผ sleep queue์— ์‚ฝ์ž…(list_push_back())ํ•˜๊ณ , blocked ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด์„œ ๋Œ€๊ธฐํ•œ๋‹ค. ์ด๋•Œ, Disabling Interrupts๋ฅผ ํ†ตํ•ด ๊ณผ์ • ์ค‘ Interrupts๋ฅผ ๋ฐ›์•„๋“ค์ด์ง€ ์•Š๊ณ , thread๋ฅผ Block ์ƒํƒœ๋กœ์˜ ์ „ํ™˜ ํ›„์— Interrupts๋ฅผ ๋ฐ›์•„๋“ค์ธ๋‹ค(Anabling Interrupts). 

 

timer_sleep() ํ•จ์ˆ˜ ์ˆ˜์ •

void timer_sleep(int64_t ticks) {
    int64_t start = timer_ticks();

    ASSERT(intr_get_level() == INTR_ON);
    thread_sleep(start + ticks);       // ํ˜„์žฌ tick + ์ž์•ผํ•˜๋Š” tick = ๊นจ์–ด๋‚˜์•ผํ•  ์‹œ๊ฐ
}

Interrupts๋ฅผ ๋ฐ›์•„๋“ค์ด๊ณ  ์žˆ์„ ๋•Œ(Interrupts ON), ํ˜„์žฌ OS์˜ tick(์‹œ๊ฐ„)์— ์ž์•ผํ•˜๋Š” ์‹œ๊ฐ„ tick์„ ๋”ํ•ด์„œ ๊นจ์–ด๋‚˜์•ผํ•  '์‹œ๊ฐ'์„ ๊ตฌํ•˜์—ฌ thread_sleep() ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๐Ÿ’ก ์ฆ‰, ํ˜„์žฌ threads๋Š” OS์˜ tick์ด 'start + tick'์ผ ๋•Œ wake up ํ•˜๊ฒŒ ๋œ๋‹ค.

 

timer_interrupt() ํ•จ์ˆ˜

static void timer_interrupt(struct intr_frame *args UNUSED) {
    ticks++;
    thread_tick();
    thread_awake(ticks);
}

timer_interrup() ํ•จ์ˆ˜์— thread_awake(ticks)๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ์„œ ticks๊ฐ€ ์ฆ๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค wake upํ•  ์ˆ˜ ์žˆ๋Š” Thread๊ฐ€ ์žˆ๋Š”์ง€ ์ฐพ๊ณ , Ready ์ƒํƒœ๋กœ ์ „ํ™˜์‹œ์ผœ ์ค€๋‹ค. ์ด๋กœ์จ Sleep/Wake up ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๐Ÿ› ๋ฐœ์ƒํ•œ Bug

Alarm Clock ๊ตฌํ˜„ ์ค‘ ๋ฐœ์ƒํ•œ Bug(Kernel PANIC)

thread_sleep() ํ•จ์ˆ˜ ๊ตฌํ˜„ ์ค‘ ๋ฐœ์ƒํ–ˆ๋˜ 'Keral PANIC' error์ด๋‹ค. ๊ตฌํ˜„ ๊ฒฐ๊ณผ๋ฅผ ์‚ดํŽด๋ณด๋ฉด, ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

Timer: 27 ticks
Thread: 1 idle ticks, 26 kernel ticks, 0 user ticks

26 kernel ticks์™€ 1 idle ticks ํ›„, Kernel PANIC์œผ๋กœ test๊ฐ€ failed ํ–ˆ๋‹ค.

Kernel PANIC

์ด๋Š” "LINUX ์‹œ์Šคํ…œ์— ์‹ฌ๊ฐํ•œ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ฒจ ์‹œ์Šคํ…œ์„ ๋‹ค์šด์‹œํ‚ค๋Š” ๋™์ž‘"์ด๋ผ๊ณ  ํ•œ๋‹ค. Thread ๊ตฌํ˜„ ์ค‘ ํ•ด๋‹น ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋กœ '์ž์›์˜ ๊ณ ๊ฐˆ', '์‹œ์Šคํ…œ์˜ ๋ถˆ์•ˆ์ •์„ฑ', '์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ์˜ ์‹คํŒจ', '๋””๋ฒ„๊น… ๋ฐ ์˜ค๋ฅ˜ ๋ณด๊ณ  ๋งค์ปค๋‹ˆ์ฆ˜'์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค(by Chat GPT). ์‹œ์Šคํ…œ์— ์ถฉ๋ถ„ํ•œ ์ž์›์ด ์—†๊ฒŒ ๋˜์—ˆ์„ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๋ฌธ์ œ๋Š” sleep_list์— push back ํ•˜๋Š” current thread์˜ ticks๊ฐ€ ํ• ๋‹น๋˜์ง€ ์•Š์•˜๊ธฐ์— ๋ฐœ์ƒํ–ˆ๊ณ , ์ด๋กœ์ธํ•ด Kernel์—์„œ ์ด Thread๋“ค์„ ๋‹ค์‹œ Wake up ์‹œํ‚ค์ง€ ๋ชปํ–ˆ๊ธฐ์— ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜์˜€๋‹ค. ๊ทธ๋ž˜์„œ 26 ticks์˜ kernel๊ณผ 1 ticks์˜ idle ํ›„์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ž์›์ด ์—†์–ด Kernel Panic์ด ๋ฐœ์ƒํ•œ ๊ฒƒ์ด๋‹ค.