struct thread {
// 동일 코드...
int64_t wakeup_tick; /* 깨워야 할 tick */
int base_priority; // 기존 우선순위
struct lock* waiting_lock; // 대기중인 lock
struct list_elem donation_elem; // 내가 다른 스레드의 donation_list에 들어갈 때 쓰이는 원소
struct list donation_list; // 나에게 donation해준 스레드들의 리스트
// 동일 코드...
};
구조체 필드가 저렇게 4개가 되어야하는 이유에 대한 그림 설명
구조체 필드가 저렇게 4개가 되어야하는 이유에 대한 그림 설명
static void
init_thread (struct thread *t, const char *name, int priority) {
// 동일 코드...
t->base_priority = priority;
t->waiting_lock = NULL;
// 동일 코드...
}
tid_t
thread_create (const char *name, int priority,
thread_func *function, void *aux) {
// 동일한 코드...
/* 새로 생성된 스레드가 현재 스레드보다 우선순위가 높으면 양보 */
if (t->priority > thread_current()->priority)
{
thread_yield();
}
// 동일한 코드...
}
int
thread_get_priority (void) {
// 인터럽트 끄기
enum intr_level old_level = intr_disable();
struct thread* current_thread = thread_current(); // 현재 스레드
// 인터럽트 다시 켜기
intr_set_level(old_level);
// 이미 계산된(기부 상황이면 기부까지 반영된) 우선순위 값 반환
return current_thread->priority;
}
인터럽트를 끄는 이유
해당 스레드의 우선순위를 읽는 과정 중에 스케줄링 등으로 우선순위 값이 변할 수 있기 때문. 인터럽트를 꺼서 atomic하게 스레드의 우선순위 값을 읽은 후에 다시 복원하는게 안전
// 우선순위 비교 함수(내림차순)
static bool priority_compare(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED)
{
struct thread *thread_a = list_entry(a, struct thread, elem);
struct thread *thread_b = list_entry(b, struct thread, elem);
return thread_a->priority > thread_b->priority;
}
void
thread_yield (void) {
// 동일 코드...
if (curr != idle_thread)
list_insert_ordered(&ready_list, &curr->elem, priority_compare, NULL);
// 동일 코드...
}
void
thread_set_priority (int new_priority) {
// 현재 스레드
struct thread* current_thread = thread_current();
current_thread->base_priority = new_priority;
// 인터럽트 끄기
enum intr_level old_level = intr_disable();
// donation이 적용된, 최종 우선순위 계산
// 나한테 기부한 스레드가 없다면, 기존 우선순위
if(list_empty(¤t_thread->donation_list))
{
current_thread->priority = new_priority;
}
// 나한테 기부한 스레드가 있다면, 기부받은 우선순위와 기존 우선순위 중 더 높은 값을 최종 우선순위 값으로 설정
else
{
// donation_list는 우선순위 순으로 정렬된 상태(내림차순)
struct thread* highest_donated_thread = list_entry(list_front(¤t_thread->donation_list), struct thread, donation_elem);
if(highest_donated_thread->priority > new_priority)
{
current_thread->priority = highest_donated_thread->priority;
}
else
{
current_thread->priority = new_priority;
}
}
// 현재 스레드의 우선순위가 최고가 아니라면, 즉시 CPU 양보
// ready_list는 우선순위 순으로 정렬된 상태(내림차순)
bool should_yield = false;
if(!list_empty(&ready_list))
{
struct thread *highest_priority_thread = list_entry(list_front(&ready_list), struct thread, elem);
if(current_thread->priority < highest_priority_thread->priority)
{
should_yield = true;
}
}
// 인터럽트 다시 켜기
intr_set_level(old_level);
// yield는 인터럽트 복원 후에 수행
if(should_yield)
{
thread_yield();
}
}