오늘 목표다
계속해서 자원 먹는 busy waiting을 한결 더 좋은 방식으로 바꿀거다
timer_sleep(ticks)
로 지정 틱까지 블록시키기…
슬립 리스트를 만들어 꺠어나는 시간 기준으로 정렬에 넣은 뒤
타이머 인터럽트로 하여금 매 틱마다 깰 시간 된 스레드만 깨우게 하는 거다
일단, 리스트 부터 만들어야 한다
전역 자료구조로 말이다
슬립 리스트 ㅇㅇ
그리고 이렇게 만든 리스트는 커널 스레드, 인터럽트 핸들러 모두
접근 가능하기에 스레드 쪽에서 수정할때에는 인터럽트 비활성화 해줘야한다
연결리스트로 구현하려 했는데
Pintos 자체적으로 리스트 자료구조 지원한다
구조체에 struct list_elem elem;
이런식으로 하나 추가하면 끝이다
그럼 이제 사용 ㄱㄴ
기존 스레드 구조체가 존재하니 거기다가 추가해주었다
이후 timer.c에 static struct list sleep_list;
로 전역 변수 리스트 선언
기존 코드 뜯어 고쳤다
인상 깊었덤 함수는 list_insert_orderd
인데 쓰기 상당히 곤란했다
리스트, 리스트 노드, 조건, aux? 이런거 넣어야 해서 말이다
aux는 걍 NULL
넣으면 되긴 하다
무슨 보조 데이터 포인터라는 비교함수 사용할 때 쓸 추가 인자 그런 거라는데 지금 필요없으니 안다루겠다
게다가 조건 만드는데에 list_entry
쓰는데 이것도 쉽지 않았다
근데 이렇게 정리해보니 그리 어렵지 않은 것 같기도 하고…
static bool wakeup_less(const struct list_elem *a, const struct list_elem *b, void *aux) {
const struct thread *ta = list_entry(a, struct thread, elem);
const struct thread *tb = list_entry(b, struct thread, elem);
return ta->wakeup_tick < tb->wakeup_tick; // 기상 시각 오름차순
}
void
timer_sleep (int64_t ticks) {
if (ticks <= 0) return; // 틱 0이면 안받음
enum intr_level old = intr_disable(); // 인터럽트 끄고 인터럽트 상태 old에 저장
int64_t wakeup = timer_ticks() + ticks; // 일어날 시간 (절대 틱)
struct thread *cur = thread_current(); // 현재 실행 중 스레드
cur->wakeup_tick = wakeup; // 현재 스레드 기상 시간
list_insert_ordered(&sleep_list, &cur->elem, wakeup_less, NULL);
// 리스트에 정렬해 저장
thread_block(); // 스레드 상태 변환
intr_set_level(old); // 인터럽트 다시 키고 복구
}
이렇게 만들었다
그냥 딱 전형적으로 만든 터라 뭐 크게 설명할 것도 없다
인터럽트 비활성화하고 슬립 리스트에 넣고 재운 뒤 인터럽트 활성화
그 다음은 리스트를 관리해줘야 한다
걍 읽고 맨앞 노드의 기상 시간이 현재 시간보다 같거나 이미 지났으면 깨우면된다
static void
timer_interrupt (struct intr_frame *args UNUSED) {
ticks++; // 현재 시각(틱) 1 증가
thread_tick(); // 타임슬라이스 소진 검사
while (!list_empty(&sleep_list)) {
struct list_elem *e = list_front(&sleep_list); // 가장 앞 노드
struct thread *t = list_entry(e, struct thread, elem); // list_elem → thread
if (t->wakeup_tick <= ticks) { // 깨어날 시간이 됨
list_pop_front(&sleep_list); // 슬립 큐에서 제거
thread_unblock(t); // READY 큐로 이동
} else break;
}
}
이거 넣고 타이머 초기화 함수에도 시간 초기화 넣어주면 완성이다
이제 정글 선배가 제작한 툴을 이용해 테스트를 돌려보면…
=== Test Summary ===
Passed: 5
- alarm-single
- alarm-multiple
- alarm-simultaneous
- alarm-zero
- alarm-negative
Failed: 1
- alarm-priority
하나 실패한다…
그치만 하나 빼고 다 통과니까 좋았어~