[목표]
fork를 제외하고 모든 테스트 케이스가 돌아가는지 확인해봅니다. (진행중)
fork도 돌아갈 수 있는 코드를 만듭니다.
빨래를 하고 왔습니다.
어제의 내용을 정리해서 게제했습니다. 그러나 다른 코드 트러블 슈팅 내용이나 어떻게 구현했는지 작성해야될 것들이 많아서 식사하고 정리를 해야될 것 같습니다.
햄버거를 먹으러 갔다왔습니다. 오면서 올리브영에서 선스프레이를 사서 왔다.

Memory Managment라는 부분을 노션에 정리했습니다. 어떻게 구현했는지. 어떤식의 함수와 구조체를 썻는지 써두었습니다.
운동(어깨)를 하고, 샤워하고 왔습니다.
식사와 휴식을 가졌습니다.

Anonymous Page에 대해서 빠르게 정리하고 kill관련 코드를 구현해보겠습니다.
길고 긴 시간이었지만, 하루를 다썻지만, 정리를 해보니 이해도 되고 좋은 것 같습니다. 나중에 회고할 때 도움이 많이 될 것 같습니다.
git에 커밋을 하고, fork 테스트 케이스가 통과되도록 코드를 gitbook에 따라 작성해보겠습니다.
supplemental_page_table_copy 라는 함수를 구현해봅니다.
해당 함수는 fork과정에서 부모의 주소를 자식에게 복사해주는 기능을 한다.
부모의 주소 공간을 src라 지칭하고, 자식의 주소 공간을 dst라고 지칭한다.
src와 dst는 지칭하는 대명사라고 생각하면되고, src에는 현재 스레드의 spt가 들어갈 것이다.
// src에서 dst로 보충 페이지 테이블 복사합니다.
// 부모 프로세스가 자식에 상속할 떄 사용. 이 함수의 결과로 자식은 부모의 주소를 완벽히 복사한다.
// src는 부모의 주소 공간, dst는 자식의 주소 공간이다.
// src와 dst는 지칭하는 대명사와 같다. 결론적으로 src에는 현재 스레드의 spt가 들어갈것이다.
bool
supplemental_page_table_copy (struct supplemental_page_table *dst UNUSED,
struct supplemental_page_table *src UNUSED) {
// src의 해시 테이블 순회 준비
struct hash_iterator i;
hash_first(&i, &src -> spt_hash); // spt가 해쉬에 있음. first로 첫번째 버킷 지정
// 모든 page를 하나씩 순회(모든 버킷)
while (hash_next(&i)) {
struct page *src_page = hash_entry(hash_cur(&i), struct page, hash_elem);
// 공통 메타데이터 추출
void *va = src_page -> va;
enum vm_type type = page_get_type(src_page); // 부모 실제 타입 추출
bool writable = src_page -> writable;
// unint 타입인지 확인
if (type == VM_UNINIT) {
// init 함수와 aux 복사 (지연로딩)
struct uninit_page *uninit = &src_page -> uninit;
vm_initializer *init = uninit -> init;
void *aux = uninit -> aux;
// dst에 등록
vm_alloc_page_with_initializer(type, va, writable, init, aux);
}
// 초기화된 페이지라면
else {
// dst에도 동일한 페이지를 생성한다.
vm_alloc_page_with_initializer(type, va, writable, NULL, NULL);
// dst 페이지 가져와서 claim 한다.
struct page *dst_page = spt_find_page(dst, va);
vm_claim_page(va);
// 실제 프레임 데이터를 복사
memcpy(dst_page -> frame -> kva, src_page -> frame -> kva, PGSIZE); // 목적지, 출발지, 사이즈 순이다.
}
// 기타 속성을 복사
if (src_page -> is_stack)
spt_find_page(dst, va) -> is_stack = true;
}
return true;
}
용어 인덱스
| 용어 | 설명 |
|---|---|
| uninit page | 아직 물리 메모리에 로드되지 않았고, 실제 데이터도 없는 페이지. 단지 “어떻게 로딩할지”에 대한 정보만 가진 상태 |
| lazy loading | 페이지에 실제로 접근(Page Fault)할 때까지, 물리 메모리 할당과 파일 로딩을 미루는 기법 |
| uninit -> anon/file/etc. | 나중에 해당 페이지가 접근되면, uninit->page_initializer()를 통해 진짜 페이지로 변신함 |
다른조 코어타임, 스택을 쌓고 페이지 테이블을 삭제하는 여러가지 정보를 습득했다.
여기서 많이 들어서 우리 팀원 코어타임때 도움을 주도록 해야겠다. 그런데 너무 어렵다.
아까 이어서 supplemental_page_table_kill 함수를 구현해보겠다.
해당함수는 포크 완료 후에 사용이 완료된 자식 페이지를 해제하고 쓰기위해 쓰인다. 자원해제 같은거다.
해당 함수는 아까 코어타임에서 어느정도 흐름을 파악했고, 코드도 그리 어렵지 않아서 비교적 빨리 했다.
// 타입에 맞게 삭제해주는 함수.
void page_destroy (struct hash_elem *e, void *aux) {
struct page *src_page = hash_entry(e, struct page, hash_elem);
vm_dealloc_page(src_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. */
// 스레드가 보유한 supplemental_page_table을 모두 파괴하고 수정된 내용을 모두 저장소에 다시 쓰게 구현하세요.
hash_clear(&spt -> spt_hash, page_destroy); // 그 안에 있는 페이지들 해제(page_destroy), 해시들도 해제
// hash_destroy(&spt -> spt_hash, page_destroy); // hash_destory로 하면 문제가 생긴다. 아마 process_cleanup 두번하는 문제도 있고, 다양하다.
}
완료를 한다면, 다음과 같은 결과를 확인할 수 있다. 41개가 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
FAIL tests/userprog/fork-read
FAIL tests/userprog/fork-close
FAIL tests/userprog/fork-boundary
pass tests/userprog/exec-once
pass tests/userprog/exec-arg
FAIL tests/userprog/exec-boundary
pass tests/userprog/exec-missing
pass tests/userprog/exec-bad-ptr
FAIL 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
FAIL 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
FAIL tests/vm/mmap-ro
FAIL tests/vm/mmap-exit
FAIL tests/vm/mmap-shuffle
pass 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
pass tests/vm/mmap-bad-fd2
pass tests/vm/mmap-bad-fd3
pass 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
41 of 141 tests failed.
Page Cleanup (uninit_destroy, anon_destroy) 부분은 나중에 하라고 할 때 다시하면 된다고 한다. 그러니 앞으로는 Stack Growth 부분을 구현해보겠다. 내일이어서 하겠다. 해가 뜨고 있다...