DevLog ๐Ÿ“จ

[DevLog][PintOS] PRJ1 Threads/Priority Scheduling

cece00 2023. 9. 27. 16:21

์šฐ์„ ์ˆœ์œ„ ์Šค์ผ€์ค„๋ง

Assignment Overview

์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ณ ๋ คํ•ด ์Šค๋ ˆ๋“œ๋ฅผ ์Šค์ผ€์ค„๋งํ•ด๋ผ. ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ step์ด ์žˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ๋‹จ์ˆœํžˆ ์ค€๋น„ ํ๋ฅผ ์ •๋ ฌํ•˜๊ณ , ์ฆ‰์‹œ CPU๋ฅผ ์–‘๋„ํ•˜๋ฉด ํ•ด๊ฒฐ๋œ๋‹ค. ๋‘ ๋ฒˆ์งธ๋Š” ๋™๊ธฐํ™” (synchronization)์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ๋กœ, ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜์—์„œ๋„ ์šฐ์„ ์ˆœ์œ„๋Œ€๋กœ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด ์šฐ์„ ์ˆœ์œ„ ๊ธฐ์ฆ (priority donation)์ด๋‹ค.

  • ๋ฌธ์ œ 1: ์ฃผ์–ด์ง„ ์šฐ์„ ์ˆœ์œ„๋Œ€๋กœ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ๋งŒ๋“ค์–ด๋ผ
    • ์Šค๋ ˆ๋“œ๋Š” ์ค€๋น„ ํ์—์„œ ์šฐ์„ ์ˆœ์œ„ ์ˆœ์„œ๋Œ€๋กœ ๋‚˜์™€์•ผ ํ•œ๋‹ค.
    • ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค€๋น„ ํ์— ๋“ค์–ด์˜ค๋ฉด, ์ฆ‰์‹œ CPU๋ฅผ ์–‘๋ณดํ•ด์•ผ ํ•œ๋‹ค.
    • ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด, ์ค€๋น„ ํ์˜ ์Šค๋ ˆ๋“œ์™€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋น„๊ตํ•ด์„œ ์ ์ ˆํžˆ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
  • ๋ฌธ์ œ 2: ์šฐ์„ ์ˆœ์œ„ ์—ญ์ „ (Priority Inversion)์„ ํ•ด๊ฒฐํ•ด๋ผ.
    • ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž์‹ ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ๋ง‰ํ˜€ ์‹คํ–‰์ด ๋˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ผ
    • ์—ฌ๊ธฐ์„œ '๋ง‰ํ˜€ ์‹คํ–‰์ด ๋˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š”' ์ƒํƒœ๋ž€ ๊ตฌ์ฒด์ ์œผ๋กœ lock, semaphore, conditional variable ๋“ฑ์˜ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ์˜ํ•ด blocked ๋œ ์ƒํƒœ๋ฅผ ๋งํ•œ๋‹ค.
    • ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ, ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž์‹ ์„ ๋ง‰๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ์—๊ฒŒ ์ž์‹ ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ธฐ์ฆ(donation)ํ•ด์„œ lock์„ ๋นจ๋ฆฌ ํ•ด์ œํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.
    • ์Šค๋ ˆ๋“œ๊ฐ€ lock์„ ํ’€๊ณ  ๋‚˜์˜ฌ ๋•Œ, ๋งŒ์•ฝ ๊ธฐ์ฆ๋ฐ›์€ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์žˆ์œผ๋ฉด ๋ชจ๋‘ ๋ฐ˜ํ™˜ํ•˜์—ฌ, ์‹ค์ œ ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ์—๊ฒŒ ์ฆ‰์‹œ CPU๋ฅผ ์–‘๋„ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.
    • ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ lock์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๊ณ (multiple), ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•˜๋Š” lock์„ ๊ฐ€์ง„ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ lock์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ์„ ์ˆ˜ ๋„ ์žˆ๋‹ค. (nested)

Implementation

01) ๋ฌธ์ œ 1

1) ์ค€๋น„ ํ๋ฅผ ์šฐ์„ ์ˆœ์œ„์ˆœ์œผ๋กœ ์ •๋ ฌํ•ด์•ผ ํ•œ๋‹ค.

์ด๋Š” ์ค€๋น„ ํ์— ์Šค๋ ˆ๋“œ๋ฅผ ๋„ฃ์„ ๋•Œ ์‚ฝ์ž… ์ •๋ ฌ์„ ํ•˜๊ฑฐ๋‚˜, ๋บ„ ๋•Œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ์ตœ๋Œ€ ์šฐ์„ ์ˆœ์œ„๋ถ€ํ„ฐ ์Šค์ผ€์ค„๋งํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์šฐ๋ฆฌ ํŒ€์€ ์‚ฝ์ž… ์ •๋ ฌ ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค.

void thread_unblock(struct thread* t) {
    ...
    list_insert_ordered(&ready_list, &t->elem, high_priority, NULL);
    ...
}

/* compare function */
bool high_priority(struct list_elem* _a, struct list_elem* _b, void* aux) {
    struct thread* a = list_entry(_a, struct thread, elem);
    struct thread* b = list_entry(_b, struct thread, elem);
    return a->priority > b->priority; 
}

2) ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋ณด๋‹ค ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์˜ค๋ฉด CPU๋ฅผ ์ฆ‰์‹œ ์–‘๋ณดํ•ด์•ผ ํ•œ๋‹ค.

์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ด์— ๋งž๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. (๋‚ด๊ฐ€ ๋‚ฎ์•„์กŒ์œผ๋ฉด ์–‘๋ณดํ•ด์•ผ ํ•  ์ƒํ™ฉ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ)

void thread_create(...) {
    ...

    thread_unblock(t);  /* ready_list์— ์‚ฝ์ž… ์ •๋ ฌ */

    thread_yield();     /* ํ•œ ๋ฒˆ yield๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. */
    intr_enable();      /* yield๋กœ CPU๋ฅผ ์ ์œ ํ•˜๊ฒŒ ๋œ ์Šค๋ ˆ๋“œ๊ฐ€ ์ธํ„ฐ๋ŸฝํŠธ๋ฅผ ํ—ˆ์šฉ */
}

void thread_set_priority(int new_priority) {
    thread_current()->priority = new_priority;

    thread_yield();     /* ํ•œ ๋ฒˆ yield๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. */
}

์ด ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ, ๊ทธ๋ฆฌ๊ณ  ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ thread_yield()๋ฅผ ํ•œ ๋ฒˆ์”ฉ ์‹คํ–‰ํ•ด ์คŒ์œผ๋กœ์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ค€๋น„ ํ๊ฐ€ ๋Š˜ ์šฐ์„ ์ˆœ์œ„ ๋†’์€์ˆœ์œผ๋กœ ์œ ์ง€๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. thread_yield()๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ํ˜„์žฌ ์‹คํ–‰์ค‘์ด๋˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ค€๋น„ ํ์— (์‚ฝ์ž…์ •๋ ฌ์œผ๋กœ) ๋„ฃ๊ณ  schedule()์„ ํ˜ธ์ถœํ•˜์—ฌ ๋‹ค์Œ์— ์‹คํ–‰๋  ์Šค๋ ˆ๋“œ๋ฅผ ํ์—์„œ ๋ฝ‘๋Š”๋‹ค. ์ด ๋•Œ ํ˜„์žฌ ์Šค๋ ˆ๋“œ์™€ ๋‹ค์Œ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅด๋ฉด thread_launch()๋ฅผ ํ˜ธ์ถœํ•ด (ํ˜„์žฌ ๋ ˆ์ง€์Šคํ„ฐ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ , ๋‹ค์Œ ์Šค๋ ˆ๋“œ์˜ context๋ฅผ ์˜ฌ๋ฆฌ๋Š”) ์‹ค์งˆ์ ์ธ context switching์ด ์ผ์–ด๋‚˜๊ฒŒ ๋œ๋‹ค. ์ด ์กฐ๊ฑด๋ฌธ (if(curr != next))์ด ์ด๋ฏธ ๊ฑธ๋ ค ์žˆ์œผ๋ฏ€๋กœ, thread_create()๋‚˜ thread_set_priority()์—์„œ ๋”ฐ๋กœ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋น„๊ตํ•˜๋Š” ์กฐ๊ฑด๋ฌธ์„ ๊ฑธ์ง€ ์•Š๊ณ , thread_yield๋ฅผ ๋ฐ”๋กœ ํ˜ธ์ถœํ•ด๋„ ๋œ๋‹ค.

๋ฌธ์ œ 2) Donation

๋™๊ธฐํ™”๊ฐ€ ๊ฐœ์ž…๋˜๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ๋ณต์žกํ•ด์ง„๋‹ค. ๋‚ด๊ฐ€ ์ฝ”๋“œ๋ฅผ ์งœ๋ฉด์„œ ์–ด๋ ค์› ๋˜ ์ง€์ ์ด ๋ช‡ ๊ฐ€์ง€ ์žˆ์—ˆ๋‹ค.

  1. ํ•จ์ˆ˜์˜ ์‹คํ–‰์ด ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์—์„œ ์›์ž์ ์œผ๋กœ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค. ์ฝ”๋“œ์˜ ๊ฐ ๋ผ์ธ์ด ์–ด๋Š ์Šค๋ ˆ๋“œ์—์„œ ์–ด๋””๊นŒ์ง€ ์‹คํ–‰๋˜๊ณ  ๋„˜์–ด๊ฐ€๋Š”์ง€๋ฅผ ๋จธ๋ฆฟ์†์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ฒƒ์ด ํ—ท๊ฐˆ๋ ธ๋‹ค.
  2. donate๋ฅผ ํ•œ ์Šค๋ ˆ๋“œ์™€ donate๋ฅผ ๋ฐ›์€ ์Šค๋ ˆ๋“œ๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•  ๊ฒƒ์ธ๊ฐ€?
  3. lock์ด multipleํ•˜๊ฒŒ ๊ฑธ๋ฆฐ ๊ฒฝ์šฐ์™€ nestedํ•˜๊ฒŒ ๊ฑธ๋ฆฐ ๊ฒฝ์šฐ, lock_acquire์™€ lock_release์—์„œ ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ•ด ์ค˜์•ผ ํ• ๊นŒ?

1) ์Šค๋ ˆ๋“œ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ž˜ ์ถ”์ ํ•˜์ž

1๋ฒˆ ๋ฌธ์ œ์™€ ๊ฐ™์€ ๊ฒฝ์šฐ๊ฐ€ ๋‹ค์Œ์˜ ์ƒํ™ฉ์ด๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ low ์Šค๋ ˆ๋“œ๊ฐ€ lock์˜ holder์ธ ์ƒํ™ฉ์—์„œ current_thread์ธ high๊ฐ€ lock_acquire๋ฅผ ์‹œ๋„ํ•œ๋‹ค๊ณ  ํ•˜์ž.

void lock_acquire(struct lock* lock) {
    ... // ๊ธฐํƒ€๋“ฑ๋“ฑ..

    struct thread* curr = thread_current();
    struct thread* holder = lock->holder;

    /* donation */
    if(holder && curr->priority > holder->priority) {
        holder->priority = curr->priority;
    }

    sema_down(...);
    lock->holder = thread_current();

    /* ๋‚˜๋Š” sema์˜ ์ฃผ์ธ์ด ๋˜์—ˆ๋‹ค! ์—ฌ๊ธฐ์„œ ๊ธฐ์ฆํ–ˆ๋˜ ๊ฒƒ์„ ๋ฐ˜ํ™˜๋ฐ›์œผ๋ฉด ์•ˆ ๋ ๊นŒ? */
    /* ์˜ˆ๋ฅผ ๋“ค์–ด ์ด์ „ holder๋ฅผ ์ €์žฅํ•ด๋‘๊ณ , holder->priority = old_priority */
    ...
}

์ฝ”๋ฉ˜ํŠธ์— ๋‹ฌ๋ฆฐ ๋ถ€๋ถ„์— ๊ธฐ์ฆ์˜ ๋ฐ˜ํ™˜ ๋กœ์ง์„ ์งœ๋ฉด ์•ˆ ๋œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด, holder์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ž”๋œฉ ์˜ฌ๋ ค ๋†“์€ ์ƒํƒœ์—์„œ lock์„ ํš๋“ํ•œ ํ›„ ๋ฐ˜ํ™˜์„ ํ•˜๊ณ ์ž ํ•œ๋“ค, holder์˜ ์‹คํ–‰์— ๋ง‰ํ˜€ ์ •์ž‘ ์ง„์งœ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์•˜๋˜ ๋‚˜(ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ ์Šค๋ ˆ๋“œ)๋Š” ์‹คํ–‰์ด ์•ˆ ๋˜๊ณ  holder๊ฐ€ ๋๋‚  ๋•Œ ๊นŒ์ง€ ready_list์—๋งŒ ๋‚จ์•„์žˆ๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, sema_down ๋ผ์ธ์˜ ๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ๋ฐ”๋กœ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

๊ทธ๋ž˜์„œ acquireํ•  ๋•Œ๋Š” ๋‚˜๋ฅผ ๋ง‰๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ (lock->holder)์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋†’์—ฌ์ฃผ์–ด์•ผ ํ•˜๊ณ , lock_release๋ฅผ ํ•  ๋•Œ๋Š” (์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ์€ ์ž…์žฅ์—์„œ) ๋‚˜์˜ lockํ•ด์ œ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋˜ ์Šค๋ ˆ๋“œ๋“ค์ด ๊ธฐ์ฆํ•œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ชจ๋‘ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. ๋‹ค๋ฅธ ๋ง๋กœ ํ•˜๋ฉด, acquire์—์„œ๋Š” higer thread, release์—์„œ๋Š” lower thread์˜ ์ž…์žฅ์—์„œ ๋กœ์ง์„ ์งœ์•ผ ํ•œ๋‹ค.

๋™๊ธฐํ™” ๋ฌธ์ œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์Šค๋ ˆ๋“œ๋ฅผ ๋‹ค๋ฃจ๋ฉด์„œ๋Š” ์ฝ”๋“œ ๊ฐ ๋ผ์ธ์„ ์‹ค์ œ๋กœ ์–ด๋–ค ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋Š”์ง€๋ฅผ ์ž˜ ์ƒ๊ฐํ•ด์•ผ ํ•œ๋‹ค.

2) donation ์ •๋ณด๋ฅผ ๊ฐ–๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ž˜ ์„ค๊ณ„ํ•˜์ž

donation์˜ ๊ด€๊ณ„๋ฅผ ์ž˜ ์ƒ๊ฐํ•ด ๋ด์•ผ ํ•œ๋‹ค. donate๋ฅผ ํ•˜๋Š” ์Šค๋ ˆ๋“œ์™€, donate๋ฅผ ๋ฐ›๋Š” ์Šค๋ ˆ๋“œ์˜ ๊ด€๊ณ„๋Š” ์ผ๋Œ€ ๋‹ค ๊ด€๊ณ„์ด๋‹ค. ์–ด๋–ค ์Šค๋ ˆ๋“œ t๊ฐ€ donate๋ฅผ ํ–ˆ๋‹ค๋ฉด, t๋Š” lock์— ๋ง‰ํ˜€ waiters์˜ ๋ฆฌ์ŠคํŠธ์— blocked๋œ ์ƒํƒœ๋กœ ๋“ค์–ด๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ, ํ•œ ์Šค๋ ˆ๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ lock์„ waitingํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋  ์ˆ˜ ์—†๋‹ค.

ํ•˜์ง€๋งŒ donate์„ ๋ฐ›๋Š” ์ž…์žฅ์—์„œ๋Š”, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์šฐ์„ ์ˆœ์œ„๋ฅผ donate๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Š” ๋ฆฌ์ŠคํŠธ ๋˜๋Š” ๋ฐฐ์—ด๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. ์šฐ๋ฆฌ ์กฐ์—์„œ๋Š” ๋จผ์ € ๋ฐฐ์—ด์˜ ์•„์ด๋””์–ด๋ฅผ ๋– ์˜ฌ๋ ธ๋‹ค.

struct thread {

    ...
    int donate_list[64];     /* ๋‚ด๊ฐ€ ๋ฐ›์€ donation */
    struct thread* holder;   /* ๋‚ด๊ฐ€ donateํ•œ ์•  */
    ...
}

/* donate์„ ๋ฐ›๋Š” ์ƒํ™ฉ์—์„œ๋Š” */
lock->holder->donate_list[curr_priority]++;

/* donate์„ ํšŒ์ˆ˜ํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” */
curr_thread->donate_list[donator_priority]--;

์ด๋Ÿฐ ์‹์œผ๋กœ ๊ธฐ์ฆ๋ฐ›์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ donation์œผ๋กœ ์ธํ•ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ๋น„๊ตํ•˜๋Š” ํ•จ์ˆ˜๋„ ๋ชจ๋‘ ๋ฐ”๊พธ์–ด์ค€๋‹ค.

๋‚ด๊ฐ€ donateํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ์˜๋ฏธํ•˜๋Š” holder์˜ ์ •๋ณด๋Š”, nested donation์„ ์œ„ํ•ด ํ•„์š”ํ•˜๋‹ค. ๋‚ด๊ฐ€ lock a์— ์ ‘๊ทผํ–ˆ๋Š”๋ฐ, lock a์˜ holder๊ฐ€ lock b์˜ waiters์— ๋“ค์–ด๊ฐ€ ์žˆ๋‹ค๋ฉด, lock->holder->holder์™€ ๊ฐ™์€ ์‹์œผ๋กœ holder๋ฅผ ๊ฒ€์ƒ‰ํ•ด์„œ lock b์˜ holder์—๊ฒŒ ๋‚˜์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ธฐ์ฆํ•ด์•ผ ํ•œ๋‹ค.

/* donate์„ ๊ณ ๋ คํ•˜์—ฌ ํŠน์ • ์Šค๋ ˆ๋“œ์˜ ์ตœ๊ณ  ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ ค๋ฉด */
int thread_max_priority(struct thread* t) {
    int i = 0;
    int max_priority = t->priority;

    for(; i < 64; i++) {
        if(t->donate_list[i] > 0 && i > max_priority) {
            max_priority = i;
        }
    }
    return max_priority;
}

/* ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„ ๊ตฌํ•˜๋Š” ํ•จ์ˆ˜ ๊ฐฑ์‹ ! */
int thread_get_priority(void) {
    return thread_max_priority(thread_current());
}

/* ordered list insert์˜ ๋น„๊ตํ•จ์ˆ˜๋„ ๊ฐฑ์‹ ! */
bool high_priority(...) {
    ...
    return thread_max_priority(a) > thread_max_priority(b);
}

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ค€๋น„ ํ์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ donation์œผ๋กœ ์ธํ•ด ๋ฐ”๋€” ์ˆ˜ ์žˆ์Œ์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ test case์—์„œ donate์„ ๋ฐ›๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ main์œผ๋กœ ํ•˜๋‚˜๋ผ์„œ ์ž˜ ํ†ต๊ณผ๋˜์—ˆ์ง€๋งŒ, ๋งŒ์•ฝ ์ค€๋น„ ํ์—์„œ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋˜ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ donate์„ ๋ฐ›์•˜๋‹ค๋ฉด, ์ค€๋น„ ํ๊ฐ€ ์žฌ์ •๋ ฌ๋  ํ•„์š”์„ฑ์ด ์ƒ๊ธด๋‹ค. ์ด ๋•Œ๋„ ๋ฌผ๋ก  thread_next_to_run์—์„œ ์ตœ๊ณ  ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋ฝ‘์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์šฐ๋ฆฌ ์กฐ์—์„œ๋Š” ํ•œ๋ฒˆ reorder(?) ํ•ด์ฃผ๊ธฐ๋กœ ํ–ˆ๋‹ค.

// sync.c
void lock_acquire(struct lock* lock) {
    ...

    /* ์—ฌ๊ธฐ์„œ lock->holder์—๊ฒŒ donation์„ ํ–ˆ๋‹ค๋ฉด */
    /* ready_list์—์„œ ํ•œ๋ฒˆ ๋ฝ‘์•˜๋‹ค๊ฐ€ ๋‹ค์‹œ ์‚ฝ์ž…์ •๋ ฌํ•œ๋‹ค. */
    if(lock->holder->statuc == THREAD_READY) {
        thread_reorder(lock->holder);
    }

    sema_down(&lock->semaphore);
    ...
}

// thread.c
void thread_reorder(struct thread* t) {
    ASSERT(t->status == THREAD_READY);

    list_remove(&t->elem);
    list_insert_ordered(&ready_list, &t->elem, high_priority, NULL);
}

donate ๊ด€๋ จ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ์ด์™ธ์—๋„ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋ฅผํ…Œ๋ฉด donate์„ ์ค€ ์Šค๋ ˆ๋“œ๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

struct thread {
    ...
    struct list donate_list;

    struct list_elem d_elem; // ์–˜๋ผ๋ฆฌ ์—ฐ๊ฒฐ
}

thread ๊ตฌ์กฐ์ฒด ๋‚ด๋ถ€์— ์žˆ๋Š” struct list_elem ๊ฐ„ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์˜ donate_list์— ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋Š” ์ƒํ™ฉ์„ ๊ฒฝ๊ณ„ํ•ด์•ผ ํ•œ๋‹ค.

๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ lock๋งˆ๋‹ค ์ž์‹ ์˜ waiters์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ ์ค‘ max ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ด€๋ฆฌํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์Šค๋ ˆ๋“œ๊ฐ€ ์ž์‹ ์ด ์†Œ์œ ํ•œ lock์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด, lock์„ releaseํ•  ๋•Œ ๋งˆ๋‹ค lock์„ ๋ฆฌ์ŠคํŠธ์—์„œ ์‚ญ์ œํ•˜๋Š” ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค. (์•„์ง ์ƒ๊ฐ์ผ ๋ฟ ๊ตฌํ˜„์€ ์•ˆ ํ–ˆ๋‹ค.) ์ด ๊ฒฝ์šฐ, lock์˜ waiters์˜ max ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ž˜ ๊ฐฑ์‹ ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ๊ด€๊ฑด์ด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

๊ตฌํ˜„์˜ ๋ฐฉ๋ฒ•์ด ๋งค์šฐ ๋‹ค์–‘ํ•˜๋‹ค. ๊ทธ ์ค‘์—์„œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋œ ์žก์•„๋จน๊ณ , (์Šค๋ ˆ๋“œ ๊ตฌ์กฐ์ฒด์˜ ํฌ๊ธฐ๋Š” ์•ฝ 1KB๋กœ ์ œํ•œ๋œ๋‹ค. ์Šคํƒ์˜ ํฌ๊ธฐ๋„ ์ž‘์•„์„œ ๋ฐฐ์—ด ๋งŽ์ด ๋„ฃ์œผ๋ฉด stack overflow ๋‚œ๋‹ค.) ๋ฆฌ์ŠคํŠธ์˜ ๊ฒ€์ƒ‰ ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ.. ์ž˜ ๊ท ํ˜•์„ ์žก์•„์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ปค๋„ ์Šค๋ ˆ๋“œ๋Š” ๋งŽ์ด ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๋ฉด ์ข‹๋‹ค.

3) multiple, nested donation ์ƒํ™ฉ์„ ๊ณ ๋ คํ•˜์ž

multiple donation ์ƒํ™ฉ์€ ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ lock์„ ๋“ค๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ด๋‹ค.

thread 0 = low
thread 1 = mid
thread 2 = high

thread 0 ์ด lock a๋ฅผ ๊ฐ–๋Š”๋‹ค.
thread 0 ์ด lock b๋ฅผ ๊ฐ–๋Š”๋‹ค.

thread 1 ์ด ์ƒ์„ฑ๋˜์–ด lock a์— ์ ‘๊ทผํ•œ๋‹ค.
thread 2 ๊ฐ€ ์ƒ์„ฑ๋˜์–ด lock b์— ์ ‘๊ทผํ•œ๋‹ค.

thread 0 ์ด lock a๋ฅผ ํ‘ผ๋‹ค.
thread 0 ์ด lock b๋ฅผ ํ‘ผ๋‹ค.

์ด ๊ฒฝ์šฐ, thread 0์˜ ์šฐ์„ ์ˆœ์œ„๋Š” low โ†’ mid โ†’ high ๋กœ ๋†’์•„์ง„๋‹ค. ๊ทธ๋ฆฌ๊ณ  lock a๋ฅผ ํ’€ ๋•Œ, ์šฐ์„ ์ˆœ์œ„๊ฐ€ high๋กœ ์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค. ์™œ? lock b์˜ waiters๋กœ thread 2(high)๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ธฐ์ฆํ•˜๊ณ .. ํšŒ์ˆ˜ํ•˜๊ณ  ์ด ๋‚œ๋ฆฌ๋ฅผ ์™œ ์น˜๋Š”์ง€๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์ž. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ์ž‘์—…์„ ๋นจ๋ฆฌ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ์ด๋‹ค. ์ฆ‰, thread 0์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ high๋กœ ๋†’์•„์ง„ ์ด์œ ๋Š”, thread 2(high)๋ฅผ waiters์—์„œ ๋นจ๋ฆฌ ๋‚ด๋ณด๋‚ด๊ธฐ ์œ„ํ•จ์ด๋ฏ€๋กœ, lock a๋ฅผ ํ’€์—ˆ๋‹ค๊ณ  ํ•ด์„œ thread 1(mid)๋ฅผ ๋จผ์ € ์‹คํ–‰ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ lock b๋ฅผ ๋นจ๋ฆฌ ํ’€์–ด์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋”ฐ๋ผ์„œ thread 0๋Š” lock a๋ฅผ ํ’€๊ณ , thread 1๋กœ๋ถ€ํ„ฐ ๊ธฐ์ฆ๋ฐ›์•˜๋˜ ์šฐ์„ ์ˆœ์œ„ mid๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (donate_list์—์„œ ์‚ญ์ œํ•œ๋‹ค.) ๊ทธ๋ฆฌ๊ณ  ๊ธฐ์ฆ๋ฐ›์€ ์šฐ์„ ์ˆœ์œ„ high๋ฅผ ์œ ์ง€ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด thread 2(mid)๋Š” ready_list๋กœ ๋“ค์–ด๊ฐ€๊ณ , current thread๋Š” ์—ฌ์ „ํžˆ thread 0์ด๋ฏ€๋กœ ๋‹ค์Œ ๋ผ์ธ์œผ๋กœ ๊ฐ€์„œ lock b๋ฅผ ํ‘ผ๋‹ค. ์ด ๋•Œ thread 2๋กœ๋ถ€ํ„ฐ ๊ธฐ์ฆ๋ฐ›์•˜๋˜ high๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์šฐ์„ ์ˆœ์œ„๊ฐ€ low๋กœ ๋‚ฎ์•„์ ธ ready_list๋กœ ๋“ค์–ด๊ฐ„๋‹ค. ๋ฐ˜ํ™˜์ด ๋ชจ๋‘ ๋๋‚ฌ์œผ๋ฏ€๋กœ thread 2(high)๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜๊ณ , thread 1(mid)๊ฐ€ ์‹คํ–‰, ๋งˆ์ง€๋ง‰์œผ๋กœ thread 0(low)๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

์ด์— ๋”ฐ๋ผ ์ฝ”๋“œ๋ฅผ ์งœ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

/* lock acquire ํ•  ๋•Œ ๊ธฐ์ฆ์„ ํ•œ๋‹ค */
void lock_acquire(struct lock* lock) {

    struct thread* curr = thread_current();
    struct thread* holder = lock->holder;

    if(thread_max_priority(curr) > thread_max_priority(holder)) {
        holder->donate_list[curr->priority]++;
    }

    sema_down(lock->semaphore);
    lock->holder = thread_current();
}

/* sema์˜ waiters๋ฅผ ์šฐ์„ ์ˆœ์œ„์ˆœ์œผ๋กœ ๋บธ๋‹ค */
void sema_up(struct semaphore *sema) {
    ...

    /* ํ˜„์žฌ ์Šค๋ ˆ๋“œ ๋‹ค์Œ์œผ๋กœ sema๋ฅผ ์žก์„ ์•  */
    struct list_elem* next_elem;
    struct thread* next;

    if(!list_empty(&sema->waiters)) {
        next_elem = min(&sema->waiters, high_priority, NULL); // less func์ด๋ฏ€๋กœ min
        next = list_entry(next_elem, struct thread, elem);

        list_remove(next);
        thread_unblock(next);
    }
    sema->value++;
    intr_enable();
}

/* donate ํšŒ์ˆ˜ */
void lock_release(struct lock* lock) {

    struct list_elem* curr_elem;
    struct thread* curr;

    struct list* waiters = &lock->semaphore->waiters;

    if(!list_empty(waiters)) {
        for(curr_elem = list_begin(waiters);
            curr_elem != list_end(waiters);
            curr_elem = list_next(curr_elem);) {

            curr = list_entry(curr_elem, struct thread, elem);
            lock->holder->donate_list[curr->priority]--;
        }
    }

    lock->holder = NULL;
    sema_up(&lock->semaphore);
}

nested donation์€ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ lock a์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ, lock a์˜ holder๊ฐ€ lock b๊ฐ€ ํ’€๋ฆฌ๊ธฐ๋ฅผ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ด๋‹ค. nested๊ฐ€ ์—ฐ์†์ ์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋ฉด chain์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (๊ผฌ๋ฆฌ๋ฌผ๊ธฐ..)

thread 0 = 3 priority
thread 1 = 6 priority
thread 2 = 9 priority // ํด์ˆ˜๋ก ๋†’์Œ

thread 0 ์ด lock a๋ฅผ ๊ฐ–๋Š”๋‹ค.
thread 1 ์ด ์ƒ์„ฑ๋˜์–ด lock b๋ฅผ ๊ฐ–๋Š”๋‹ค.
thread 1 ์ด lock a์— ์ ‘๊ทผํ•œ๋‹ค. waiters๋กœ ๋“ค์–ด๊ฐ€ ๋Œ€๊ธฐ.
thread 2 ๊ฐ€ ์ƒ์„ฑ๋˜์–ด lock b์— ์ ‘๊ทผํ•œ๋‹ค.

์ด ๊ฒฝ์šฐ thread 2๋Š” lock b์˜ holder์ธ thread 1์ด ๋นจ๋ฆฌ lock a๋ฅผ ํš๋“ํ•˜๊ณ , ์‹คํ–‰๋˜์–ด lock b๋ฅผ ํ’€์–ด์ค„ ์ˆ˜ ์žˆ๋„๋ก ์ž์‹ ์˜ ์šฐ์„ ์ˆœ์œ„์ธ 9๋ฅผ thread 1์—๊ฒŒ ๊ธฐ์ฆํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  thread 1์ด ์ ‘๊ทผํ•˜๊ณ ์ž ํ•˜๋Š” lock a์˜ holder์ธ thread 0์—๊ฒŒ๋„ 9๋ฅผ ๊ธฐ์ฆํ•œ๋‹ค. ๊ทธ๋ž˜์•ผ thread 0์ด lock a๋ฅผ ๋นจ๋ฆฌ releaseํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ˜„์žฌ ์ผ€์ด์Šค์—์„œ๋Š” thread 0๋งŒ ์žˆ๊ธฐ ๋–„๋ฌธ์— ์™œ ์šฐ์„ ์ˆœ์œ„ 9๊ฐ€ thread 0์—๊ฒŒ๊นŒ์ง€ ๊ธฐ์ฆ๋˜์–ด์•ผ ํ•˜๋Š”์ง€ ํ•„์š”์„ฑ์ด ๋Š๊ปด์ง€์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋งŒ์•ฝ thread 3์ด 8์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๊ณ  ๋Œ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž. thread 2๋Š” 8๋ณด๋‹ค ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , thread 0์ด lock a๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋จผ์ € ์‹คํ–‰๋˜์ง€ ๋ชปํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, thread 2๋Š” ์ž์‹ ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ nested lock์„ ์ตœ์ข…์ ์œผ๋กœ ๊ฐ–๊ณ  ์žˆ๋Š” thread 0์œผ๋กœ ๊ธฐ์ฆํ•˜์—ฌ ๋น ๋ฅด๊ฒŒ lock์„ ํ•ด์†Œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด thread ๊ตฌ์กฐ์ฒด ๋‚ด์˜ holder (์ด ์Šค๋ ˆ๋“œ๊ฐ€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ธฐ์ฆํ•œ ์Šค๋ ˆ๋“œ) ํ•„๋“œ๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค. ๊ธฐ์ฆ์„ while๋ฌธ์„ ๋Œ๋ฉด์„œ ํ•˜๊ณ , ๋ฐ˜ํ™˜ ์—ญ์‹œ ์ด์ค‘ for๋ฌธ์„ ๋Œ๋ฉด์„œ ํ•œ๋‹ค.

void lock_acquire(struct lock *lock) {

    /* nested priority donation */
    struct thread *holder = lock->holder;
    struct thread *curr = thread_current();

    while (holder) {
      if (thread_max_priority(curr) > thread_max_priority(holder)) {
        holder->donate_list[thread_max_priority(curr)]++;        
        holder = holder->holder;
      } else
        break;
    }

    /* lock holder๊ฐ€ ready list์— ์žˆ์—ˆ๋‹ค๋ฉด */
    if (lock->holder && lock->holder->status == THREAD_READY) {
        thread_reorder(lock->holder);
    }

    /* ๋‚˜์˜ ํ™€๋”๋ฅผ ํ˜„์žฌ lock->holder๋กœ ์„ค์ • */
    thread_current()->holder = lock->holder;

    sema_down(&lock->semaphore);
    lock->holder = thread_current();
}

void lock_release(struct lock *lock) {
  if (!list_empty(&lock->semaphore.waiters)) {
    struct list_elem *curr;
    struct thread *donator;

    /* ๋‹ค์Œ์œผ๋กœ holder๊ฐ€ ๋  ์Šค๋ ˆ๋“œ */
    struct list_elem *next_elem =
        list_min(&lock->semaphore.waiters, high_prio, NULL);
    struct thread *next = thread_entry(next_elem);

    for (curr = list_begin(&lock->semaphore.waiters);
         curr != list_end(&lock->semaphore.waiters); curr = list_next(curr)) {
      donator = thread_entry(curr);

      /* waiter๊ฐ€ ๊ธฐ์ฆ๋ฐ›์•˜๋˜ ์šฐ์„ ์ˆœ์œ„ ๋ฐ˜ํ™˜ for nested */
      for (int i = 0; i < 64; i++) {
        if (donator->donate_list[i] > 0) {
          thread_current()->donate_list[i]--;
        }
      }
      /* waiter์—๊ฒŒ์„œ ๊ธฐ์ฆ๋ฐ›์€ ์šฐ์„ ์ˆœ์œ„ ๋ฐ˜ํ™˜ */
      thread_current()->donate_list[donator->priority]--;
      donator->holder = next;
    }
    /* ๋‚˜์˜ holder๋Š” NULL */
    thread_current()->holder = NULL;
  }

  lock->holder = NULL;
  sema_up(&lock->semaphore);
  thread_yield(); /* ์œ„์—์„œ unblock๋œ ์• ๊ฐ€ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋” ๋†’์œผ๋ฉด ์Šค์ผ€์ค„ */
}

๊ธฐ์ฆ๊ณผ ๋ฐ˜ํ™˜์„ ์ž˜ ์ˆ˜ํ–‰ํ•˜๊ณ , ์›๋ž˜ ์žˆ๋˜ thread ์ •๋ณด ์™ธ์— ์ƒˆ๋กœ ์ƒ๊ธด donate_list, holder ์ •๋ณด๋ฅผ ์ž˜ ๊ด€๋ฆฌํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ์ด์™ธ์—๋„ semaphore, conditional variable์—์„œ๋„ ์šฐ์„ ์ˆœ์œ„๋Œ€๋กœ down, wake ํ•  ์ˆ˜ ์žˆ๋„๋ก thread_yield๋ฅผ ์ ์ ˆํžˆ ์‹คํ–‰ํ•ด์ค€๋‹ค.

๋™๊ธฐํ™”์— ๊ด€ํ•œ ๋ฌธ์ œ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์˜ ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ๋จธ๋ฆฟ์†์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๊ธฐ ํž˜๋“ค๋‹ค๋Š” ์ ์—์„œ ์–ด๋ ต๊ฒŒ ๋Š๊ปด์ง€๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๊ฐ ํ•จ์ˆ˜๋งˆ๋‹ค printf๋ฅผ ์‹ฌ์–ด ๋†“๊ณ  ์ „์ฒด ์ฝ”๋“œ ํ๋ฆ„์ด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€๋ฅผ ๋จผ์ € ์ดํ•ดํ•ด๋ณด๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค. ๋˜, donation๊ด€๋ จ ์ •๋ณด๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ• ์ง€ ๊ทธ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์งœ๋Š” ๊ฒƒ์ด ๊ต‰์žฅํžˆ ๋‹ค์–‘ํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ ๋‹ค. lock์„ releaseํ•  ๋•Œ ์ด์ค‘ for๋ฌธ์„ ๋Œ์ง€ ์•Š๊ธฐ ์œ„ํ•ด, ํ•˜๋‚˜์˜ lock์œผ๋กœ ์ธํ•ด ๊ธฐ์ฆ๋ฐ›์€ ์ตœ๋Œ€์˜ ์šฐ์„ ์ˆœ์œ„๋งŒ์„ ์ €์žฅํ•ด๋‘์–ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. donate๊ฐ€ ์ด๋ฃจ์–ด์งˆ๋•Œ๋งˆ๋‹ค ์ตœ๋Œ“๊ฐ’์„ ๊ฐฑ์‹ ํ•˜๋ฉด์„œ. ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Œ์„ ์•Œ๊ณ , ๊ฐ ๋ฐฉ๋ฒ•์˜ ๋‹จ์ ๊ณผ ์žฅ์ ์„ ์ˆ™๊ณ ํ•ด์„œ ๊ท ํ˜• ์žกํžŒ ๊ตฌํ˜„๋ฐฉ๋ฒ•์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ  ์‹ถ๋‹ค. ์ผ๋‹จ์€ ํ˜„์žฌ ์ฝ”๋“œ๊ฐ€ ์ •๋ง๋กœ (test case ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ) ๋ชจ๋“  donation ์ƒํ™ฉ์—์„œ ์˜๋„๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด ๋งž๋Š”์ง€ ๋ฐ˜๋ก€๋ฅผ ์กฐ๊ธˆ ๋” ์ƒ๊ฐํ•ด๋ด์•ผ๊ฒ ๋‹ค.

์ฝ”๋“œ๋Ÿ‰์€ ์ ์€๋ฐ ํ•œ ๋ผ์ธ ์น˜๋Š”๋ฐ ํ•œ์‹œ๊ฐ„์”ฉ ๊ฑธ๋ฆฐ๋“ฏ

2023.10.03 ์ˆ˜์ •: ํ˜„์žฌ ์ฝ”๋“œ์˜ ๋ฐ˜๋ก€๋ฅผ ๋ฐœ๊ฒฌ. test code์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ๋ฐ˜๋ก€๊ฐ€ ์žˆ์Œ.