반응형
목표
이전의 pintos는 fork할 때 부모가 메모리가 할당된 page에 대해서 자식에게 복사할 때 같은 내용의 물리메모리를 자식에게도 할당 해주었다. 이처럼 같은 메모리가 두번 복사되는 것은 메모리 낭비이다.
그렇기 fork시에 자식과 부모가 같은 물리 메모리를 가리키게 하고 해당 페이지에 write 요청이 발생하면 새로운 물리메모리를 할당하여 주도록 수정한다.
💡 fork 시 물리메모리를 모두 복사하지 않고 부모와 같은 물리메모리를 공유하다가 write작업 시 해당 페이지의 물리메모리를 새로 맵핑한다.
COPY시 코드 수정
fork시에 page와 frame은 복사본은 자식에게 주지만 frame에 있는 kva에는 부모와 자식이 같은 곳을 가리고 있다.
bool supplemental_page_table_copy(struct supplemental_page_table *dst,
struct supplemental_page_table *src)
{
...
case VM_ANON:
vm_alloc_page(tmp->operations->type, tmp->va, tmp->writable);
cpy = spt_find_page(dst, tmp->va);
if (cpy == NULL)
{
return false;
}
cpy->copy_writable = tmp->writable;
struct frame *cpy_frame = malloc(sizeof(struct frame));
cpy->frame = cpy_frame;
cpy_frame->page = cpy;
// 자식 frame 구조체를 만들고 물리메모리의 시작 주소 kva를 부모와 같은 곳을 가리키도록 할당한다.
cpy_frame->kva = tmp->frame->kva;
struct thread *t = thread_current();
lock_acquire(&lru_lock);
list_push_back(&lru, &cpy_frame->lru_elem);
lock_release(&lru_lock);
// 자식의 page에 대한 pml4 맵핑 시 writable 0으로 만들어준다.
if (pml4_set_page(t->pml4, cpy->va, cpy_frame->kva, 0) == false)
{
return false;
}
swap_in(cpy, cpy_frame->kva);
writable을 0으로 만드는이유
- 자식이 page에 write 요청을 하면 writable이 0으로 되어 있기에 write protection 오류가 나면서 page fault로 이동하게 되고 새로운 물리메모리 할당을 수행할 수 있다.
vm_try_handle_fault
bool vm_try_handle_fault(struct intr_frame *f, void *addr,
bool user, bool write, bool not_present)
{
...
if (write && !not_present && page->copy_writable && page)
{
// printf("not present is false\\n");
return vm_handle_wp(page);
}
...
}
- page fault 발생 시 write 요청이면서 원래 page가 writable 가능 페이지인지를 확인하고 ㅍvm_handle_wp함수를 호출한다.
vm_handle_wp
static bool
vm_handle_wp(struct page *page)
{
// 공유하고 있는 부모의 kva 저장
void *parent_kva = page->frame->kva;
//새로 물리메모리 할당
page->frame->kva = palloc_get_page(PAL_USER);
//기존 부모의 데이터 복사
memcpy(page->frame->kva, parent_kva, PGSIZE);
pml4_set_page(thread_current()->pml4, page->va, page->frame->kva, page->copy_writable);
return true;
}
- write 요청한 page에 새로운 물리메모리를 할당하고 부모의 메모리 내용을 memcpy로 복사한다.
- pml4_set_page로 가상메모리와 물리메모리를 맵핑하면서 0으로 설정되었던 writeable 을 원상 복귀 시킨다.
문제점
여기까지 구현하고 해결하지 못한 문제점
- 자식과 부모가 같은 물리메모리를 할당하고 있어서 자식이 먼저 죽었을 때 공유하고 있던 물리메모리를 지워버리고 죽는 상황이 생긴다. 그렇기에 부모가 해당 물리 메모리를 읽으려고하면 에러가 발생함
해결
- 프로세스가 죽고 cleanup될 때 pml4_destroy함수가 실행을 하지 않고 SPT_kill까지 진행하는 것으로 해결하였다.
Q. 사실 이렇게 해서 All pass를 하긴 하였으나 정상적인 방법인지 의문이 생긴다. 치팅으로 테스트 케이스에 안걸리는 것이 아닌가하는 생각이 든다.
static void
process_cleanup(void)
{
struct thread *curr = thread_current();
#ifdef VM
supplemental_page_table_kill(&curr->spt);
return; // <- 추가한 부분
#endif
uint64_t *pml4;
pml4 = curr->pml4;
if (pml4 != NULL)
{
curr->pml4 = NULL;
pml4_activate(NULL);
pml4_destroy(pml4);
return;
}
}
pintos 3주차 vm 결과
회고
Swap in / out을 구현하고 나서도 merge 관련 문제점을 해결하지 못 하였다. 3일동안 3명이서 열심히 디버깅을 하였으나 해결하지 못하였고 결국 merge관련 테스트 케이스를 포기하였다.
그리고 잘 되는 코드를 받와서 cow-simple을 완료하였다. 우리팀이 작성한 코드로 merge를 해결하지 못한 것이 많이 아쉽다.
반응형
'지난 글 모음' 카테고리의 다른 글
[sw 정글] pintos 3주차 - part 4: Memory Mapped Files (0) | 2022.06.21 |
---|---|
[sw 정글] pintos 3주차 - part 3: Stack Growth (0) | 2022.06.21 |
[sw 정글] pintos 3주차 - part 2: Anonymous page & Lazy Loading (0) | 2022.06.21 |
[sw 정글] pintos 3주차 - part 1: Memory Management (0) | 2022.06.21 |
[Malloc-Lab] 기본개념과 Implicit 구현하기 (3) | 2022.05.10 |