Anonymous Page 구현

developer_jennifer·2023년 6월 20일
0

크래프톤 정글

목록 보기
22/29

Anonymous Page 구현

🤔 왜 구현하는데?
프로세스의 가상 메모리 공간을 관리하기 위해 구현해야 하는 중요한 요소로 디스크에 저장된 파일과 연결되지 않은, 메모리 상에서만 존재하는 페이지이다.

  • anonymoust page가 있으면 좋은 이유
    (1) 스왑 공간 활용- 스왑 공간을 활용하여 메모리 부족 상황에서 페이지를 스왑아웃하는 것이 가능
    (2) 메모리 할당을 유연하게 할 수 있음(가상 메모리 공간 안에서)
    (3) 파일 매핑 이외의 메모리 영역을 다룰 수 있음

Anonymous page까지의 전체 흐름 파악

Lazy Loading for executable

구현하기 위한 절차(순서)
1. lazy_load_segment() 함수 설정 : 첫번째 페이지 폴트가 발생했을 때 실행하며 해당 세그먼트를 로드하고 초기화하는 역할을 함, lazy_load_segment()함수를 생성해서 세그먼트 lazy loading을 처리
2. vm_alloc_page_with_initializer()에서 가상 메모리를 할당 : 각 페이지는 lazy loading을 위해 uninit_new() 함수로 초기화 한후 lazy_load_segment() 함수로 설정
3. 페이지 폴트 처리 : 페이지 폴트가 발생하면 페이지 폴트 핸들러를 호출하는데, 페이지 폴트 핸들러는 해당 페이지가 로드되어 있지 않은 경우 'lazy_load_segment()' 함수를 호출하여 해당 세그먼트를 로드하고 초기화
4. 파일 읽기 : lazy_load_segment() 함수 내에서 파일 내용을 읽어와 메모리에 쓰는 작업을 수행
5. 페이지 초기화 : memset() 함수를 사용하여 초기화되지 않은 나머지 부분을 0으로 설정
6. 페이지 테이블 업데이트 : 로드한 페이지를 페이지 테이블에 매핑(spt_insert_page)

1,3,4,5 lazy_load_segment()함수 설정

static bool
lazy_load_segment (struct page *page, void *aux) {
	/* TODO: Load the segment from the file */
	/* TODO: This called when the first page fault occurs on address VA. */
	/* TODO: VA is available when calling this function. */
	struct lazy_load_arg *lazy_load_arg=(struct lazy_load_arg *)aux;

	//1) 파일의 position을 ofs으로 지정한다. 세그먼트의 시작 위치를 ofs으로 설정
	file_seek(lazy_load_arg->file,lazy_load_arg->ofs);
	//2) 파일을 read_bytes만큼 물리 프레임에 읽어 들인다. 이때 읽은 바이트 수가 read_bytes수와 다르면 할당된 메모리를 해제하고 false 반환
	if(file_read(lazy_load_arg->file, page->frame->kva, lazy_load_arg->read_bytes)!=(int)(lazy_load_arg->read_bytes)){
		palloc_free_page(page->frame->kva);
		return false;
	}
	//3) 다 읽은 지점부터 zero_bytes만큼 0으로 채운다.
	//이때 memset 함수는 특정 메모리 영역을 지정된 값으로 설정하는 역할을 함
	memset(page->frame->kva + lazy_load_arg->read_bytes,0,lazy_load_arg->zero_bytes);

	return true;
}

2,6 ```bool vm_alloc_page_with_initializer (enum vm_type type, void va, bool writable, vm_initializer init, void aux);```

주어진 타입의 초기화되지 않은 페이지를 생성

(1) 초기화 되지 않은 페이지를 생성
(2) 생성된 페이지의 swap_in 핸들러가 호출된다. 이 핸들러는 페이지를 초기화하고 주어진 aux와 함께 init을 호출하여 페이지를 초기 상태로 설정
→ swap_in 핸들러는 페이지 폴트 핸들러의 일부로 해당 페이지를 메모리로 로드하는 역할을 한다. 이때 swap_in 함수 내에서 uninit_initialize 함수에 도달하는데 이 부분을 수정해야 할수도 있다.
(3) 페이지 구조체를 프로세스의 보조 페이지 테이블에 삽입해서 페이지의 가상주소와 물리 주소간의 매핑이 이루어짐

struct page *p = (struct page *)malloc(sizeof(struct page));
bool(*page_initializer)(struct page*,enum vm_type,void *); // 포인터를 나타냄

		switch(VM_TYPE(type)){
			case VM_ANON:
				page_initializer = anon_initializer;
				break;
			case VM_FILE:
				page_initializer = file_backed_initializer;
				break;
		}

		uninit_new(p,upage,init,type,aux,page_initializer);//uninit_new 호출해서 "uninit" 페이지 구조체를 생성

		p->writable = writable; //page의 상태를 수정 가능한 상태로 만듦

		return spt_insert_page(spt,p); // 페이지를 만들었으므로 spt에 페이지 삽입

Supplemental Page Table - Revisit

supplemental_page_table_copysupplemnetal_page_table_kill 함수를 구현해서 spt의 복사와 제거를 지원한다.

  1. supplemental_page_table_copy : 자식이 부모의 실행 컨텍스트를 상속해야 할때 사용됨
  • 구현 과정
    (1) dst spt를 초기화
    (2) src spt의 모든 엔트리를 순회하면서 엔트리의 정보를 dst에 복사한다. 이때 각 가상 주소와 frame 정보를 복사
    (3) 복사가 실패하면 false 반환 후 성공하면 true
bool
supplemental_page_table_copy (struct supplemental_page_table *dst UNUSED,
		struct supplemental_page_table *src UNUSED) {
			struct hash_iterator i;
			hash_first(&i, &src->spt_hash);
			while(hash_next(&i)){
				//src_page 정보
				struct page *src_page = hash_entry(hash_cur(&i), struct page, hash_elem);
				enum vm_type type = src_page ->operations->type;
				void *upage = src_page -> va;
				bool writable = src_page->writable;

				/*1) type이 uninit이면 */
				if(type == VM_UNINIT){
					vm_initializer *init = src_page -> uninit.init;
					void *aux = src_page->uninit.aux;
					vm_alloc_page_with_initializer(VM_ANON,upage,writable,init,aux);
					continue;
				}

				/*2) type이 uninit이 아니면*/
				if(!vm_alloc_page_with_initializer(type,upage,writable,NULL,NULL)) return false;

				if(!vm_claim_page(upage)) return false;

				struct page *dst_page = spt_find_page(dst,upage);
				memcpy(dst_page->frame->kva,src_page->frame->kva,PGSIZE);
			}
			return true;
}
  1. supplemental_page_table_kill : 프로세스가 종료될 때 호출(exit())
  • 구현 과정
    (1) 각 엔트리에 연결된 페이지를 제거한다. 이때 페이지의 프레임과 관련 자원을 해제한다.
void
supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) {
	/* TODO: Destroy all the supplemental_page_table hold by thread and
	 * TODO: writeback all the modified contents to the storage. */
	/*페이지 테이블과 관련된 자원만 해제, 해시 테이블은 그대로 보존 */
	hash_clear(&spt->spt_hash,hash_page_destroy); // 해시 테이블에서 모든 요소를 제거
}

(2) hash_page_destroy 함수를 추가 구현해준다.

/* 페이지 구조체에 메모리 해제 작업을 수행*/
void hash_page_destroy(struct hash_elem *e, void *aux){
	struct page *page =hash_entry(e,struct page, hash_elem);
	destroy(page);
	free(page);
}

Page Cleanup

  1. uninit_destroy
  2. anon_destroy
    이거 2개를 구현해야 한다고 하는데 잘 모르겠다..
    일단 return 넣어줌

🤔 rehash란?
해시 충돌을 해결하기 위해 해시 테이블의 크기를 확장하거나 재구성 하는 작업
1. 더 큰 크기의 새로운 해시 테이블 생성
2. 기존 해시 테이블의 모든 요소를 순회하면서 새로운 해시 테이블에 재배치
3. 재배치된 요소들을 기존 해시 테이블에서 제거하고, 메모리를 해제
4. 새로운 해시 테이블로 대체

profile
블로그 이전합니다 -> https://heekyoung2000.tistory.com/

0개의 댓글

관련 채용 정보