[Pintos-KAIST] Project 1 : Alarm Clock

์œ ์„ ยท2024๋…„ 4์›” 27์ผ
0

Pintos - KAIST

๋ชฉ๋ก ๋ณด๊ธฐ
1/16
post-thumbnail

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป GITHUB ๋ ˆํฌ์ง€ํ† ๋ฆฌ
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป GITHUB alarm clock ์ด์Šˆ

๊ณผ์ œ ์„ค๋ช…

๐Ÿคซ ์ง„์ž… ๋ฐฉ๋ฒ•

๊ธฐ๋ณธ์ ์ธ ์ž๋ฃŒ๋“ค์€ ์ •๊ธ€ ํŽ˜์ด์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ณ , ๋ถ€๊ฐ€์ ์ธ ์ž๋ฃŒ๋ฅผ ๊ณต์œ ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค!
์ง„์ž…์กฐ์ฐจ ๋ชปํ•˜๊ฒ ์„๋•Œ... ๋งŽ์ด ๋„์›€ ๋ฐ›์€ ์„ ๋ฐฐ๋‹˜๋“ค์˜ ์ž๋ฃŒ์ž…๋‹ˆ๋‹ค (๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค๐Ÿ™)

์ €๋Š” ์ด ์ˆœ์„œ๋กœ ์ฐธ๊ณ ํ•˜๋ฉด์„œ ํ”„๋กœ์ ํŠธ์— ์ง„์ž…ํ•˜์˜€์Šต๋‹ˆ๋‹ค!

โฐ Alarm Clock

์šด์˜์ฒด์ œ์—๋Š” ์‹คํ–‰์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์ž ์‹œ ์žฌ์› ๋‹ค๊ฐ€ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋‹ค์‹œ ๊นจ์šฐ๋„๋ก ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋Š”๋ฐ, ์ด ๊ธฐ๋Šฅ์„ Alarm Clock ์ด๋ผ๊ณ  ํ•œ๋‹ค.

ํ˜„์žฌ ํ•€ํ† ์Šค์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” Alarm Clock ๊ธฐ๋Šฅ์€ busy-waiting ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ์ด๋Š” ๋งค์šฐ ๋น„ํšจ์œจ์ ์œผ๋กœ ๋งŽ์€ CPU ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ฒŒ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋ฐฉ์‹์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์ด ๊ณผ์ œ์˜ ๋ชฉํ‘œ์ด๋‹ค.

๐Ÿƒ busy-waiting

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 ์—์„œ thread ์˜ ์ƒํƒœ

๐Ÿ˜ด sleep-awake

๋ณ€๊ฒฝ ๋ฐฉ์•ˆ
ํ˜„์žฌ => busy-waiting
์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šด ํ›„ ์ผ์–ด๋‚  ์‹œ๊ฐ„์ธ์ง€ ํ™•์ธํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„์ง ์ผ์–ด๋‚  ์‹œ๊ฐ„์ด ์•„๋‹ˆ๋ผ๋ฉด ๋‹ค์‹œ ready state๋กœ ๋ณด๋‚ธ๋‹ค.

๋ณ€๊ฒฝ์•ˆ => sleep-awake
์ด๋Ÿฌํ•œ ๋น„ํšจ์œจ์„ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์ž ์ด ๋“  ์Šค๋ ˆ๋“œ๋ฅผ ready state ๊ฐ€ ์•„๋‹Œ block state ๋กœ ๋‘์–ด์„œ ๊นจ์–ด๋‚  ์‹œ๊ฐ„์ด ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์Šค์ผ€์ค„๋ง์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ํ•˜๊ณ , ๊นจ์–ด๋‚  ์‹œ๊ฐ„์ด ๋˜์—ˆ์„ ๋•Œ ready state ๋กœ ๋ฐ”๊พธ์–ด ์ฃผ๋ฉด ๋œ๋‹ค.

๊ตฌํ˜„ ๋ชฉํ‘œ

  • loop ๊ธฐ๋ฐ˜ wait() -> sleep-awake ๋กœ ๋ณ€๊ฒฝ
  • timer_sleep() ํ˜ธ์ถœ์‹œ thread๋ฅผ ready_list์—์„œ ์ œ๊ฑฐ, sleep queue์— ์ถ”๊ฐ€
  • wake up ์ˆ˜ํ–‰
    - timer interrupt๊ฐ€ ๋ฐœ์ƒ์‹œ tick ์ฒดํฌ
    - ์‹œ๊ฐ„์ด ๋‹ค ๋œ thread๋Š” sleep queue์—์„œ ์‚ญ์ œํ•˜๊ณ , ready_list์— ์ถ”๊ฐ€

์ˆ˜์ • ๋ฐ ์ถ”๊ฐ€ ํ•จ์ˆ˜

  • 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 ์•ˆ์น˜๊ฒŒ ํ•˜๋Š”๋ฒ•!!

  1. ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™

  2. code .bashrc ์ž…๋ ฅ

  3. ํŒŒ์ผ ์ œ์ผ ๋ฐ‘์— ๋ณธ์ธ์˜ source activate ๊ฒฝ๋กœ ์ถ”๊ฐ€

ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

  1. /pintos ๊ฒฝ๋กœ์—์„œ source ./activate (์‚ฌ์ „ ํ™˜๊ฒฝ ์„ค์ •์„ ํ–ˆ๋‹ค๋ฉด ์•ˆํ•ด์ค˜๋„ ๋œ๋‹ค!)

  2. threads ํด๋” ๋“ค์–ด๊ฐ€์„œ make clean make check๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด Test Case๋“ค์— ๋Œ€ํ•ด์„œ ์ฑ„์ ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  3. Test Case ํ•œ๊ฐ€์ง€๋งŒ ๋Œ๋ฆฌ๊ณ  ์‹ถ๋‹ค๋ฉด, pintos/(ํ”„๋กœ์ ํŠธ๋ช…)/build์— ๋“ค์–ด๊ฐ€์„œ ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋œ๋‹ค.
    pintos -T (Timout์ด ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„) -- -q -run (Test case ์ด๋ฆ„)
    ex) pintos -T 30 -- -q run alarm-multiple

๊ตฌํ˜„

์Šค๋ ˆ๋“œ ๋””์Šคํฌ๋ฆฝํ„ฐ ํ•„๋“œ ์ถ”๊ฐ€

  • include/threads/thread.h

    โ–ถ๏ธ 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 */
    .
    .
    .
    

์ „์—ญ๋ณ€์ˆ˜ ์ถ”๊ฐ€

  • threads/thread.c

    โ–ถ๏ธ 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;

.
.
.

๊ตฌํ˜„ํ•  ํ•จ์ˆ˜ ์„ ์–ธ

  • include/threads/thread.h
.
.
.

/** 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);

.
.
.

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

  • threads/thread.c

    โ–ถ๏ธ 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 ();
}

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

  • devices/timer.c

    โ–ถ๏ธ ๊ธฐ์กด์˜ 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() ํ•จ์ˆ˜ ๊ตฌํ˜„

  • threads/thread.c

    โ–ถ๏ธ 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
    }
}

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

  • devices/timer.c

โ–ถ๏ธ ๋งค 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);
	}
}

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

  • threads/thread.c

โ–ถ๏ธ 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
        }
    }
}

upadate_next_tick_to_awake() ํ•จ์ˆ˜ ์ถ”๊ฐ€

  • threads/thread.c

    โ–ถ๏ธ 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;
}

get_next_tick_to_awake() ํ•จ์ˆ˜ ์ถ”๊ฐ€

  • threads/thread.c
/** project1-Alarm Clock */
int64_t
get_next_tick_to_awake(void)
{
	return next_tick_to_awake;
}

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ


idle tick์ด 550์œผ๋กœ ์ฆ๊ฐ€

์ฐธ๊ณ 

[Pintos] Project 1 : Thread(์Šค๋ ˆ๋“œ) - Alarm Clock

profile
Sunny Day!

0๊ฐœ์˜ ๋Œ“๊ธ€