출근하고 memory mapped files를 공부하고 구현하려 하다가 그냥 에러부터 해결하자고 마음먹고 해결했다.
어이가 없었던 것은 아무것도 안건드렸는데 make check해보니 swap-fork
가 통과해버린것.. 진짜 pintos는 운인가??
그리고 fork-read
를 분석해보니 오류를 찾아낼 수 있었다. process.c의 lazy_load_segment
에서 file을 free해주고 있었다. 다른 곳에서 문제가 발생하지 않은 것이 신기할정도.. 고치고 나니 상기의 사진처럼 출력되었다. 하지만 pass된 case중 하나인 page-merge-par
은 랜덤?으로 가끔 성공할 때가 있는 case라 실제로 pass는 33개이다.
오류 수정 후 mmap 구현을 시작했다. 과정을 설명하자면 정말 구차하게? 구현했다.ㅋㅋㅋㅋ
일단 stack에 file의 길이와 주어진 length를 이용하여 얼마만큼 채워지는지 기억하고, 채워진 위치와 할당한 공간의 차이로 얼마만큼 0을 채워주어야 하는지 고민하면서 여러가지 방식을 도입하다가.. 좋은 코드 제 1원칙! 일단 돌아가야 한다! 를 모토로 변수를 엄청선언하고 일일히 저장하면서 printf도 찍어보고 결국 구현했다.
test case를 통과했을 때의 짜릿함은 잊을 수 없을 것 같다. 하지만 남은 일들이 많았다. file_read
로 bytes를 기억해 memset으로 나머지에 0을 부여하는 아이디어는 좋았으나 알고보니 모든 접근을 va로 하고있었다. 우리는 physical frame에 즉시 할당해주어야 했으므로 spt_find_page
후 vm_claim_page
로 frame을 만들었다. 이를 통하여 kva로 접근하여 physical frame에 할당을 해줄 수 있었다.
void *
do_mmap (void *addr, size_t length, int writable, struct file *file, off_t offset) {
if((uint64_t)addr % PGSIZE)
return NULL;
file_seek(file, offset);
int pg_cnt = 0;
off_t read_bytes = 0;
void *va = NULL;
struct page *page;
while(length > pg_cnt * PGSIZE){
va = (uint64_t)addr + pg_cnt * PGSIZE;
if(spt_find_page(&thread_current()->spt, va) == NULL){
if(vm_alloc_page(VM_FILE, va, writable) == NULL)
return NULL;
}
else
return NULL;
page = spt_find_page(&thread_current()->spt, va);
vm_claim_page(page->va);
pg_cnt++;
read_bytes = file_read(file, page->frame->kva, PGSIZE);
if(read_bytes < PGSIZE)
break;
}
memset((uint64_t)page->frame->kva + read_bytes, 0, PGSIZE - read_bytes);
file_seek(file, offset);
return page->frame->kva;
}
페어 프로그래밍 너무 재밌다. 동시에 내 부족함도 깨닫는다. 혼자선 못했을 것 같다...
munmap도 구현하지 않았고 mmap도 수정할 부분이 남은 것 같다. 자꾸 swap-fork
같은게 말썽이라 슬프다