-
Pintos Project #1 : Pintos 환경 구축 (1/3)Computer Science/OS 2020. 5. 29. 14:43728x90
1. 개요
- Pintos의 소스 코드 분석, 전체적인 구조 이해하는 것
2. 내용
- Pintos 운영체제가 부팅을 시작하여, alarm-multiple 테스트를 수행하기까지의 과정에 대해 다음을 수행한다.
- 함수 분석
- 자료구조 분석
- 프로그램 실행 경로 분석
- 배포한 가상 머신 상의 ~/pintos/src/threads 디렉토리 내의 소스 코드를 대상으로 분석한다.
- 대상 소스 코드 중 조건부 컴파일을 위한 매크로 USERPROG와 FILESYS 해당 부분은 분석 대상에서 제외한다.
- 프로그램 수행 경로를 따라 주요 함수를 분석하고, 관련 주요 자료구조에 대한 분석을 포함하여야 한다.
3. 순서
- 함수의 분석
- 자료구조의 분석
- 프로그램 실행 경로의 분석
3-1. 함수의 분석
1. thread_init()
1) thread_init() : thread의 초기화를 의미한다. 자세히 말하자면 kernel 자기 자신을 하나의 thread로 만드는 과정이다. 이를 kernel 본체 thread라고 하겠다.
2) ASSERT (intr _get_level () == INTR_OFF) : ASSERT()는 괄호안의 조건이 만족되어야만 한다는 뜻이다. 즉, 여기서는 interrupt가 off되어야만 진행한다는 의미이다. 외부interrupt의 off는 외부interrupt를 무시한다는 의미인데, 무시하지 않는다면 ready queue에서 다음 thread의 scheduling과정에서 interrupt가 발생되어 오류를 보일 수 있기 때문이다.
3) list_init(&ready_list), list_init(&all_list) : ready_list는 ready queue를 의미한다. Ready queue는 linked-list형태로 되어있다. Ready queue의 초기화를 의미한다. Ready queue이외에 job queue, device queue등이 있다. 이를 초기화한다.
4) Initial_thread=running_thread() : thread의 자료구조인 tcb의 시작주소를 thread의 시작주소로 하겠다는 의미이다.
5) Init_thread(initial_thread, “main”, PRI_DEFAULT) :thread의 본격적인 초기화이다. Thread의 초기화는 thread의 tcb의 초기화를 의미한다.
(1) Initial_thread : 초기화 대상
(2) “main” : 대상의 이름을 main으로 한다.
(3) PRI_DEFAULT : thread의 우선순위이다.
6) Initial_thread->status=THREAD_RUNNING : thread의 상태를 running으로 바꾼다.
7) Initial_thread->tid=allocate_tid() : thread의 고유 id인 tid를 할당한다. Allocate_tid()함수는 1씩 증가된 값을 return한다.
2. palloc_init()
1) palloc_init() : 동적 메모리 할당 영역의 초기화를 하는 함수이다. 이외에 malloc_init(), paginig_init()함수가 있다.
2) free_start=ptov(1024*1034) : pintos에서 사용할 메모리 영역의 시작 주소를 free_start에 저장한다.
3) Free_end=ptov(init_ram_pages*PGSIZE) : page의 갯수와 page의 크기(PGSIZE)를 곱하여 전체 영역을 구하고, 그 값을 free_end에 저장한다.
4) Free_pages=(free_end-free_start)/PGSIZE : 사용 가능한 전체 메모리 영역의 페이지 갯수를 구하여 free_pages에 저장한다.
5) User_pages=free_pages/2 : 전체 페이지의 절반을 user page로 한다.
6) If문을 보면, 만약 user pages가 user pages의 최대크기(limit)보다 크면, user pages를 최대 크기와 동일하게 설정한다.
7) Kernel_pages=free_pages-user_pages : user pages를 할당하고 남은 공간에 kernel pages를 할당한다.
8) 첫 번째 init_pool은 kernel_pool이라는 이름의 base address를 free_start로 하고, page갯수가 kernel pages와 같게 하여 memory pool을 생성한다.
9) 두 번째 user_pool은 init_pool은 kernel_pool이라는 이름의 base address를 (free_start+kernel pool의 크기)로 하고, page갯수가 user pages와 같게 하여 memory pool을 생성한다.
10) 이 함수가 실행된 직후의 memory pool의 구조는 다음과 같다.
(1) Kernel pool과 user pool에 tcb의 크기인 4KB 단위로 동적 메모리가 할당된다.
(2) .text : 기본 명령어들이 있다.
(3) .rodata : 값이 바뀌지 않는 전역변수가 있다.
(4) .data : 일반 전역변수가 있다.
(5) .bss : 초기값이 주어진 전역변수가 있다.
3. intr_init()
1) intr_init() : interrupt의 초기화를 의미한다. Interrupt의 초기화는 곧 idt의 초기화를 의미한다. Interrupt를 처리하기 위한 routine을 함수로 구현하고, 이 함수의 시작 주소를 IDT(Interrupt Descriptor Table)에 저장한다.
2) pic_init() : pic의 초기화이다. PIC(Programmable Interrupt Contoller)는 cpu의 Interrupt 담당 비서라고 생각하면 된다. 즉 모든 interrupt는 pic에 연결되고, cpu는 pic와 연결되는 구조이다. (8259)
3) 다음으로 나오는 for문은 idt의 초기화이다. 여기서 INTR_CNT는 256이다. Interrupt의 자료구조
4) Idtr_operand=make_idtr_operand(sizeof idt-1,idt) : Idt를 가리키는 포인터가 별도로 존재하는데 이것을 idtr이라고 한다. 여기서 idtr은 table의 시작주소를 가리키게 된다.
5) 다음으로 나오는 for문은 Interrupt의 이름을 unknown으로 한다.
6) 특정 interrupt만 이름을 지정한다.
4. IntrNN_stub:
1) Cpu가 interrupt를 받으면, 받음과 동시에 interrupt의 고유번호를 알게 된다. 또한 context를 총 3차례의 push를 하므로써 저장하는데 interrupt받자마자 context의 1/3을 stack에 저장(push)한다.
2) 고유번호를 통해 idt에서 intrNN_stub로 jump한다.
3) intrNN_stub에서 context의 1/3을 stack에 저장한다. (총 2/3 저장 완료)
4) Jmp Intr_entry로 인해 intr_entry로 jump한다.
5. Intr_entry:
1) Intr_entry에서 context의 1/3을 저장한다. 이로써 모든 context가 stack에 저장되고 이를 intr_frame이라고 한다.
2) Kernel의 환경을 설정한다.
3) Call intr_handler를 통해 본격적으로 interrupt를 처리하는 함수로 진입한다.
6. Intr_exit:
1) 3번의 push로 context를 저장하였지만, 마무리단계에서는 1번의 pop으로 context를 복원한다.
2) Addl $12, $esp : intr_frame을 해산시킨다.
3) Iret : interrupt return을 의미한다.
7. Intr_handler()
1) Intr_handler() : 모든 interrupt, fault, exception을 다루는 함수이다.
2) Intr_frame *frame : intr_frame을 가리키는 포인터를 설정한다.
3) External=frame->vec_no>=0x20&&frame->vec_no<0x30 : vec_no는 Interrupt의 고유번호이다. 고유번호가 이 범위 내에 있다면, 그 interrupt는 외부 interrupt이고 이를 external로 한다.
4) External을 다룰때는 다른 interrupt를 off한다.
5) In_external_intr=true : 외부 interrupt가 실행중인지 여부를 true로 한다.
6) Yield_on_return=false : run인 thread로부터 time slice expired로 인해 cpu를 빼앗아도 되는지 여부를 false로 한다.
7) Handler=intr_handlers[frame->vec_no] : table에서 해당 interrupt처리 함수를 찾아서 실행한다.
8) In_external_intr=false : 외부 interrupt가 실행중인지 여부를 false로 한다.
9) Pic_end_of_interrupt(frame->vec_no) : pic가 cpu에게 interrupt가 정상적으로 종료되었다는 ack(신호)을 보낸다.
10) If문을 보면, 만약 interrupt 처리 도중, time slice expired가 되어 yield_on_return이 true가 될 수 있다. 이 경우 thread_yield()함수를 실행시켜 run인 thread의 cpu를 빼앗는다.
8. thread_start()
1) thread_start() : idle thread를 만들고, thread들이 multiprogramming을 하도록 interrupt를 enable한다.
2) Thread_create(“idle”,PRI_MIN,ide,&idle_started) : idle thread를 만드는 함수이다.
(1) “idle” : 새로 만들 thread의 이름
(2) PRI_MIN : thread의 우선순위, min이므로 제일 낮은 우선순위를 가진다.
(3) Idle : idle thread에서 실행할 idle code(함수)
(4) &idle_started : idle함수의 변수
3) Intr_enable() : interrupt의 enable(허용)을 나타낸다. Interrupt의 enable은 곧 multiprogramming을 하겠다라고 해석된다.
9. Thread_create()
1) Thread_create() : thread를 생성하는 함수이다.
2) T=palloc_Get_page(PAL_ZERO) : 새 thread의 4KB의 tcb를 생성한다.
3) Init_thread(t,name,priority) : tid가 t이고 우선순위가 priority인 thread를 초기화한다.
4) /*stack frame for kernel_thread()*/ ~ thread_unblock(t) : 일반적으로 context switch가 발생하면, 이전 context를 현재로 복원한다. 하지만 특별한 경우로 sheduling의 대상이 새로만든 thread라면, 이전 context가 의미없는 값일 수 있다. 따라서 처음 thread_create()로 인해 thread가 생성될 때, fake stack frames을 만든 후 해당 thread를 ready상태로 바꾸어 ready queue에 넣는다.
5) Thread는 새로 만들어지면 바로 run하지 않고 ready상태로 대기하였다가 차례가 되면 run한다.
10. Idle()
1) idle() : idle()함수로 만들어진 idle thread는 시스템이 할 일이 없을 때 실행되는 thread이다.
2) For ( ; ; ) : 무한루프를 도는 for문을 통해 idle thread는 의미없는 실행을 계속한다.
11. Thread_tick()
1) Thread_tick() : run하는 thread에게 cpu의 할당 시간을 부여하는 함수이다.
2) 첫 번째 if-else문을 보면, 현재 thread t가 idle thread인지, user thread인지, kernel thread인지 구별한다. 새 thread가 생성되면 thread_tick은 0으로 초기화 된다.
3) 두 번째 if문을 보면, TIME_SLICE는 일반적으로 4를 의미한다. 즉 TIME_SLICE보다 현재 thread의 cpu 소유시간이 크다면, cpu를 빼앗아야 한다. (time slice expired)
4) Intr_yield_on_return() :yield_on_return을 true(1)로 한다는 뜻이다. True가 되면 cpu를 빼앗는다.
728x90'Computer Science > OS' 카테고리의 다른 글
CS : OS : Process (0) 2021.03.25 Pintos Project #3 : Thread scheduling (2) 2020.05.29 Pintos Project #2 : Alarm Clock의 개선 (0) 2020.05.29 Pintos Project #1 : Pintos 환경 구축 (3/3) (0) 2020.05.29 Pintos Project #1 : Pintos 환경 구축 (2/3) (0) 2020.05.29