
void timer_sleep (int64_t ticks)
{
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
while (timer_elapsed (start) < ticks)
thread_yield ();
}
ticks에 도달하지 않은 스레드를 담을 연결 리스트 sleep_list를 선언하고, thread_init에서 초기화.
/* thread.c */
static struct list sleep_list; // sleep_list 선언
...
void thread_init(void)
{
...
list_init(&sleep_list); // sleep_list 초기화
...
}
스레드 구조체에 일어날 시각인 ticks를 저장할 wakeup_ticks 필드를 추가.
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. */
/* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */
int64_t wakeup_tick; /* Wake up tick */
...
};
thread_sleep 함수를 호출하여 현재 스레드를 대기 상태로 전환. 대기 상태로 전환된 스레드는 ticks 시간이 경과한 후에 다시 실행됨. 이때, CPU를 해제하고 다른 스레드에게 실행 기회를 양보하여 CPU와 시스템 자원을 효율적으로 관리!
/* timer.c */
void timer_sleep(int64_t ticks) {
int64_t start = timer_ticks();
ASSERT(intr_get_level() == INTR_ON);
// while (timer_elapsed (start) < ticks)
// thread_yield ();
// sleep wake
thread_sleep(start + ticks);
}
이 함수는 스레드를 대기 상태로 전환하여 특정 시간(ticks)까지 실행을 중지시키는 역할을 함.
/* thread.c */
void thread_sleep(int64_t ticks) { // ticks 만큼 sleep
struct thread *t = thread_current(); // 현재 스레드
enum intr_level old_level; // 인터럽트 레벨
ASSERT(intr_get_level() == INTR_ON); // 인터럽트가 켜져있는지 확인
old_level = intr_disable(); // 인터럽트 끄기
t->status = THREAD_BLOCKED; // 스레드 상태를 BLOCKED로 변경
t->wakeup_tick = ticks; // 깨어날 tick 설정
list_push_back(&sleep_list, &t->elem); // sleep_list에 추가
schedule(); // 스케줄링
intr_set_level(old_level); // 인터럽트 레벨 복구
}
타이머 인터럽트가 발생할 때마다 현재 시간을 업데이트하고, 이에 따라 대기 중인 스레드를 깨우고 스레드 스케줄링을 수행.
/* timer.c */
static void
timer_interrupt(struct intr_frame *args UNUSED) {
ticks++;
thread_wakeup(ticks);
thread_tick();
}
특정 시간(ticks)에 도달한 스레드들을 대기 상태에서 깨우고 실행 가능한 상태로 변경.
void thread_wakeup(int64_t ticks) { // ticks가 되면 깨우기
struct list_elem *e; // 리스트 엘리먼트
struct thread *t; // 스레드
enum intr_level old_level; // 인터럽트 레벨
ASSERT(intr_get_level() == INTR_OFF); // 인터럽트가 꺼져있는지 확인
old_level = intr_disable(); // 인터럽트 끄기
for (e = list_begin(&sleep_list); e != list_end(&sleep_list);) { // sleep_list 순회
t = list_entry(e, struct thread, elem); // 스레드 가져오기
if (t->wakeup_tick <= ticks) { // 깨어날 시간이 되었으면
e = list_remove(e); // 리스트에서 제거
thread_unblock(t); // unblock
} else { // 깨어날 시간이 아직 안되었으면
e = list_next(e); // 다음 엘리먼트로
}
}
intr_set_level(old_level); // 인터럽트 레벨 복구
}
/* Test: /threads/build에서 입력 */
pintos -- -q run alarm-multiple

idle틱이 550으로 증가한 것을 확인할 수 있다! 🙊
"Idle 틱"은 시스템이 어떤 작업도 수행하지 않고 대기 상태인 시간을 나타냄.
대기 중인 스레드가 깨어나서 실행될 때, CPU가 대기 상태에서 벗어나고 스레드가 실행되면서 "Idle 틱"이 발생!!