본문 바로가기
pintos

[pintos] Project1:Threads - Alarm Clock

by 메릴린 2022. 12. 9.
728x90

학교에서 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()를 실행하지 않아도 된다.
728x90
반응형

댓글