https://casys-kaist.github.io/pintos-kaist/introduction

프로세스 vs쓰레드

1. Thread | 2. Process | 3. Virtual memory | 4. file system

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;
}

Semaphore 관련 함수들

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);
}

Untitled