[TIL] [WEEK11-12] Pintos Project(3) Anonymous Page 2.

woo__j·2024년 6월 13일
0

Pintos Project

목록 보기
11/14

먼저 page_fault() 함수를 보면 #ifdef VM 일 때 vm_try_handle_fault()를 호출한다.


🛠️ vm_try_handle_fault()

해당 함수는 page fault가 발생했을 때 제어권을 받아 처리하는 함수다.
접근한 메모리에 물리 프레임이 존재하지 않을 경우 spt에서 인자로 받은 가상주소에 해당하는 페이지를 확인한다. 존재한다면 쓰기 가능한 페이지인지(writable == 0) 확인한 후 해당 페이지에 물리 프레임 할당해준다. (= vm_do_claim_page 호출)

만약 접근한 메모리에 물리 프레임이 존재하는 경우엔, 물리 프레임이 할당되어 있으면서도 page fault가 일어난 상황이다. 이는 읽기 전용 페이지에 쓰기를 시도한 경우다. 따라서 이 또한 예외처리 해주도록 한다.

bool vm_try_handle_fault(struct intr_frame *f UNUSED, void *addr UNUSED,
						 bool user UNUSED, bool write UNUSED, bool not_present UNUSED)
{
	struct supplemental_page_table *spt UNUSED = &thread_current()->spt;
	struct page *page = NULL;

	if (addr == NULL)
	{
		return false;
	}

	if (is_kernel_vaddr(addr))
	{
		return false;
	}

	/* 접근한 메모리의 물리 프레임이 존재하지 않는 경우, not_present = true */
	if (not_present)
	{
		void *rsp = f->rsp;
		if (!user)
			rsp = thread_current()->rsp;

		/* spt에서 해당 가상 주소에 해당하는 페이지 반환 */
		page = spt_find_page(spt, addr);
		if (page == NULL)
		{
			return false;
		}
		/* 쓰기가 불가능한 페이지(0)에 write를 요청한 경우 */
		if (write == 1 && page->writable == 0)
		{
			return false;
		}
		return vm_do_claim_page(page);
	}
	return false;
}

Anonymous Page 파트 너무 길다..
정말 마지막으로 spt - revisit 부분만 구현하면 해당 파트 끝이다.


🛠️ Supplemental Page Table - Revisit

vm_try_handle_fault()까지 수정해도 fork 관련된 test case는 fail이 뜨는데,
그 이유는 이전 프로젝트에서 구현한 fork 시스템 콜에서, spt를 복사하는 함수가 구현되지 않아서 그렇다.

해당 부분을 자세히 찾아보면 __do_fork()에서 #ifdef VM을 보면 supplemental_page_table_copy()를 호출하는 것을 볼 수 있다.
생각해보면 thread 구조체에 spt를 추가했는데, 해당 멤버변수를 복사하는 것도 추가해야겠지?

자식 프로세스를 생성하거나, 프로세스가 종료될 때 spt를 copy 하는 함수와 kill 하는 함수 두 가지를 구현해야 한다.

1) supplemental_page_table_copy()
해당 함수는 자식 프로세스를 생성할 때 부모 프로세스의 spt를 자식 프로세스에게 상속해주는(복사해주는) 함수다.
src의 각각의 페이지들을 반복문으로 모두 dst에 복사한다.

각 페이지 타입에 맞게 할당받고 초기화한다.
현재까지는 uninit과 anon까지만 구현했기 때문에 두 부분만 생각해서 복사해주면 된다.

먼저 uninit type이라면 vm_alloc_page_with_initializer를 호출해 uninit type의 페이지를 생성하고 초기화하면 된다.

그리고 anon type이라면 내용이 로딩된 상태이기 때문에 페이지를 할당받은 후 매핑을 해주고 내용까지 복사시켜줘야 한다. 먼저 vm_alloc_page로 페이지를 할당받은 후, vm_claim_page로 매핑 처리, 마지막으로 memcpy로 내용을 복사해준다.

지금은 아직 구현하지 않았지만 나중에 file_backed type일 경우도 추가해줘야 한다.

/* 자식 프로세스 생성할 때 spt 복사하는 함수 */
/* src를 dst에 복사 */
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);
	/* src 각각의 페이지들을 반복문으로 복사 */
	while (hash_next(&i))
	{
		/* 현재 src_page의 속성들 */
		struct page *src_page = hash_entry(hash_cur(&i), struct page, bucket_elem);
		enum vm_type type = src_page->operations->type;
		void *upage = src_page->va;
		bool writable = src_page->writable;

		/* page가 uninit type이라면  */
		if (type == VM_UNINIT)
		{
			/* uninit type의 페이지 생성 및 초기화 */
			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;
		}

		/* page가 anon type이라면 */
		if (!vm_alloc_page(type, upage, writable))
		{
			return false;
		}

		/* 부모 type의 초기화 함수를 담은 uninit page로 초기화 후 */
		/* page fault 처리 (vm_claim_page) 후, 즉 페이지와 프레임을 매핑해준 후 */
		if (!vm_claim_page(upage))
		{
			return false;
		}

		/* memcpy로 매핑된 프레임에 내용을 복사 */ 
		struct page *dst_page = spt_find_page(dst, upage);
		memcpy(dst_page->frame->kva, src_page->frame->kva, PGSIZE);
	}
	return true;
}

2) supplemental_page_table_kill()
이는 프로세스가 종료될 때와 & 실행 중 process_cleanup()에서 호출된다.

supplemental_page_table_kill()은 spt의 페이지 항목들을 순회하며 각 페이지 type에 맞는 destroy 함수를 호출함으로써 spt의 각 bucket에 들어있는 page들을 지운다.

spt는 해시 테이블이므로, hash_clear()를 호출해 삭제해주도록 하자.
인자로 hash_page_destroy를 넣어주는데, 이는 destroy 매크로를 호출해 각 페이지 type에 맞는 destroy 함수를 호출한다.

/* 프로세스가 종료될 때와 실행 중 process_cleanup을 호출할 때 */
/* 페이지 항목들을 순회하며 페이지 type에 맞는 destroy 함수 호출 */
void supplemental_page_table_kill(struct supplemental_page_table *spt UNUSED)
{
	hash_clear(&spt->spt_hash, hash_page_destroy);
}

void hash_page_destroy(struct hash_elem *e, void *aux)
{
	struct page *page = hash_entry(e, struct page, bucket_elem);
	destroy(page);
	free(page);
}

#define destroy(page)                \
	if ((page)->operations->destroy) \
	(page)->operations->destroy(page)

해당 부분까지 구현했을 때, 38/141 fail이 뜬다.

pass tests/userprog/args-none
pass tests/userprog/args-single
pass tests/userprog/args-multiple
pass tests/userprog/args-many
pass tests/userprog/args-dbl-space
pass tests/userprog/halt
pass tests/userprog/exit
pass tests/userprog/create-normal
pass tests/userprog/create-empty
pass tests/userprog/create-null
pass tests/userprog/create-bad-ptr
pass tests/userprog/create-long
pass tests/userprog/create-exists
pass tests/userprog/create-bound
pass tests/userprog/open-normal
pass tests/userprog/open-missing
pass tests/userprog/open-boundary
pass tests/userprog/open-empty
pass tests/userprog/open-null
pass tests/userprog/open-bad-ptr
pass tests/userprog/open-twice
pass tests/userprog/close-normal
pass tests/userprog/close-twice
pass tests/userprog/close-bad-fd
pass tests/userprog/read-normal
pass tests/userprog/read-bad-ptr
pass tests/userprog/read-boundary
pass tests/userprog/read-zero
pass tests/userprog/read-stdout
pass tests/userprog/read-bad-fd
pass tests/userprog/write-normal
pass tests/userprog/write-bad-ptr
pass tests/userprog/write-boundary
pass tests/userprog/write-zero
pass tests/userprog/write-stdin
pass tests/userprog/write-bad-fd
pass tests/userprog/fork-once
pass tests/userprog/fork-multiple
pass tests/userprog/fork-recursive
pass tests/userprog/fork-read
pass tests/userprog/fork-close
pass tests/userprog/fork-boundary
pass tests/userprog/exec-once
pass tests/userprog/exec-arg
pass tests/userprog/exec-boundary
pass tests/userprog/exec-missing
pass tests/userprog/exec-bad-ptr
pass tests/userprog/exec-read
pass tests/userprog/wait-simple
pass tests/userprog/wait-twice
pass tests/userprog/wait-killed
pass tests/userprog/wait-bad-pid
pass tests/userprog/multi-recurse
pass tests/userprog/multi-child-fd
pass tests/userprog/rox-simple
pass tests/userprog/rox-child
pass tests/userprog/rox-multichild
pass tests/userprog/bad-read
pass tests/userprog/bad-write
pass tests/userprog/bad-read2
pass tests/userprog/bad-write2
pass tests/userprog/bad-jump
pass tests/userprog/bad-jump2
FAIL tests/vm/pt-grow-stack
pass tests/vm/pt-grow-bad
FAIL tests/vm/pt-big-stk-obj
pass tests/vm/pt-bad-addr
pass tests/vm/pt-bad-read
pass tests/vm/pt-write-code
FAIL tests/vm/pt-write-code2
FAIL tests/vm/pt-grow-stk-sc
pass tests/vm/page-linear
pass tests/vm/page-parallel
pass tests/vm/page-merge-seq
FAIL tests/vm/page-merge-par
FAIL tests/vm/page-merge-stk
FAIL tests/vm/page-merge-mm
pass tests/vm/page-shuffle
FAIL tests/vm/mmap-read
FAIL tests/vm/mmap-close
FAIL tests/vm/mmap-unmap
FAIL tests/vm/mmap-overlap
FAIL tests/vm/mmap-twice
FAIL tests/vm/mmap-write
pass tests/vm/mmap-ro
FAIL tests/vm/mmap-exit
FAIL tests/vm/mmap-shuffle
FAIL tests/vm/mmap-bad-fd
FAIL tests/vm/mmap-clean
FAIL tests/vm/mmap-inherit
FAIL tests/vm/mmap-misalign
FAIL tests/vm/mmap-null
FAIL tests/vm/mmap-over-code
FAIL tests/vm/mmap-over-data
FAIL tests/vm/mmap-over-stk
FAIL tests/vm/mmap-remove
pass tests/vm/mmap-zero
FAIL tests/vm/mmap-bad-fd2
FAIL tests/vm/mmap-bad-fd3
FAIL tests/vm/mmap-zero-len
FAIL tests/vm/mmap-off
FAIL tests/vm/mmap-bad-off
FAIL tests/vm/mmap-kernel
FAIL tests/vm/lazy-file
pass tests/vm/lazy-anon
FAIL tests/vm/swap-file
FAIL tests/vm/swap-anon
FAIL tests/vm/swap-iter
FAIL tests/vm/swap-fork
pass tests/filesys/base/lg-create
pass tests/filesys/base/lg-full
pass tests/filesys/base/lg-random
pass tests/filesys/base/lg-seq-block
pass tests/filesys/base/lg-seq-random
pass tests/filesys/base/sm-create
pass tests/filesys/base/sm-full
pass tests/filesys/base/sm-random
pass tests/filesys/base/sm-seq-block
pass tests/filesys/base/sm-seq-random
FAIL tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
FAIL tests/filesys/base/syn-write
pass tests/threads/alarm-single
pass tests/threads/alarm-multiple
pass tests/threads/alarm-simultaneous
pass tests/threads/alarm-priority
pass tests/threads/alarm-zero
pass tests/threads/alarm-negative
pass tests/threads/priority-change
pass tests/threads/priority-donate-one
pass tests/threads/priority-donate-multiple
pass tests/threads/priority-donate-multiple2
pass tests/threads/priority-donate-nest
pass tests/threads/priority-donate-sema
pass tests/threads/priority-donate-lower
pass tests/threads/priority-fifo
pass tests/threads/priority-preempt
pass tests/threads/priority-sema
pass tests/threads/priority-condvar
pass tests/threads/priority-donate-chain
FAIL tests/vm/cow/cow-simple
38 of 141 tests failed.

⚙️ Modify List

- vm_alloc_page_with_initializer()
- load_segment()
- lazy_load_segment()
- setup_stack()
- vm_try_handle_fault()

0개의 댓글

관련 채용 정보