프로세스가 가상 페이지를 통해 물리 메모리에 접근하려 시도할 때, 물리 프레임이 모두 꽉 차 있으면 물리 메모리에서 적당한 하나의 프레임을 골라 디스크로 Swap Out 한다. 이 때 swap out할 적당한 프레임을 고르는 정책을 Page Replacement Policy라고 부른다.
앞에서 선언해주었던 struct frame과 frame_table 리스트를 다시 한번 가져와보자. 이 둘의 존재 이유는 물리 프레임들을 관리해주면서 swap out시킬 적당한 프레임을 고르기 편하게 해 주는 데에 있다.
include/vm/vm.h
struct frame {
void *kva;
struct page *page;
struct list_elem frame_elem;
}
vm.c
frame들을 관리하는 frame table 리스트와 해당 리스트를 순회해주기 위한 start 변수를 선언해준다.
struct list frame_table;
struct list_elem *start;
vm.c/vm_init()
맨 처음 가상 메모리에 대한 서브 시스템들을 초기화해주는 vm_init() 함수에서 프레임 테이블과 start 변수도 초기화해준다.
void vm_init(void)
{
vm_anon_init();
vm_file_init();
#ifdef EFILESYS /* For project 4 */
pagecache_init();
#endif
register_inspect_intr();
list_init(&frame_table); // 수정!
start = list_begin(&frame_table); // 수정!
}
vm_init()은 언제 실행되는가?
init.c → main() → vm_init()의 순서로 실행된다. 핀토스의 메인 프로그램이 실행될 때 같이 실행된다.
이제 페이지를 claim할 때 페이지에 해당하는 물리 프레임을 가져오는 vm_get_frame()을 수정한다.
페이지를 물리 메모리 공간에 palloc하여 할당받는 과정에서 아무 것도 받아오지 못했다면, 물리 프레임에 자리가 없어 가져오지 못한 것으로 판단한다. 그렇담 vm_evict_frame()을 호출하여 프레임 하나의 데이터를 swap out해버리고 해당 프레임과 새 페이지를 매핑해줄 것이다.
이 때 프레임을 할당받은 다음에 물리 프레임을 관리하는 struct frame을 페이지 테이블에 insert시켜 관리한다.
static struct frame *vm_get_frame(void)
{
// struct frame *frame = NULL;
/* TODO: Fill this function. */
struct frame *frame = (struct frame *)malloc(sizeof(struct frame));
frame->kva = palloc_get_page(PAL_USER); /* USER POOL에서 커널 가상 주소 공간으로 1page 할당 */
/* if 프레임이 꽉 차서 할당받을 수 없다면 페이지 교체 실시
else 성공했다면 frame 구조체 커널 주소 멤버에 위에서 할당받은 메모리 커널 주소 넣기 */
if (frame->kva == NULL)
{
frame = vm_evict_frame(); // 수정!
frame->page = NULL;
return frame;
}
/* 새 프레임을 프레임 테이블에 넣어 관리한다. */
list_push_back (&frame_table, &frame->frame_elem);
frame->page = NULL;
ASSERT(frame != NULL);
ASSERT(frame->page == NULL);
return frame;
}