/////
Search

Alarm Clock

기본 개념

Alarm Clock : 스레드가 특정 시간 동안 잠들어 있다가 정해진 시간이 되면 자동으로 깨어나는 기능

thread.h

wakeup_tick

해당 스레드가 깨워져야하는 시점을 나타내는 값(= 스레드가 sleep 상태로 들어갈 때, 몇 번째 tick(인터럽트 타이머 기준)이 되었을 때 깨워야 하는 지를 저장)
struct thread { // 이미 존재하는 코드... int64_t wakeup_tick; /* 스레드를 깨우기 위한 틱 수 */ // 이미 존재하는 코드... };
C
복사
시스템의 tick 카운터와 비교하여 지정된 tick이 되면 sleep_list에서 해당 스레드를 깨워 ready 상태로 전환하는 데 사용

sleep_list

현재 sleep(대기) 상태에 있는 스레드들을 담는 리스트
extern struct list sleep_list; // sleep 상태인 스레드들을 담는 리스트
C
복사
extern 키워드를 사용해 해당 변수가 다른 파일에서 정의되어 있음을 표현 → thread.c 파일에서는 선언만 하고, 실제 메모리 할당 및 초기화는 다른 소스 파일에서 진행(여러 파일에서 sleep_list를 사용 가능하도록)
각 스레드는 자신의 wakeup_tick 값에 따라 sleep_list 에 저장됨. 스레드가 특정 시간(tick)까지 잠들어 있어야할 때 해당 스레드를 이 리스트에 삽입. 타이머 인터럽트가 발생할 때마다 sleep_list 를 확인하여 깨워야할 tick이 된 스레드를 깨워 ready 상태로 전환시킴

thread.c

전역 변수(sleep_list)

struct list sleep_list; // timer.c 파일에서 사용 : sleep 상태인 스레드들을 담는 리스트
C
복사

thread_init()

void thread_init (void) { // 동일한 코드... list_init (&sleep_list); // 동일한 코드... }
C
복사

timer.c

timer_sleep()

void timer_sleep (int64_t ticks) { struct thread* current_thread; enum intr_level old_level; ASSERT(intr_get_level() == INTR_ON); // negative, zero 테스트에 대한 처리(예외 처리) if(ticks <= 0) { return; } // 먼저 인터럽트 끄기(핸들러와의 레이스 컨디션 방지) old_level = intr_disable(); current_thread = thread_current(); current_thread->wakeup_tick = (timer_ticks()) + ticks; // ticks만큼 후에 깨우기 list_insert_ordered(&sleep_list, &current_thread->elem, wakeup_tick_compare, NULL); // sleep_list에 현재 스레드 추가(오름차순 정렬) thread_block(); // 현재 스레드를 block 상태로 바꾸기 intr_set_level(old_level); // 인터럽트 다시 켜주기 }
C
복사

wakeup_tick_compare()

/* insert_ordered 함수에 사용할 비교 함수 */ static bool wakeup_tick_compare(const struct list_elem* a, const struct list_elem* b) { // 두 스레드의 wakeup_tick 값을 비교해 더 작은 값을 가진 스레드를 앞에 오도록 하기 struct thread* thread_a = list_entry(a, struct thread, elem); struct thread* thread_b = list_entry(b, struct thread, elem); return thread_a->wakeup_tick < thread_b->wakeup_tick; }
C
복사

timer_interrupt()

static void timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); /* * sleep_list에 있는 스레드들 중에서 깨워야 할 스레드가 있는지 확인 * 타이머 인터럽트 : 1초에 100번 발생 -> 매 인터럽트마다 sleep_list에서 깨울 스레드가 있는지 확인 */ struct list_elem* elem = list_begin(&sleep_list); while(elem != list_end(&sleep_list)) { struct thread* td = list_entry(elem, struct thread, elem); if(td->wakeup_tick <= ticks) { elem = list_remove(elem); // 깨울 스레드는 리스트에서 제거하고 다음 엘리먼트로 이동 thread_unblock(td); // 스레드 깨우기 } // 오름차순 정렬 상태에서 ticks보다 큰 wakeup_tick을 가진 스레드부터는 볼 이유 없음 else { break; } } }
C
복사