Supplemental Page Table - Revisit
bool supplemental_page_table_copy (struct supplemental_page_table *dst,
struct supplemental_page_table *src);
git_book 설명:
보조 페이지 테이블을 src에서 dst로 복사합니다. 이 함수는 자식이 부모의 실행 컨텍스트를 상속해야 할 때 사용됩니다(예: fork()). src의 보충 페이지 테이블에 있는 각 페이지를 반복하고 dst의 보충 페이지 테이블에 있는 항목의 정확한 복사본을 만듭니다. 초기화되지 않은 페이지를 할당하고 즉시 청구해야 합니다.
supplemental_page_table_copy함수 호출하는 곳:
hash.c에 있는 hash_first 함수를 참고해 만들 수 있다.
/* Copy supplemental page table from src to 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);
while (hash_next(&i)) {
struct page *parent_page = hash_entry (hash_cur (&i), struct page, hash_elem);
enum vm_type type = page_get_type(parent_page);
void *upage = parent_page->va;
bool writable = parent_page->writable;
vm_initializer *init = parent_page->uninit.init;
void *aux = parent_page->uninit.aux;
if (parent_page->operations->type == VM_UNINIT) {
if (!vm_alloc_page_with_initializer(type, upage, writable, init, aux)) {
return false;
}
}
else {
if (!vm_alloc_page(type, upage, writable)) {
return false;
}
if (!vm_claim_page(upage)) {
return false;
}
struct page *child_page = spt_find_page(dst, upage);
memcpy(child_page->frame->kva, parent_page->frame->kva, PGSIZE);
}
}
return true;
}
원본 테이블(src)의 각 페이지를 순회하면서 동일한 페이지를 대상 테이블(dst)에 생성하고, 필요한 경우 원본 페이지의 데이터를 대상 페이지에 복사한다.
1. hash_first와 hash_next를 사용하여 원본 테이블의 각 페이지를 순회한다.
2. hash_entry를 사용하여 현재 페이지의 정보를 가져온다.
3. 페이지의 타입, 주소, 쓰기 가능 여부, 초기화 함수, 보조 데이터 등을 저장한다.
4. *페이지의 타입이 VM_UNINIT(초기화되지 않은)인 경우, 초기화 함수와 보조 데이터를 사용하여 대상 테이블에 새로운 페이지를 생성한다.
5. *페이지의 타입이 VM_UNINIT이 아닌 경우, 대상 테이블에 새로운 페이지를 생성하고, 해당 페이지를 claim(메모리를 할당)한다. 그 다음 원본 페이지의 데이터를 대상 페이지에 복사한다.
6. 모든 페이지가 성공적으로 처리되면 true를 반환하고, 그렇지 않으면 false를 반환한다.
* 페이지의 타입이 VM_UNINIT(초기화되지 않은)인 경우와 아닌 경우를 나눠서 처리하는 이유는 두 타입의 페이지가 메모리에 로드되는 방식이 다르기 때문이다.
VM_UNINIT 타입의 페이지는 아직 메모리에 로드되지 않은 상태를 나타낸다. 이런 페이지는 디스크에 저장되어 있거나, 아직 생성되지 않았을 수 있다. 이런
페이지를 메모리에 로드하려면 초기화 함수와 보조 데이터를 사용하여 페이지를 생성하고 초기화해야 한다. (이 과정에서 초기화 함수는 페이지의 데이터를 생성하거나 디스크에서 불러오는 등의 역할)
반면, VM_UNINIT이 아닌 페이지는 이미 메모리에 로드된 상태를 나타낸다. 이런 페이지를 다른 위치에 복사하려면 단순히 페이지의 데이터를 복사하면 된다. 이 과정에서 메모리 할당과 데이터 복사가 이루어진다.
void supplemental_page_table_kill (struct supplemental_page_table *spt);
git_book 설명:
보조 페이지 테이블이 보유하고 있던 모든 리소스를 해제합니다. 이 함수는 프로세스가 종료될 때 호출됩니다(userprog/process.c의 process_exit()). 페이지 항목을 반복하고 테이블의 페이지에 대해 destroy(page)를 호출해야 합니다. 이 함수에서 실제 페이지 테이블(pml4)과 물리적 메모리(할당된 메모리)는 걱정할 필요가 없습니다. 호출자는 보조 페이지 테이블이 정리된 후 이를 정리하기 때문입니다.
void
page_kill (struct hash_elem *e, void *aux) {
struct page *page = hash_entry(e, struct page, hash_elem);
destroy(page);
free(page);
}
/* Free the resource hold by the supplemental page table */
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, page_kill);
}
해시 테이블은 남기고 해시 테이블의 모든 요소를 제거하는 hash_clear함수를 써서 수행하면 된다. (해시 테이블까지 삭제하면 만들자마자 지워버리게 되는 셈이다)
여기까지 했을 때 read관련된 테이스가 모두 fail했다...
read에서 checkadress가 문제였다.
void check_address(void *addr) {
struct thread *t = thread_current();
if (!is_user_vaddr(addr) || addr == NULL || pml4_get_page(t->pml4 , addr) == NULL) {
exit(-1);
}
}
문제점을 찾아보시오~!!
.
.
.
.
.
vm에서는 page fault가 발생한다. 아직 메모리에 로드되지 않았을 경우도 있기에 위 함수에서 'pml4_get_page(t->pml4 , addr) == NULL' 경우를 제외시켜줘야 한다.
여기까지 했을 때 테스트 결과 userprog 테스트가 모두 통과하게 된다.
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
'개발일지 > PintOS' 카테고리의 다른 글
pintos - virtual memory(7) (0) | 2023.12.25 |
---|---|
pintos - virtual memory(6) (0) | 2023.12.22 |
pintos - virtual memory(4) (0) | 2023.12.20 |
pintos - virtual memory(3) (0) | 2023.12.19 |
pintos - Virtual Memory(1) (0) | 2023.12.14 |