Always Be Wise

Project_3 : Virtual Memory - Memory Mapped Files(2) 본문

카이스트 정글 - 프로젝트/Pintos

Project_3 : Virtual Memory - Memory Mapped Files(2)

bewisesh91 2022. 1. 24. 15:37
728x90

Memory Mapped File은 anonymouse page와 달리 file-backed mapping이다.

따라서, 페이지 폴트가 발생하면 물리 프레임이 즉시 할당되고 파일의 데이터가 물리 프레임에 복사된다.

우선, mmap( )부터 구현해보도록 하자. mmap( )은메모리를 페이지 단위로 할당받을 수 있는 시스템 콜이다.

인자로 받은 파일 fd의 offset에서 length만큼 내용을 읽어와 프로세스의 가상 주소 공간 addr에 매핑한다. 

전체 파일은 addr에서 시작하는 연속된 가상 페이지로 매핑되며, 이는 do_mmap( ) 함수를 통해 이루어진다.

/* userprog/syscall.c */

/*--------------- PROJECT3: Virtual Memory ----------------*/
void *mmap (void *addr, size_t length, int writable, int fd, off_t offset) {
	struct file *file = find_file_by_fd(fd);

	if (file == NULL)
		return NULL;
	
	/* 파일의 시작점도 페이지 정렬 */
	if (offset % PGSIZE != 0) 
        	return NULL;
    	

	/*  It must fail if addr is not page-aligned */
	if (pg_round_down(addr) != addr || is_kernel_vaddr(addr))
		return NULL;

	/*  if the range of pages mapped overlaps any existing set of mapped pages */
	if (spt_find_page(&thread_current()->spt, addr))
		return NULL;

	/* addr가 NULL(0), 파일의 길이가 0*/
	if (addr == NULL || (long long)length == 0)
		return NULL;
	
	/* file descriptors representing console input and output are not mappable */
	if (fd == 0 || fd == 1)
		exit(-1);
	
	return do_mmap(addr, length, writable, file, offset);
}
/*---------------------------------------------------------*/


/* vm/file.c */

/*--------------- PROJECT3: Virtual Memory ----------------*/
void *do_mmap (void *addr, size_t length, int writable, struct file *file, off_t offset) {
	struct file *mfile = file_reopen(file);

    void * ori_addr = addr;
    size_t read_bytes = length > file_length(file) ? file_length(file) : length;
    size_t zero_bytes = PGSIZE - read_bytes % PGSIZE;

	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;

                struct container *container = (struct container*)malloc(sizeof(struct container));
                container->file = mfile;
                container->offset = offset;
                container->page_read_bytes = page_read_bytes;

		if (!vm_alloc_page_with_initializer (VM_FILE, addr, writable, lazy_load_segment, container)) {
			return NULL;
        }
		read_bytes -= page_read_bytes;
		zero_bytes -= page_zero_bytes;
		addr       += PGSIZE;
		offset     += page_read_bytes;
	}
	return ori_addr;
}
/*---------------------------------------------------------*/

munmap( )의 경우, 인자로 받은 addr에 대한 메모리 매핑을 해제하는 시스템 콜이다.

munmap( )은 내부에서 do_munmap( ) 함수를 호출한다.

해당 함수는 addr에 해당 하는 페이지에 변경 사항이 있는지 확인하고 변경이 있을 시, 이를 파일에 옮겨 적는 함수이다.

/* userprog/syscall.c */

/*--------------- PROJECT3: Virtual Memory ----------------*/
void munmap (void *addr) {
    do_munmap(addr);
}
/*---------------------------------------------------------*/


/* vm/file.c */

void do_munmap (void *addr) {   
	while (true) {
        struct page* page = spt_find_page(&thread_current()->spt, addr);
        
        if (page == NULL)
            break;

        struct container * aux = (struct container *) page->uninit.aux;
        
        
        if(pml4_is_dirty(thread_current()->pml4, page->va)) {
            file_write_at(aux->file, addr, aux->page_read_bytes, aux->offset);
            pml4_set_dirty (thread_current()->pml4, page->va, 0);
        }

        pml4_clear_page(thread_current()->pml4, page->va);
        addr += PGSIZE;
    }
}

 

 

 

 

Comments