๐ฉ๐ปโ๐ป GITHUB ๋ ํฌ์งํ ๋ฆฌ
๐ฉ๐ปโ๐ป GITHUB Copy On Write ์ด์
Copy-on-write๋ ๋์ผํ ๋ฌผ๋ฆฌ ํ์ด์ง์ ์ธ์คํด์ค๋ฅผ ์ด์ฉํ์ฌ ๋ ๋น ๋ฅธ ๋ณต์ ์์
์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฆฌ์์ค ๊ด๋ฆฌ ๊ธฐ์ ์ด๋ค. ์ผ๋ฐ์ ์ผ๋ก, ์ด๋ค ๋ฆฌ์์ค๊ฐ ์ฌ๋ฌ ํ๋ก์ธ์ค์ ์ํด ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ, ์ถฉ๋์ด ๋ฐ์ํ์ง ์๋๋ก ๊ฐ ํ๋ก์ธ์ค์๋ ํด๋น ๋ฆฌ์์ค์ ๊ณ ์ ํ ๋ณต์ฌ๋ณธ์ด ์์ด์ผ ํ๋ค. ํ์ง๋ง ๋ฆฌ์์ค๊ฐ ์์ ๋์ง ์๊ณ ์ฝ๊ธฐ๋ง ํ๋ ๊ฒฝ์ฐ์๋ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ํด๋น ๋ฆฌ์์ค์ ๋ํ ์ฌ๋ฌ๊ฐ์ ๋ณต์ฌ๋ณธ์ด ์์ ํ์๊ฐ ์๋ค.
๊ทธ๋์ fork
๋ฅผ ํ ๋์๋ ์๋ก์ด ๋ฌผ๋ฆฌ ํ์ด์ง๋ฅผ ํ ๋นํ์ง ์๊ณ ๋ถ๋ชจ์ ๊ฐ์ ๋ฌผ๋ฆฌ ํ์ด์ง๋ฅผ ๋งคํ๋ง ํด์ฃผ์๋ค๊ฐ ์ถํ์ write
๋ฅผ ์๋ํ ๋์๋ง ์๋ก์ด ๋ฌผ๋ฆฌ ํ์ด์ง๋ฅผ ํ ๋นํด ์ฃผ๋ฉด ๋๋ค.
strutc page {
...
/** Project 3-Memory Management */
struct hash_elem hash_elem;
bool writable;
/** Project 3-Copy On Write */
bool accessible;
};
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
/** Project 3-Memory Management */
hash_init(spt, page_hash, page_less, NULL);
}
/* 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) {
/** Project 3-Memory Mapped Files */
struct hash_iterator iter;
hash_first(&iter, &src->spt_hash);
while (hash_next(&iter)) {
struct page *src_page = hash_entry(hash_cur(&iter), struct page, hash_elem);
enum vm_type type = src_page->operations->type;
void *upage = src_page->va;
bool writable = src_page->writable;
if (type == VM_UNINIT) {
void *aux = src_page->uninit.aux;
vm_alloc_page_with_initializer(page_get_type(src_page), upage, writable, src_page->uninit.init, aux);
}
else if (type == VM_FILE) {
struct vm_load_arg *aux = malloc(sizeof(struct vm_load_arg));
aux->file = src_page->file.file;
aux->ofs = src_page->file.offset;
aux->read_bytes = src_page->file.page_read_bytes;
if (!vm_alloc_page_with_initializer(type, upage, writable, NULL, aux))
return false;
struct page *dst_page = spt_find_page(dst, upage);
file_backed_initializer(dst_page, type, NULL);
dst_page->frame = src_page->frame;
pml4_set_page(thread_current()->pml4, dst_page->va, src_page->frame->kva, src_page->writable);
}
else {
if (!vm_alloc_page(type, upage, writable))
return false;
/** Project 3-Copy On Write */
// 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);
if (!vm_copy_claim_page(dst, upage, src_page->frame->kva, writable))
return false;
}
}
return true;
}
/** Project 3-Copy On Write */
static bool
vm_copy_claim_page(struct supplemental_page_table *dst, void *va, void *kva, bool writable) {
struct page *page = spt_find_page(dst, va);
if (page == NULL)
return false;
struct frame *frame = (struct frame *)malloc(sizeof(struct frame));
if (!frame)
return false;
page->accessible = writable;
frame->page = page;
page->frame = frame;
frame->kva = kva;
if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, false)) {
free(frame);
return false;
}
list_push_back(&frame_table, &frame->frame_elem);
return swap_in(page, frame->kva);
}
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;
/** Project 3-Copy On Write */
struct page *page = spt_find_page(&thread_current()->spt, addr);
if (addr == NULL || is_kernel_vaddr(addr))
return false;
if (!not_present && write)
return vm_handle_wp(page);
if (!page) {
void *rsp = user ? f->rsp : thread_current()->stack_pointer;
if (STACK_LIMIT <= rsp - 8 && rsp - 8 == addr && addr <= USER_STACK){
vm_stack_growth(thread_current()->stack_bottom - PGSIZE);
return true;
}
else if (STACK_LIMIT <= rsp && rsp <= addr && addr <= USER_STACK){
vm_stack_growth(thread_current()->stack_bottom - PGSIZE);
return true;
}
return false;
}
return vm_do_claim_page(page);
}
static bool
vm_handle_wp (struct page *page UNUSED) {
/** Project 3-Copy On Write */
if (!page->accessible)
return false;
void *kva = page->frame->kva;
page->frame->kva = palloc_get_page(PAL_USER | PAL_ZERO);
if (page->frame->kva == NULL)
page->frame = vm_evict_frame();
memcpy(page->frame->kva, kva, PGSIZE);
if (!pml4_set_page(thread_current()->pml4, page->va, page->frame->kva, page->accessible))
return false;
return true;
}
process_cleanup
์ ์ํํ๊ฒ ๋๋๋ฐ ์ด ๋ spt๋ฅผ ์ง์ฐ๋ ๊ฒ ๋ฟ๋ง ์๋๋ผ pml4๋ ๊ฐ์ด ํ๊ดดํ๋ค. pml4_destroy
๋ฅผ ๋ง๊ณ pml4_clear
๋ง ์ํํ์ฌ kva์ ์ฐ๊ฒฐ๋ง ๋์ ์ํ๋ก ๋ง๋ค์ด ์ฌ๊ฐ์ฉํ๊ฒ ๋๋ ค์ค๋ค. ๊ทธ๋ฆฌ๊ณ ๋์ค์ OS๊ฐ ์ข
๋ฃ๋ ๋๋ง kva๋ฅผ destory์ํค๋๋ก ํ๋ค.static void
anon_destroy (struct page *page) {
struct anon_page *anon_page = &page->anon;
/** Project 3-Swap In/Out */
if (anon_page->page_no != BITMAP_ERROR)
bitmap_reset(swap_bitmap, anon_page->page_no);
if (page->frame) {
lock_acquire(&swap_lock);
list_remove(&page->frame->frame_elem);
lock_release(&swap_lock);
page->frame->page = NULL;
free(page->frame);
page->frame = NULL;
}
pml4_clear_page(thread_current()->pml4, page->va); /** Project 3-Copy On Write */
}
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
pass tests/vm/pt-grow-stack
pass tests/vm/pt-grow-bad
pass tests/vm/pt-big-stk-obj
pass tests/vm/pt-bad-addr
pass tests/vm/pt-bad-read
pass tests/vm/pt-write-code
pass tests/vm/pt-write-code2
pass tests/vm/pt-grow-stk-sc
pass tests/vm/page-linear
pass tests/vm/page-parallel
pass tests/vm/page-merge-seq
pass tests/vm/page-merge-par
pass tests/vm/page-merge-stk
pass tests/vm/page-merge-mm
pass tests/vm/page-shuffle
pass tests/vm/mmap-read
pass tests/vm/mmap-close
pass tests/vm/mmap-unmap
pass tests/vm/mmap-overlap
pass tests/vm/mmap-twice
pass tests/vm/mmap-write
pass tests/vm/mmap-ro
pass tests/vm/mmap-exit
pass tests/vm/mmap-shuffle
pass tests/vm/mmap-bad-fd
pass tests/vm/mmap-clean
pass tests/vm/mmap-inherit
pass tests/vm/mmap-misalign
pass tests/vm/mmap-null
pass tests/vm/mmap-over-code
pass tests/vm/mmap-over-data
pass tests/vm/mmap-over-stk
pass 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
pass tests/vm/mmap-off
pass tests/vm/mmap-bad-off
pass tests/vm/mmap-kernel
pass tests/vm/lazy-file
pass tests/vm/lazy-anon
pass tests/vm/swap-file
pass tests/vm/swap-anon
pass tests/vm/swap-iter
pass 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
pass tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
pass 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
pass tests/vm/cow/cow-simple
All 141 tests passed.
ec2 ํ๊ฒฝ์์ swap-fork๊ฐ FAILํ์์ง๋ง, WSL ํ๊ฒฝ์์ passํ๋ ๊ฒ์ ํ์ธํจ.