미소를뿌리는감자의 코딩

[Pintos_project3 (15)] do_mmap 본문

정글 일지

[Pintos_project3 (15)] do_mmap

미뿌감 2024. 12. 3. 15:12
728x90

1. 개요

do_mmap의 경우엔, file_backed 페이지에 대해서 PM와 mapping을 시켜주는 함수이다.

2. 본문

mmap함수의 경우엔, do_mmap을 하기 전에 여러 인자들에 대해서 유효성 검사를 하는 것이 주된 목표라고 할 수 있다.

주석 처리를 통해 각각의 코드의 의미를 적어보았다.

// userprog/syscall.c

/** Project 3: Memory Mapped Files - Memory Mapping */
void *mmap(void *addr, size_t length, int writable, int fd, off_t offset) { 
    /* addr = 매핑을 시작할 가상 메모리 주소
     * offset = 파일의 매핑 시작 위치
     */
    if (!addr || pg_round_down(addr) != addr || is_kernel_vaddr(addr) || is_kernel_vaddr(addr + length))
        return NULL;
        /* 각각의 조건에 대해서 확인해보자. 
         * pg_round_down(addr) != addr ; 메모리 매핑 주소가 페이지 경계에 정렬되어 있지 않을 때
         * is_kernel_vaddr(addr) ; 커널 전용 주소가 사용되는 지 확인. 매핑 가상 주소가 커널 전용 주소이면 안됨. 
         * is_kernel_vaddr(addr + length) ; 범위 끝이 커널 주소인지 확인. 즉, 시작과 끝이 유저 전용 주소인지 확인.*/


    if (offset != pg_round_down(offset) || offset % PGSIZE != 0) // offset 또한 페이지 경계에 정렬되어 있어야 함.
        return NULL;


    if (spt_find_page(&thread_current()->spt, addr)) // 이미 현재 addr가 page_table에 매핑이 되어 있다면 실패. 중복되지 않아야 함.
        return NULL;

    struct file *file = process_get_file(fd); // file descriptor로 file 가져오기. 

    if ((file >= STDIN && file <= STDERR) || file == NULL) // 파일이 표준 입력/출력/오류 라면 안되므로 이를 확인, fd가 유효한지 확인.
        return NULL;

    if (file_length(file) == 0 || (long)length <= 0)  // 매핑할 파일의 크기 0인 경우 실패. 매핑할 길이가 0 이하인 경우도 실패.
        return NULL;

    return do_mmap(addr, length, writable, file, offset);
}

 

mmap이 매핑 가능 조건을 확인하는 함수였다면, do_mmap은 실제 매핑을 진행하는 함수라고 할 수 있다.

이 또한 주석 처리를 통해 코드 의미를 적어두었다.

/* Do the mmap / mmap이 매핑 가능 조건을 확인하는 함수였다면, do_mmap은 실제 매핑을 진행하는 함수.*/
void *do_mmap(void *addr, size_t length, int writable, struct file *file, off_t offset) {
    lock_acquire(&filesys_lock); // 파일 시스템에 동시 접근하지 않도록 잠금.
    struct file *mfile = file_reopen(file); //reopen을 통해 파일 핸들을 복제해서 독립적으로 파일을 사용할 수 있도록 설정.
    void *ori_addr = addr; // 매핑이 성공했을 때 반환할 원래 주소.
    size_t read_bytes = (length > file_length(mfile)) ? file_length(mfile) : length;
    size_t zero_bytes = PGSIZE - read_bytes % PGSIZE;

    ASSERT((read_bytes + zero_bytes) % PGSIZE == 0); // 페이지 단위인지 확인.
    ASSERT(pg_ofs(addr) == 0); // 시작 주소가 페이지 경계인지 확인.
    ASSERT(offset % PGSIZE == 0);

    struct aux *aux;
    while (read_bytes > 0 || zero_bytes > 0) {
		// 페이지 단위로 page_read_bytes와 page_zero_bytes를 사용.
        size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
        size_t page_zero_bytes = PGSIZE - page_read_bytes;

        aux = (struct aux *)malloc(sizeof(struct aux)); // aux 동적 할당.
        if (!aux)
            goto err;

        aux->file = mfile; // file 정보
        aux->offset = offset; // offset 정보
        aux->page_read_bytes = page_read_bytes; // 바이트 정보

        if (!vm_alloc_page_with_initializer(VM_FILE, addr, writable, lazy_load_segment, aux)) { // vm_alloc_page_with_initializer로 페이지 할당.
            goto err;
        }

        read_bytes -= page_read_bytes; // 처리한 바이트 수를 전체 바이트 수에서 빼주기.
        zero_bytes -= page_zero_bytes;
        addr += PGSIZE; // 다음에 읽을 addr를 찾기 위해 PGSIZE를 더해줌.
        offset += page_read_bytes;
    }
    lock_release(&filesys_lock); // acquire했던 lock 놔주기

    return ori_addr; // 할당 성공 시, 주소 반환

err:
    free(aux);
    lock_release(&filesys_lock);
    return NULL; // 실패 시, NULL 반환.
}

 

3. 결과

 

728x90