이번 포스팅은 user 가 mmap & munmap 시스템 콜을 호출할 때 상황을 보려고 한다.
프로젝트 2 시스템 콜과 같이 시스템 콜 핸들러에 mmap 과 munmap을 추가하고 do_mmap, do_munmap으로 운영체제가 유저의 요청을 처리한다.
mmap과 munmap은 디스크로 부터 파일 내용을 메모리에 적재할 때 사용하며 파일을 건드리는 부분에서는 lock이 필요하다.
시스템 콜
system call handler{
#ifdef VM
case SYS_MMAP:
f->R.rax = mmap_syscall(f->R.rdi,f->R.rsi,f->R.rdx,f->R.r10,f->R.r8);
break;
case SYS_MUNMAP:
munmap_syscall(f->R.rdi);
break;
#endif
}
void *mmap_syscall(void *addr, size_t length, int writable, int fd, off_t offset){
struct supplemental_page_table spt = thread_current()->spt;
if (!addr || pg_round_down(addr) != addr || is_kernel_vaddr(addr) || is_kernel_vaddr(addr + length))
return NULL;
if (offset != pg_round_down(offset) || offset % PGSIZE != 0)
return NULL;
if (spt_find_page(&thread_current()->spt, addr))
return NULL;
struct file *file = get_file_from_fd(fd);
if ((file >= STDIN && file <= STDERR) || file == NULL)
return NULL;
if (file_length(file) == 0 || (long)length <= 0)
return NULL;
return do_mmap(addr, length, writable, file, offset);
}
void munmap_syscall(void *addr){
do_munmap(addr);
return;
}
void * do_mmap (void *addr, size_t length, int writable, struct file *file, off_t offset) {
lock_acquire(&filesys_lock);
struct file *copied_file = file_reopen(file);
void *start_addr = addr;
size_t read_bytes = (length > file_length(copied_file)) ? file_length(copied_file) : length;
size_t zero_bytes = PGSIZE - read_bytes % PGSIZE;
// int total_page_count = length <= PGSIZE ? 1: length % PGSIZE ? length /PGSIZE + 1 : length /PGSIZE;
ASSERT((read_bytes + zero_bytes) % PGSIZE == 0);
ASSERT(pg_ofs(addr) == 0); // upage가 페이지 정렬되어 있는지 확인
ASSERT(offset % PGSIZE == 0); // ofs가 페이지 정렬되어 있는지 확인
struct lazy_load_arg *lazy_load_arg;
while(read_bytes > 0 || zero_bytes > 0){
size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
size_t page_zero_bytes = PGSIZE - page_read_bytes;
lazy_load_arg = (struct lazy_load_arg *)malloc(sizeof(struct lazy_load_arg));
if (lazy_load_arg == NULL)
goto err;
lazy_load_arg->file = copied_file;
lazy_load_arg->offset = offset;
lazy_load_arg->length = page_read_bytes;
if (!vm_alloc_page_with_initializer(VM_FILE, addr,writable, lazy_load_segment, lazy_load_arg))
goto err;
read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes;
addr += PGSIZE;
offset += page_read_bytes;
}
lock_release(&filesys_lock);
return start_addr;
err:
free(lazy_load_arg);
lock_release(&filesys_lock);
return NULL;
}
load_segment와 같이 파일에 대한 정보들을 uninit page에 저장해두고 #PF에 의해 lazy load된다.
void do_munmap (void *addr) {
struct thread *curr = thread_current();
struct page *page;
lock_acquire(&filesys_lock);
while ((page = spt_find_page(&curr->spt, addr))) {
if (page)
destroy(page);
addr += PGSIZE;
}
lock_release(&filesys_lock);
}
'PintOS' 카테고리의 다른 글
PintOS Project 3 : Virtual Memory 정리 (0) | 2024.10.01 |
---|---|
PintOS Project 3 : Virtual Memory(3) - swap in & swap out LRU (0) | 2024.10.01 |
PintOS Project 3 : Virtual Memory(2) - file load , page fault 다루기 (2) | 2024.10.01 |
PintOS Project 3 : Virtual Memory (1) - supplemetal page table 보조 페이지 테이블 (0) | 2024.10.01 |
PintOS Project 2 : system call (2) (1) | 2024.09.18 |