일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 동적 프로그래밍(Dynamic Programming)
- 백준 2504번
- 위상 정렬(Topology Sort)
- 스택(Stack)
- BFS
- DFS(Depth First Search)
- 백준 9012번
- BFS(Breadth First Search)
- 백준 17608번
- 백준 1707번
- 백준 21606번
- 백준 2261번
- 분할 정복(Divide and Conquer)
- 백준 1948번
- DFS
- 이분 그래프(Bipartite Graph)
- 이분 탐색(Binary Search)
- 플로이드 워셜 알고리즘(Floyd-Warshall Algorithm)
- DFS & BFS
- 백준 2493번
- 다익스트라 알고리즘(Dijkstra Algorithm)
- 트리(Tree)
- 백준 2812번
- 알고리즘 개념
- 그래프(Graph)
- 위상 정렬(Topological Sort)
- 백준 10000번
- 백준 18352번
- 그리디 알고리즘(Greedy Algorithm)
- 큐(Queue)
- Today
- Total
Always Be Wise
Project_3 : Virtual Memory - Anonymous Page(1) 본문
이제부터는 anonymous page라고 하는 non-disk based image를 구현할 것이다.
file-backed pages와 달리 anonymouse mapping은 명명된 파일 소스, 백업 파일이나 디바이스가 없기 때문에 익명이다.
anonymous page는 스택과 힙과 같은 실행 파일에서 사용된다.
include/vm/anon.h에 anonymous page를 설명하는 anon_page 구조체가 있다.
anonymouse page 관련하여 필요한 정보나 상태를 저장하기 위해 멤버를 추가할 수 있다.
include/vm/page.h에서 페이지의 일반 정보를 포함하고 있는 page 구조체도 참고해야 한다.
구조체 anon_page anon이 해당 page 구조체에 포함되어 있다.
Page Initialization with Lazy Loading
Lazy Loading은 메모리 로드가 필요한 시점까지 지연되는 설계를 의미한다.
즉, 페이지가 할당되어 그것에 해당하는 페이지 구조체가 있지만,
아직 전용 물리 프레임이 없어 페이지의 실제 내용이 로드되지 않은 상태를 의미한다.
이는 페이지 폴트에 의해서 필요하다고 신호를 받을 때 로드된다.
Pintos에서 페이지는 총 세 가지의 유형으로 구분되며, 각 페이지마다 초기화 루틴이 다르다.
먼저, 커널이 새로운 페이지 요청을 수신하면 vm_alloc_page_with_initializer( ) 함수가 호출된다.
vm_alloc_page_with_initializer( ) 함수는 페이지 구조체를 할당함으로써 새로운 페이지를 초기화하고,
페이지 유형에 따라 적절한 이니셜라이저를 설정, 사용자 프로그램에 컨트롤을 반환한다.
실행 중인 사용자 프로그램이 소유한 것으로 생각되지만 아직 내용이 없는 페이지에 접근하려고 할 때, 페이지 폴트가 발생한다.
페이지 폴트 처리 중에, uninit_initialize가 실행되어 이전에 설정한 이니셜라이저를 호출한다.
이니셜라이저는 anonymous page의 경우 anon_initializer가 되고, file-backed page의 경우 file_backed_initializer가 된다.
페이지는 initialize -> (page_fault -> lazy-load -> swap-in -> swap-out -> ... ) -> destroy의 라이프 사이클을 가질 수 있다.
각각의 라이프 사이클 전환 때마다 페이지 유형(또는 VM_TYPE)에 따라 필요한 절차가 달라진다.
각 페이지 유형에 대해 이러한 전환 프로세스를 구현해야 한다.
Lazy Loading for Executable
Lazy Loading의 경우, 프로세스 실행 시 즉시 필요로 되는 메모리 영역만 메인 메모리에 로드된다.
이것은 모든 binary image를 한 번에 메모리에 로드하는 Eager Loading에 비해 오버헤드를 줄일 수 있다.
Pintos에서는 Lazy Loading을 지원하기 위해, include/vm/vm.h에 VM_UNINIT이라는 페이지 유형을 도입하였고,
모든 페이지들은 초기에 VM_INIT 페이지로 만들어진다. 또한, include/vm/uninit.h에 초기화 되지 않은 페이지를 위한
uninit_page 구조체를 제공한다. 초기화되지 않은 페이지를 생성, 초기화, 파괴하는 함수는 include/vm/uninit.c에서 확인할 수 있고,
이러한 함수들을 구현해야 한다. 페이지 폴트 시, 페이지 폴트 핸들러는 제어권을 vm/vm.c에 있는 vm_try_handle_fault로 전송한다.
이 경우, 페이지 폴트가 유효한 페이지 폴트인지 확인한다. 유효한 페이지 폴트라는 것은 해당 접근이 유효하지 않다는 것을 의미한다.
유효하지 않은 페이지 폴트일 경우, 일부 콘텐츠를 페이지에 로드하고 제어권을 사용자 프로그램으로 반환한다.
유효하지 않은 페이지 폴트에는 Lazy_Loaded Page, Swaped-Out Page, Write-Protected Page 등 세 가지 경우가 있다.
만약 Lazy Loading에 의한 페이지 폴트라면, 커널은 vm_alloc_page_with_initializer에서 설정한 이니셜라이저 중 하나를 호출하여
세그먼트를 지연 로드한다. 이를 위해 userprog/process.c에서 lazy_load_segment( )를 구현해야 한다.
Implement vm_alloc_page_with_initializer( ).
bool vm_alloc_page_with_initializer (enum vm_type type, void *va, bool writable, vm_initializer *init, void *aux);
전달된 vm_type에 따라 적절한 이니셜라이저를 가져와 uninit_new를 호출해야 한다.
주어진 유형을 사용하여 초기화되지 않은 페이지를 만든다.
uninit page의 swap_in 핸들러는 유형에 따라 자동적으로 페이지를 초기화하고 지정된 AUX로 INIT을 호출한다.
페이지 구조체가 정해지면, 프로세스의 spt에 페이지를 삽입한다. vm.h에 정의된 VM_TYPE 매크로를 사용하면 편리하다.
static bool uninit_initialize (struct page *page, void *kva);
페이지 폴트 핸들러는 호출 체인을 따르며, swap_in을 호출할 때 최종적으로 uninit_initialize에 도달한다.
첫 번째 폴트에서 페이지를 초기화한다. 템플릿 코드는 먼저 vm_initializer와 aux를 가져오고 함수 포인터를 통해 해당하는
page_initializer를 호출한다. 설계에 따라 uninit_initialize를 수정해야 할 수도 있다.
필요에 따라 vm/anon.c에서 vm_anon_init 및 anon_initializer를 수정할 수 있습니다.
void vm_anon_init (void);
vm_anon_init은 anonymouse page 하위 시스템에 대해 초기화 한다. 이 함수는 anonymouse page와 관련된 모든 것을 설정할 수 있다.
bool anon_initializer (struct page *page,enum vm_type type, void *kva);
anon_initializer는 page -> operations에서 anonymouse page 핸들러를 설정한다.
현재는 비어있는 구조체인 anon_page의 몇몇 정보들을 업데이트할 필요가 있다.
이 함수는 anonymouse page(VM_ANON)의 이니셜라이저로 사용된다.
Implement load_segment and lazy_load_segment in userprog/process.c.
userprog/process.c의 load_segment에서 프로그램 로더의 코어를 수정할 필요가 있다.
로프를 돌 때마다 vm_alloc_page_with_initializer를 호출하여 보류 중인 페이지 개체를 생성한다.
페이지 폴트가 발생하면 세그먼트가 파일에서 실제로 로드된다.
static bool load_segment (struct file *file, off_t ofs, uint8_t *upage, uint32_t read_bytes, uint32_t zero_bytes, bool writable);
현재 코드는 파일에서 읽을 바이트 수와 메인 루프 내에서 0으로 채울 바이트 수를 계산한다.
vm_alloc_page_with_initializer를 호출하여 보류 중인 개체를 생성한다. 보조 값은 aux 인자로 설정해야 한다.
이진 적재를 위해 필요한 정보를 포함한 구조를 작성할 수 있다.
static bool lazy_load_segment (struct page *page, void *aux);
load_segment에서 lazy_load_segment가 vm_alloc_page_with_initializer의 네 번째 인수로 제공된다.
lazy_load_segment 함수는 실행 파일 페이지의 이니셜라이저이며 페이지 폴트 시 실행된다. 인자로 page와 aux를 받는다.
aux는 load_segment에서 설정하는 정보입니다. 이 정보를 사용하여 세그먼트를 읽을 파일을 찾아 세그먼트를 메모리로 읽어야 한다.
스택 할당을 새로운 메모리 관리 시스템에 맞추려면 userprog/process.c의 setup_stack을 조정해야 한다.
첫 번째 스택 페이지는 lazily 할당될 필요는 없다. 로드 시 명령어를 사용하여 할당하고 초기화할 수 있다.
스택을 식별하는 방법을 제공해야 할 수도 있다. vm/vm.h의 vm_type에 있는 보조 마커를 사용하여 페이지를 표시할 수 있다.
마지막으로, vm_try_handle_fault 함수를 수정하여 페이지 폴트가 발생한 주소에 해당하는 페이지 구조를 해결해야 한다.
Supplemental Page Table - Revisit
이제 복사 및 정리 작업을 지원하기 위해 spt 인터페이스를 수정해야 한다. 이러한 연산은 프로세스를 생성하거나 폐기할 때 필요하다.
Implement supplemental_page_table_copy and supplemental_page_table_kill in vm/vm.c.
bool supplemental_page_table_copy (struct supplemental_page_table *dst, struct supplemental_page_table *src);
인자로 받은 src에서 dst로 spt를 복사한다. 이는 자식이 부모의 실행 문맥을 물려받을 필요가 있을 때 사용된다.
src spt의 각 페이지를 반복하고 dst spt의 항목을 정확하게 복사한다.
void supplemental_page_table_kill (struct supplemental_page_table *spt);
spt에 의해 보유되었던 모든 리소스를 해제한다. 이 함수는 프로세스가 종료될 때 호출된다(userprog/process.c의 process_exit()).
페이지 엔트리를 반복하며 돌면서 destroy를 호출해야 한다.
Page Cleanup
Implement uninit_destroy in vm/uninit.c and anon_destroy in vm/anon.c.
초기화되지 않은 페이지의 삭제 작업을 위한 핸들러이다.
초기화되지 않은 페이지가 다른 페이지 객체로 변환되더라도 프로세스가 종료될 때 연전히 초기화되지 않은 페이지가 있을 수 있다.
static void uninit_destroy (struct page *page);
페이지 구조체에 유지된 리소스를 해제한다. 페이지의 VM 유형을 확인하고 그에 따라 처리하는 것이 좋다.
static void anon_destroy (struct page *page);
anonymous page에 저장된 리소스를 해제한다. 페이지 구조를 명시적으로 해제할 필요는 없다.
'카이스트 정글 - 프로젝트 > Pintos' 카테고리의 다른 글
Project_3 : Virtual Memory - Stack Growth(1) (0) | 2022.01.23 |
---|---|
Project_3 : Virtual Memory - Anonymous Page(2) (0) | 2022.01.22 |
Project_3 : Virtual Memory - Memory Management(2) (0) | 2022.01.19 |
Project_3 : Virtual Memory - Memory Management(1) (0) | 2022.01.14 |
Project_3 : Virtual Memory - Introduction (0) | 2022.01.11 |