[Pintos-KAIST] Project 1 : Priority Donation

์œ ์„ ยท2024๋…„ 5์›” 2์ผ
1

Pintos - KAIST

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

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

๊ณผ์ œ ์„ค๋ช…

Priority Inverstion Problem์€ thread๊ฐ€ ๋‘ ๊ฐœ ์ด์ƒ์˜ lock๋ณด์œ ๊ฐ€๋Šฅํ•  ๋•Œ, ๋†’์€ priority์˜ thread๊ฐ€ ๋‚ฎ์€ priority์˜ thread๋ณด๋‹ค ๋Šฆ๊ฒŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์ ์„ ๋งํ•œ๋‹ค.

โœ”๏ธ ์ž์„ธํ•œ Priority Inversion Problem ์„ค๋ช… ํ™•์ธํ•˜๊ธฐ

Priority Inverstion

๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด,

H (high), M (medium), L (low) ๋ผ๋Š” ์„ธ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ๊ณ  ๊ฐ๊ฐ์˜ ์šฐ์„ ์ˆœ์œ„๋Š” H > M > L ์ด๋‹ค. H ๊ฐ€ L ์„ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋Š” ์ƒํ™ฉ(์˜ˆ๋ฅผ ๋“ค์–ด, H ๊ฐ€ lock ์„ ์š”์ฒญํ–ˆ๋Š”๋ฐ ์ด lock ์„ L ์ด ์ ์œ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ)์ด ์ƒ๊ธด๋‹ค๋ฉด H ๊ฐ€ L ์—๊ฒŒ CPU ์ ์œ ๋ฅผ ๋„˜๊ฒจ์ฃผ๋ฉด M ์ด L ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์œผ๋ฏ€๋กœ ์ ์œ ๊ถŒ์„ ์„ ์ ํ•˜์—ฌ ์‹คํ–‰๋˜์–ด์„œ ์Šค๋ ˆ๋“œ๊ฐ€ ๋งˆ๋ฌด๋ฆฌ ๋˜๋Š” ์ˆœ์„œ๊ฐ€ M->L->H ๊ฐ€ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ M ์ด ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ H ๋ณด๋‹ค ์šฐ์„ ํ•˜์—ฌ ์‹คํ–‰๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

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

priority donation

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด priority donation์„ ๊ตฌํ˜„ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

priority donation ์ด๋ž€ ์œ„์˜ ์ƒํ™ฉ์—์„œ H ๊ฐ€ ์ž์‹ ์ด ๊ฐ€์ง„ priority ๋ฅผ L ์—๊ฒŒ ์ผ์‹œ์ ์œผ๋กœ ์–‘๋„ํ•˜์—ฌ์„œ H ์ž์‹ ์˜ ์‹คํ–‰์„ ์œ„ํ•ด L ์ด ์ž์‹ ๊ณผ ๋™์ผํ•œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ ธ์„œ ์šฐ์„ ์ ์œผ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

ํ•€ํ† ์Šค documents ์—์„œ๋Š” priority donation ์ด ์ผ์–ด๋‚œ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ƒํ™ฉ์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค๊ณ  ํ•˜๋ฉด์„œ Multiple donation, Nested donation ๋‘ ๊ฐ€์ง€๋ฅผ ์–ธ๊ธ‰ํ•œ๋‹ค.

1. Multiple donation

  • lock์„ ์—ฌ๋Ÿฌ ๊ฐœ ์ ์œ ํ•œ ์Šค๋ ˆ๋“œ๋Š” lock์„ ์š”์ฒญํ•œ ์Šค๋ ˆ๋“œ์˜ priority ์ค‘ ๊ฐ€์žฅ ๋†’์€ priority๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
  • lock์„ ๋ฐ˜ํ™˜ํ•  ๊ฒฝ์šฐ์—๋Š”, ๋ฐ˜ํ™˜ํ•œ lock์„ ํš๋“ํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ์ œ์™ธํ•œ lock์„ ์š”์ฒญํ•œ ์Šค๋ ˆ๋“œ๋“ค์˜ priority ์ค‘์—์„œ ๊ฐ€์žฅ ๋†’์€ priority๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.

2. Nested donation

  • Donation์€ ์žฌ๊ท€์ ์œผ๋กœ ์ด์–ด์ง„๋‹ค.
    • T1์ด ์ ์œ ํ•œ lockA๋ฅผ T2๊ฐ€ ์š”์ฒญํ•˜๋ฉด (T2๊ฐ€ ๋” ๋†’์„ ๊ฒฝ์šฐ) T2์˜ priority๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
    • ์œ„ ์ƒํ™ฉ์—์„œ, T2๊ฐ€ ์ ์œ ํ•œ lockB๋ฅผ T3์ด ์š”์ฒญํ•˜๋ฉด (T3์ด ๋” ๋†’์„ ๊ฒฝ์šฐ) T1๊ณผ T2๋ฅผ T3์˜ priority๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.

์ˆ˜์ • ํ•จ์ˆ˜ ๋ฐ ์ž๋ฃŒ๊ตฌ์กฐ

  • void lock_acquire (struct lock *lock) : lock์„ ์ ์œ ํ•˜๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ์™€ ์š”์ฒญ ํ•˜๋Š” ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋น„๊ตํ•˜์—ฌ priority donation์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์ˆ˜์ •
  • void lock_release (struct lock *lock) : donation list ์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋„๋ก remove_with_lock(), refresh_prioriy() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ
  • void thread_set_priority (int new_priority) : ์Šค๋ ˆ๋“œ ์šฐ์„ ์ˆœ์œ„ ๋ณ€๊ฒฝ์‹œ donation์˜ ๋ฐœ์ƒ์„ ํ™•์ธ ํ•˜๊ณ  ์šฐ์„ ์ˆœ์œ„ ๋ณ€๊ฒฝ์„ ์œ„ํ•ด donation_priority()ํ•จ์ˆ˜ ์ถ”๊ฐ€
  • struct thread

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

  • void donate_priority(void) : priority donation์„ ์ˆ˜ํ–‰
  • void remove_with_lock(struct lock *lock) : donation list์—์„œ ์Šค๋ ˆ๋“œ ์—”ํŠธ๋ฆฌ๋ฅผ ์ œ๊ฑฐ
  • void refresh_priority(void) : ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐ

์‚ฌ์ „ ํ™˜๊ฒฝ ์„ค์ •

๋™์ž‘ ์ˆœ์„œ ์ค‘ 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 donate-one

๊ตฌํ˜„

struct thread์— prioriry donation๊ด€๋ จ ํ•ญ๋ชฉ ์ถ”๊ฐ€

  • include/threads/thread.h
    • donation ์ดํ›„ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ดˆ๊ธฐ ์šฐ์„ ์ˆœ์œ„ ๊ฐ’์„ ์ €์žฅํ•  ํ•„๋“œ
    • ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” lock ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ฃผ์†Œ๋ฅผ ์ €์žฅํ•  ํ•„๋“œ
    • multiple donation์„ ๊ณ ๋ คํ•˜๊ธฐ ์œ„ํ•œ ๋ฆฌ์ŠคํŠธ ์ถ”๊ฐ€
      • ํ•ด๋‹น ๋ฆฌ์ŠคํŠธ๋ฅผ ์œ„ํ•œ elem๋„ ์ถ”๊ฐ€
.
.
.
	/** project1-Priority Inversion Problem */
	int original_priority;
    struct lock *wait_lock;
    struct list donations;
    struct list_elem donation_elem;
.
.
.

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

  • threads/thread.c

    Priority donation ๊ด€๋ จ ์ž๋ฃŒ๊ตฌ์กฐ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ ์‚ฝ์ž…

static void
init_thread (struct thread *t, const char *name, int priority) {
	ASSERT (t != NULL);
	ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
	ASSERT (name != NULL);

	memset (t, 0, sizeof *t);
	t->status = THREAD_BLOCKED;
	strlcpy (t->name, name, sizeof t->name);
	t->tf.rsp = (uint64_t) t + PGSIZE - sizeof (void *);

	/** project1-Priority Inversion Problem */
    t->priority = t->original_priority = priority;
    list_init(&t->donations);
    t->wait_lock = NULL;

	t->magic = THREAD_MAGIC;
}

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

  • threads/synch.c
    • ํ•ด๋‹น lock์˜ holder๊ฐ€ ์กด์žฌํ•˜์—ฌ wait์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์•„๋ž˜ ๋™์ž‘์„ ์ˆ˜ํ–‰.
      • wait์„ ํ•˜๊ฒŒ ๋  lock ์ž๋ฃŒ๊ตฌ์กฐ ํฌ์ธํ„ฐ ์ €์žฅ
        • ์“ฐ๋ ˆ๋“œ ๋””์Šคํฌ๋ฆฝํ„ฐ์— ์ถ”๊ฐ€ํ•œ ํ•„๋“œ
      • lock์˜ ํ˜„์žฌ holder์˜ ๋Œ€๊ธฐ์ž list์— ์ถ”๊ฐ€
      • priority donation์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ ์ถ”๊ฐ€
        • ๊ตฌํ˜„ํ•˜๊ฒŒ ๋  ํ•จ์ˆ˜์ธ donate_priority()
      • lock ํš๋“ ํ›„ lock์˜ holder ๊ฐฑ์‹ 
void
lock_acquire (struct lock *lock) {
	ASSERT (lock != NULL);
	ASSERT (!intr_context ());
	ASSERT (!lock_held_by_current_thread (lock));

   /** project1-Priority Inversion Problem */
   struct thread *t = thread_current();
    if (lock->holder != NULL) {
        t->wait_lock = lock;
        list_push_back(&lock->holder->donations, &t->donation_elem);
        donate_priority();
    }

	sema_down (&lock->semaphore);

   /** project1-Priority Inversion Problem */
   t->wait_lock = NULL;
   lock->holder = t;
}

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

  • include/threads/thread.h
.
.
.
/** project1-Priority Inversion Problem */
void donate_priority(void);
void remove_with_lock(struct lock *lock);
void refresh_priority(void);
.
.
.
  • threads/thread.c
    • void donate_priority(void)
    • priority donation์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜
    • Nested donation์„ ๊ณ ๋ คํ•˜์—ฌ ๊ตฌํ˜„
      • ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” lock๊ณผ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์“ฐ๋ ˆ๋“œ๋“ค์„ ์ˆœํšŒํ•˜๋ฉฐ ํ˜„
        ์žฌ ์“ฐ๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ lock์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ์—๊ฒŒ ๊ธฐ๋ถ€
      • nested depth๋Š” 8๋กœ ์ œํ•œ
/** project1-Priority Inversion Problem */
void 
donate_priority() 
{
    struct thread *t = thread_current();
    int priority = t->priority;

    for (int depth = 0; depth < 8; depth++) 
	{
        if (t->wait_lock == NULL)
            break;

        t = t->wait_lock->holder;
        t->priority = priority;
    }
}

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

  • threads/synch.c
    • lock์„ ํ•ด์ œํ•œ ํ›„, ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์˜ ๋Œ€๊ธฐ ๋ฆฌ์ŠคํŠธ ๊ฐฑ์‹  (remove_with_lock() ์‚ฌ์šฉ)
    • priority๋ฅผ donation ๋ฐ›์•˜์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์›๋ž˜์˜ priorit๋กœ ์ดˆ๊ธฐํ™” (refresh_priority() ์‚ฌ์šฉ)
void
lock_release (struct lock *lock) {
	ASSERT (lock != NULL);
	ASSERT (lock_held_by_current_thread (lock));

	lock->holder = NULL;

   /** project1-Priority Inversion Problem */
   remove_with_lock(lock);
   refresh_priority();

	sema_up (&lock->semaphore);
}

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

  • threads/thread.c
    • lock์„ ํ•ด์ง€ ํ–ˆ์„ ๋•Œ, waiters ๋ฆฌ์ŠคํŠธ์—์„œ ํ•ด๋‹น ์—”ํŠธ๋ฆฌ๋ฅผ ์‚ญ์ œ ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„
    • ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์˜ waiters ๋ฆฌ์ŠคํŠธ๋ฅผ ํ™•์ธํ•˜์—ฌ ํ•ด์ง€ํ•  lock์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ์—”ํŠธ๋ฆฌ๋ฅผ ์‚ญ์ œ
/** project1-Priority Inversion Problem */
void remove_with_lock(struct lock *lock) 
{
    struct thread *t = thread_current();
    struct list_elem *curr = list_begin(&t->donations);
    struct thread *curr_thread = NULL;

    while (curr != list_end(&t->donations)) 
	{
        curr_thread = list_entry(curr, struct thread, donation_elem);

        if (curr_thread->wait_lock == lock)
            list_remove(&curr_thread->donation_elem);

        curr = list_next(curr);
    }
}

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

  • threads/thread.c
    • ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋ณ€๊ฒฝ ๋˜์—ˆ์„ ๋•Œ, donation์„ ๊ณ ๋ คํ•˜์—ฌ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋‹ค์‹œ ๊ฒฐ์ •ํ•˜๋Š” ํ•จ์ˆ˜
    • ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ธฐ๋ถ€ ๋ฐ›๊ธฐ ์ „์˜ ์šฐ์„ ์ˆœ์œ„๋กœ ๋ณ€๊ฒฝ
    • ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์˜ waiters ๋ฆฌ์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„์™€ ๋น„๊ต ํ›„ ์šฐ์„ ์ˆœ์œ„ ์„ค์ •
/** project1-Priority Inversion Problem */
void refresh_priority(void) 
{
    struct thread *t = thread_current();
    t->priority = t->original_priority;

    if (list_empty(&t->donations))
        return;

    list_sort(&t->donations, cmp_priority, NULL);

    struct list_elem *max_elem = list_front(&t->donations);
    struct thread *max_thread = list_entry(max_elem, struct thread, donation_elem);

    if (t->priority < max_thread->priority)
        t->priority = max_thread->priority;
}

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

  • threads/thread.c
  • refresh_priority() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์šฐ์„ ์ˆœ์œ„์˜ ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•œ donation ๊ด€๋ จ
    ์ •๋ณด๋ฅผ ๊ฐฑ์‹ 
  • donation_priority(), test_max_priority() ํ•จ์ˆ˜๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜์—ฌ priority
    donation์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์Šค์ผ€์ค„๋ง
void
thread_set_priority (int new_priority) {
	thread_current ()->priority = new_priority;

	/** project1-Priority Inversion Problem */
    thread_current()->original_priority = new_priority;

	/** project1-Priority Inversion Problem */
    refresh_priority();

	/** project1-Priority Scheduling */
	test_max_priority();
}

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

ํ†ต๊ณผ๋˜์–ด์•ผํ•˜๋Š” ํ…Œ์ŠคํŠธ

  • donate-one
  • donate-multiple
  • donate-multiple2
  • donate-nest
  • donate-sema
  • donate-lower

์ฐธ๊ณ 

profile
Sunny Day!

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