https://casys-kaist.github.io/pintos-kaist/introduction
1. alarm clock 시도해보기
2. kernel thread 동작 이해하기
3. thread scheduling 이해하기
4. alarm clock 해결하기
5. context switch 이해하기
6. priority scheduling 해결하기
struct thread {
/* Owned by thread.c. */
tid_t tid; /* Thread identifier. */
enum thread_status status; /* Thread state. */
char name[16]; /* Name (for debugging purposes). */
int priority; /* Priority. */
/* Shared between thread.c and synch.c. */
struct list_elem elem;
/* List element.
-스레드를 이중연결 리스트에 넣기 위해서 쓰인다.
-이중연결리스트라 하면, ready_list (run을 위해 ready중인 스레드의 리스트),
sema_down()에서 세마포어에서 waiting중인 스레드 리스트를 말한다.
-이 두 경우에서 쓸 수 있는 이유는 세마포어에 있는 스레드는 ready상태가 될 수 없고,
반대로 ready인 스레드는 세마포어일 수가 없다.
그래서 이 두 리스트에 대해서 같은 list_elem을 사용할 수 있는 것이다.
*/
/* Owned by thread.c. */
struct intr_frame tf; /* Information for switching */
unsigned magic; /* Detects stack overflow. */
}
____________________________________________________________________________
enum thread_status {
**THREAD_RUNNING,**
/* Running thread.
오직 한개의 thread만 run하고 있다
thread_current( )하면 return 됨
*/
**THREAD_READY,**
/* Not running but ready to run.
스케줄러에 의해 run됨
ready thread는 ready_list라는 이중연결리스트 안에 보관
*/
**THREAD_BLOCKED,**
/* Waiting for an event to trigger.
대기 or 일시정지 ? 중인 상태
thread_unblock( )으로 thread_ready 가 됨
*/
**THREAD_DYING** /* About to be destroyed. */
} ;
하나의 kernel_thread는 하나의 function를 실행시키고 이후 종료되는 것이다. 즉, 한 개의 kernel_thread는 컴퓨터에서 수행하는 한 개의 task를 개념화한 것이다
/* Function used as the basis for a kernel thread. */
static void
kernel_thread (thread_func *function, void *aux) {
ASSERT (function != NULL);
/* intr_enable( ) : because the scheduler runs with interrupts off.
그래서 thread 실행 할 동안은 켜놓(enable)는거*/
intr_enable ();
function (aux); /* Execute the thread function. */
thread_exit (); /* If function() returns, kill the thread. */
}
void // PINTOS의 첫번째 thread를 만든다
thread_init (void) {
ASSERT (intr_get_level () == INTR_OFF);
/* Reload the temporal gdt for the kernel
* This gdt does not include the user context.
* The kernel will rebuild the gdt with user context, in gdt_init (). */
struct desc_ptr gdt_ds = {
.size = sizeof (gdt) - 1,
.address = (uint64_t) gdt
};
lgdt (&gdt_ds);
/* Init the global thread context */
lock_init (&tid_lock);
list_init (&ready_list);
list_init (&destruction_req);
/* Set up a thread structure for the running thread. */
initial_thread = running_thread ();
init_thread (initial_thread, "main", PRI_DEFAULT);
initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid ();
}
____________________________________________________________________________
/* Idle thread 만들고 interrupt 활성화
Starts preemptive thread scheduling by enabling interrupts.
Also creates the idle thread. */
void
thread_start (void) {
/* Create the idle thread. */
struct semaphore idle_started;
sema_init (&idle_started, 0);
thread_create ("idle", PRI_MIN, idle, &idle_started);
/* Start preemptive thread scheduling.
인터럽트 활성화*/
intr_enable ();
/* Wait for the idle thread to initialize idle_thread. */
sema_down (&idle_started);
}
____________________________________________________________________________
tid_t
thread_create (const char *name, int priority, thread_func *function, void *aux) {
struct thread *t;
tid_t tid;
ASSERT (function != NULL);
/* Allocate thread. */
t = palloc_get_page (PAL_ZERO);
if (t == NULL)
return TID_ERROR;
/* Initialize thread. */
init_thread (t, name, priority);
tid = t->tid = allocate_tid ();
/* Call the kernel_thread if it scheduled.
* Note) rdi is 1st argument, and rsi is 2nd argument. */
t->tf.rip = (uintptr_t) kernel_thread;
t->tf.R.rdi = (uint64_t) function;
t->tf.R.rsi = (uint64_t) aux;
t->tf.ds = SEL_KDSEG;
t->tf.es = SEL_KDSEG;
t->tf.ss = SEL_KDSEG;
t->tf.cs = SEL_KCSEG;
t->tf.eflags = FLAG_IF;
/* Add to run queue. */
thread_unblock (t);
return tid;
}
struct semaphore {
unsigned value; /* Current value. */
struct list waiters; /* List of waiting threads. */
};
____________________________________________________________________________
void sema_init (struct semaphore *sema, unsigned value) {
ASSERT (sema != NULL);
sema->value = value;
list_init (&sema->waiters);
}
____________________________________________________________________________
// sema_down(&sema)를 할 때, sema의 값이 0이라면 실행을 멈추고, sema가 1이 될 때까지 기다린다.
/*idle() 함수가 sema_up(&idle_started)를 실행하기 전까지 “main” thread는
sema_down(&idle_started)에 멈춰 있는다. idle() 함수가 sema_up(&idle_started)를 실행하면
(=모든 실행준비를 마치고 이제 다른 kernel thread를 생성할 준비가 되면)
다음으로 넘어가 run_actions()을 실행한다. */
void sema_down (struct semaphore *sema) {
enum intr_level old_level;
ASSERT (sema != NULL);
//Returns true during processing of an external interrupt and false at all other times.
ASSERT (!intr_context ());
old_level = intr_disable ();
while (sema->value == 0) {
list_push_back (&sema->waiters, &thread_current()->elem);
thread_block ();
}
//while 문 나왔다는건 semaphore에 있던 thread가 할거 다하고 나왔다는거임 그래서 +1
//이제 내가 value -1하고 들어감
sema->value--;
intr_set_level (old_level);
}
