Project1: Alarm Clock
PintOS에서 thread와 process의 관계
실제 OS에서는 하나의 process 안에 여러 개의 thread가 존재할 수 있으며, 이 thread들은 같은 virtual address space를 공유한다.
PintOS에서는 구현을 단순화하기 위해서 하나의 process에 하나의 thread만 있도록 구성되어 있다.
PintOS에 한해서는 process = thread라고 생각해도 무방하다.
실제 코드에서 pml4(특정 process의 virtual address 정보를 담고 있는 테이블)등 process가 가지고 있어야 할 내용을 thread struct가 가지고 있다.
현재 PintOS의 Alarm Clock 방식, 문제점
Alarm Clock은 자고 있는 thread들을 깨워주는 PintOS의 기능이다.
어렵게 말하면, 호출한 프로세스를 정해진 시간 후에 다시 시작하는 커널 내부 함수이다.
기본적으로 PintOS에는 Round-Robin 방식이 사용되고 있다. 할당 시간이 지나면 프로세스는 선점(preempted)당하고 ready queue의 제일 뒤에 가서 다시 줄을 선다.
PintOS에서는 thread가 CPU를 사용할 시간(할당시간)은 4 tick(40ms)으로 한정되어 있다. 4 tick이 지나면 thread는 ready_list 맨 뒤에 추가된다.
이 방식의 문제점은 busy waiting 방식을 사용한다는 것인데, 자고 있는 thread들 중에 아직 일어날 시간이 아닌 thread들까지 Running 상태에 넣어서 CPU를 사용한다는 점이다!
busy waiting 상태
계속 CPU와 Memory를 쓰면서 대기하는 상태 → CPU 자원이 낭비되는 문제가 있다.
해결책
sleep-awake(Block & Wakeup) 방식을 사용한다.
즉, sleep_list를 하나 만들어서 Blocked된 상태(잠자는 상태)로 thread들을 대기시키다가 깰 시간이 된 thread들만 ready_list에 넣어준다!
이렇게 바꾸면 아직 깨어날 시간이 되지 않은 thread들은 CPU를 사용하지 않게 된다!
수정 및 추가한 코드
// thread.h
struct thread
{
// project1 : Alarm Clock
int64_t wakeup; // 자신이 일어나야할 시각 각인
}
// 함수의 원형 선언
void thread_sleep(int64_t ticks);
void thread_awake(int64_t ticks);
// thread.c
// project1 : Alarm Clock
static struct list sleep_list; // blocked state thread를 위한 별도의 list생성
// project1 : Alarm Clock
void thread.init(void)
{
list_init(&sleep_list); // init 시킬 때 sleep_list도 만들어줌
}
// project1 : Alarm Clock
// thread의 blocked state 만들어줌
void thread_sleep(int64_t ticks) // ticks는 일어날 시각을 말함
{
struct thread *cur;
enum intr_level old_level;
old_level = intr_disable(); // interrupt 끔
cur = thread_current();
ASSERT(cur != idle_thread);
cur->wakeup = ticks; // 언제 깰건지 저장
list_push_back(&sleep_list, &cur->elem); // cur.elem을 sleep_list의 끝에 넣음
thread_block(); // state를 block상태로 만들어주고, schedule돌림
intr_set_level(old_level); // interrupt 킴
}
// project1 : Alarm Clock
// sleep thread를 깨운다.
void thread_awake(int64_t ticks) // 이 ticks는 계속 증가하는 ticks에서 정확한 tick을 말함
{
struct list_elem *e = list_begin(&sleep_list);
while (e != list_end(&sleep_list))
{
struct thread *t = list_entry(e, struct thread, elem);
if (t->wakeup <= ticks) // 현재 시각이 일어날 시간을 지났으면 -> 일어나!!
{
e = list_remove(e);
thread_unblock(t);
}
else
{
e = list_next(e);
}
}
}
// timer.c
static void
timer_interrupt(struct intr_frame *args UNUSED)
{
ticks++;
thread_tick();
// project1 : Alarm Clock
thread_awake(ticks); // 깨울 tick이 되면 자는 thread를 깨움
}
// project 1 - Alarm Clock
void timer_sleep(int64_t ticks)
{ // ticks: 자고싶어하는 duration
int64_t start = timer_ticks(); // start에 계속 흘러가는 timer의 tick을 넣는다.
ASSERT(intr_get_level() == INTR_ON);
thread_sleep(start + ticks); // 깨울 시간이 기간이 아니라 시각이므로 (ticks로 하면 fail)
}
'sw사관학교정글 > PintOS(KAIST's CS330 class)' 카테고리의 다른 글
[week09] PintOS - Project 2(User Programs) : Argument Passing (2) | 2022.01.11 |
---|---|
[week09] PintOS - Project 2(User Programs) : Introduction (0) | 2022.01.11 |
[week08] PintOS - Project 1(thread) : Priority scheduling(3) donation (0) | 2021.12.31 |
[week08] PintOS - Project 1(thread) : Priority Scheduling(2) (0) | 2021.12.31 |
[week08] PintOS - Project 1(thread) : Priority Scheduling(1) (0) | 2021.12.31 |