학교에서 pintos 프로젝트를 운영체제 시간에 프로젝트 과제로 한 학기동안 진행했는데 마감과 기타 다른 과목에 쫓겨 제대로 못한 거 같아 다시 해보려고 한다.. 학교에서는 project3에 이 부분을 다루지만 pintos manual에서는 project1에 해당하니 pintos manual 순서대로 복습 및 추가 공부를 진행해보려한다..
모든 핀토스 프로젝트는 서강대학교에서 제공한 자료를 기반으로 진행했습니다
Alarm Clock
Alarm Clock 파트에서 우리에게 요구하는 것은 busy waiting을 없애는 것이다.
devices/timer.c의 timer_sleep()의 busy waiting 없애기
void
timer_sleep (int64_t ticks)
{
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
while (timer_elapsed (start) < ticks)
thread_yield ();
}
기존의 timer_sleep()
함수를 보면 while문을 이용해 sleep 상태에 들어간 thread들을 wake up time이 될 때까지 계속 thread_yield()
함수를 호출해 busy waiting을 하고 있다.
이 비효율성을 해결하기 위해 queue를 따로 만들어 sleep 상태에 들어가는 thread들을 blocked 상태로 만들어 해당 queue에 넣고 wake up time이 될 때 다시 ready queue에 넣는 방식으로 바꾸려 한다.
위의 방식을 구현하기 위해서는 thread에 wake up time이 저장되어 있어야 하고 pintos의 ready queue처럼 blocked thread를 저장할 queue를 선언해주어야 한다.
struct thread
src/threads/thread.h의 struct thread에 아래와 같이 wake up time 값을 저장할 변수를 추가해준다.
struct thread
{
//...
/* Project1 */
int64_t wakeup; /* wake up time when thread go to sleep */
//...
};
blocked thread 저장할 queue 선언
timer_sleep()
함수에서 thread를 blocked로 만들고 해당 thread를 queue에 넣어주어야 하기 때문에 device/timer.c에 blocked thread를 관리할 변수 blocked_list
를 선언하고 timer_init()
함수에서 해당 list를 초기화 해준다.
/* Project1 */
static struct list blocked_list;
/* Sets up the timer to interrupt TIMER_FREQ times per second,
and registers the corresponding interrupt. */
void
timer_init (void)
{
pit_configure_channel (0, 2, TIMER_FREQ);
intr_register_ext (0x20, timer_interrupt, "8254 Timer");
// prj1
list_init(&blocked_list);
}
timer_sleep() 수정
void
timer_sleep (int64_t ticks)
{
int64_t start = timer_ticks ();
ASSERT (intr_get_level () == INTR_ON);
struct thread *cur = thread_current();
enum intr_level old_level;
old_level = intr_disable();
cur->wakeup = start+ticks;
list_push_back(&blocked_list, &cur->elem);
thread_block();
intr_set_level(old_level);
}
kernel threads(cur->wakeup
)와 interrupt handler(start+ticks
) 사이의 data sharing이 일어나고 있기 때문에 intr_disable()
함수를 통해 interrupt를 turn off 해주고 thread의 wakeup 변수에 start+ticks를 저장해준다.
timer_interrupt() 수정
핀토스 메뉴얼에서 alarm clock에서 sleeping thread를 깨우기 위해서는 timer interrupt를 써야 한다고 명시되어 있다.
timer interrupt가 발생해 timer_interrupt()
함수가 실행될 때마다 함수는 blocked_list
의 thread를 돌며 현재 ticks보다 wakeup이 작은 thread를 unblock 상태로 만들어 read_list
에 push해준다.
/* Timer interrupt handler. */
static void
timer_interrupt (struct intr_frame *args UNUSED)
{
ticks++;
thread_tick ();
// Prj1
struct thread *t;
struct list_elem *t_elem = list_begin(&blocked_list);
while(t_elem != list_end(&blocked_list)){
struct thread *t = list_entry(t_elem, struct thread, elem);
int64_t wakeup = t->wakeup;
if(wakeup <= ticks){
t_elem = list_remove(t_elem);
thread_unblock(t); // push t into ready_list
}
else{
t_elem = list_next(t_elem);
}
}
}
list_remove()
함수에서 인자로 넘어온 element를 제거하면 해당 인자의 다음 elem을 반환하기 때문에 따로list_next()
를 실행하지 않아도 된다.
'pintos' 카테고리의 다른 글
[pintos] Project1:Threads - Priority Scheduling (2) (0) | 2022.12.09 |
---|---|
[pintos] Project1:Threads - Priority Scheduling (1) (0) | 2022.12.09 |
Appendix A.1 Loading 정리 (0) | 2022.12.09 |
댓글