스케줄링이란 대기 중인 스레드 중에 실행할 스레드를 정하는 과정입니다. 현재 PintOS는 Round Robin 방식으로 스케줄링이 구현되어 있습니다.
스레드마다 중요성이 다르기 때문에 스레드의 우선순위에 따라 실행순서를 결정하는 priority scheduling을 구현할 것입니다.
/* thread/thread.c */
void
thread_unblock (struct thread *t)
{
enum intr_level old_level;
ASSERT (is_thread (t));
old_level = intr_disable ();
ASSERT (t->status == THREAD_BLOCKED);
list_push_back (&ready_list, &t->elem);
t->status = THREAD_READY;
intr_set_level (old_level);
}
void
thread_yield (void)
{
struct thread *cur = thread_current ();
enum intr_level old_level;
ASSERT (!intr_context ());
old_level = intr_disable ();
if (cur != idle_thread)
list_push_back (&ready_list, &cur->elem);
cur->status = THREAD_READY;
schedule ();
intr_set_level (old_level);
}
/* thread/thread.c */
static void
schedule (void)
{
struct thread *cur = running_thread ();
struct thread *next = next_thread_to_run ();
struct thread *prev = NULL;
ASSERT (intr_get_level () == INTR_OFF);
ASSERT (cur->status != THREAD_RUNNING);
ASSERT (is_thread (next));
if (cur != next)
prev = switch_threads (cur, next);
thread_schedule_tail (prev);
}
static struct thread *
next_thread_to_run (void)
{
if (list_empty (&ready_list))
return idle_thread;
else
return list_entry (list_pop_front (&ready_list), struct thread, elem);
}
ready_list에 priority 순서에 맞춰서 push 하는 방법과 정렬되지 않은 리스트에서 priority 가 가장 높은 스레드를 찾아 pop을 하는 방법이 있습니다. 전자의 방법대로 구현하고자 했습니다.
list_insert_ordered()
/* lib/kernel/list.c */
void
list_insert_ordered (struct list *list, struct list_elem *elem,
list_less_func *less, void *aux)
{
struct list_elem *e;
ASSERT (list != NULL);
ASSERT (elem != NULL);
ASSERT (less != NULL);
for (e = list_begin (list); e != list_end (list); e = list_next (e))
if (less (elem, e, aux))
break;
return list_insert (e, elem);
}
리스트를 순회하면서 요소를 넣을 위치를 찾습니다.
list_insert()
/* lib/kernel/list.c */
void
list_insert (struct list_elem *before, struct list_elem *elem)
{
ASSERT (is_interior (before) || is_tail (before));
ASSERT (elem != NULL);
elem->prev = before->prev;
elem->next = before;
before->prev->next = elem;
before->prev = elem;
}
요소를 리스트에 넣습니다.
thread_compare_priority() 구현/* thread/thread.c */
bool
thread_compare_priority (struct list_elem *l, struct list_elem *s, void *aux UNUSED)
{
return list_entry (l, struct thread, elem)->priority
> list_entry (s, struct thread, elem)->priority;
}
priority를 비교하는 함수입니다.
/* thread/thread.c */
void
thread_unblock (struct thread *t)
{
enum intr_level old_level;
ASSERT (is_thread (t));
old_level = intr_disable ();
ASSERT (t->status == THREAD_BLOCKED);
//list_push_back (&ready_list, &t->elem);
list_insert_ordered (&ready_list, &t->elem, thread_compare_priority, 0);
t->status = THREAD_READY;
intr_set_level (old_level);
}
list_push_back() 함수를 주석처리하고 list_insert_ordered()함수를 사용합니다.
void
thread_yield (void)
{
struct thread *cur = thread_current ();
enum intr_level old_level;
ASSERT (!intr_context ());
old_level = intr_disable ();
if (cur != idle_thread)
//list_push_back (&ready_list, &cur->elem);
list_insert_ordered (&ready_list, &cur->elem, thread_compare_priority, 0);
cur->status = THREAD_READY;
schedule ();
intr_set_level (old_level);
}
void
thread_test_preemption (void)
{
if (!list_empty (&ready_list) &&
thread_current ()->priority <
list_entry (list_front (&ready_list), struct thread, elem)->priority)
thread_yield ();
}
/* thread/thread.c */
tid_t
thread_create (const char *name, int priority,
thread_func *function, void *aux)
{
...
thread_unblock (t);
thread_test_preemption ();
return tid;
}
void
thread_set_priority (int new_priority)
{
thread_current ()->priority = new_priority;
thread_test_preemption ();
}

우선순위 스케줄링과 관련하여 다른 테스트들도 성공하려면 sempahhore, condition variable, donation에 대한 부분도 구현해야합니다.