[Pintos] Virtual Memory 구현하기 Part2: 파일과 페이지 공유 및 교체하기 (Memory Mapped Files, Swap In/Out, Copy On Write)

2025. 6. 6. 22:17·크래프톤 정글/Code 정글(C언어)

Virtual Memory 구현하기 Part2: 파일과 페이지 공유 및 교체하기 (Memory Mapped Files, Swap In/Out, Copy On Write)

이번 글에서는 Virtual Memory의 나머지 부분들인 Memory Mapped Files, Swap In/Out, Copy On Write를 마저 구현해 봅니다.

 

※ 주의: 제 컴퓨터 기준에서는, All Pass가 뜨는 것을 확인했으나, 다른 조원들의 컴퓨터에서 page-merge.* 테스트가 간헐적으로 실패하는 것을 확인했습니다. 따라서 그대로 적용하기보다는, 참고만 하시는 것을 추천드립니다.

 

 

사전준비: 전역 Lock 외부 공유 및 활용하기

merge 관련 테스트 통과를 위해서는 process.c에 있는 load 함수의 filesys_open 전후로 lock을 걸어줘야 하는데요. 이를 위해 기존 syscall.h에 있었던 전역 lock 구조체인 filesys_lock을 활용합니다.

(1) filesys_lock 외부 선언하기 (syscall.h)

extern struct lock filesys_lock;	// 파일 시스템 동기화용 전역 락

(2) syscall 모듈 참조 추가 (process.c)

#include "userprog/syscall.h"	// filesys_lock 지원

(3) load 함수의 filesys_open 전후로 lock 처리 추가하기 (process.c)

// filesys_open 이전 코드 생략..

lock_acquire(&filesys_lock);	// lock 걸기
file = filesys_open (file_name);
// 이후 코드 생략..

done:
	lock_release(&filesys_lock);	// lock 풀기
    return success;

 

 

Memory Mapped Files

(1) file_backed_initializer 구현하기 (file.c)

file_backed_initializer 구현하기

/* 파일 기반 페이지 초기화: lazy load 정보 → file_page에 복사 */
bool
file_backed_initializer(struct page *page, enum vm_type type, void *kva) {
	// 해당 페이지의 동작 테이블을 file_ops로 설정
	page->operations = &file_ops;

	// page 내부 file_page 구조체 설정
	struct file_page *file_page = &page->file;

    // lazy_load_segment에서 전달된 보조 데이터 추출
    struct lazy_load_arg *aux = (struct lazy_load_arg *)page->uninit.aux;

    // 파일 매핑 정보 복사
    file_page->file = aux->file;
    file_page->ofs = aux->ofs;
    file_page->read_bytes = aux->read_bytes;
    file_page->zero_bytes = aux->zero_bytes;

    return true;
}

기존 file_page 구조체에 필드 추가하기 (file.h)

이전에 만든 lazy_load_arg 구조체의 필드들을 그대로 가져와서 사용합니다.

struct file_page {
	struct file *file;
	off_t ofs;
	uint32_t read_bytes;
	uint32_t zero_bytes;
};

 

(2) file_backed_destroy 구현하기 (file.c)

/* 파일 매핑된 페이지 제거 시, 변경 내용 기록 및 자원 해제 */
static void
file_backed_destroy(struct page *page) {
	struct file_page *file_page UNUSED = &page->file;

    // 페이지가 dirty 상태이면 파일에 변경 내용 반영
    if (pml4_is_dirty(thread_current()->pml4, page->va)) {
        lock_acquire(&filesys_lock);
        file_write_at(file_page->file, page->va, file_page->read_bytes, file_page->ofs);
        lock_release(&filesys_lock);

        // dirty 비트 초기화
        pml4_set_dirty(thread_current()->pml4, page->va, false);
    }

    // frame이 존재하면 frame 테이블에서 제거 및 정리
    if (page->frame) {
        list_remove(&page->frame->frame_elem);
        page->frame->page = NULL;
        page->frame = NULL;
        free(page->frame);
    }

    // 페이지 테이블에서 매핑 제거
    pml4_clear_page(thread_current()->pml4, page->va);
}

 

(3) file_backed_swap_in 구현하기 (file.c)

/* 파일 기반 페이지를 디스크에서 메모리로 swap in */
static bool
file_backed_swap_in(struct page *page, void *kva) {
	struct file_page *file_page UNUSED = &page->file;

    // 파일에서 데이터 읽어와 물리 메모리(kva)에 적재
    lock_acquire(&filesys_lock);
	int read = file_read_at(file_page->file, page->frame->kva,
    						file_page->read_bytes, file_page->ofs);
    lock_release(&filesys_lock);

    // 남은 영역은 0으로 초기화
	memset(page->frame->kva + read, 0, PGSIZE - read);

	return true;
}

 

(4) file_backed_swap_out 구현하기 (file.c)

/* 파일 기반 페이지를 메모리에서 내보내며, 변경된 내용은 파일에 반영 */
static bool
file_backed_swap_out(struct page *page) {
	struct file_page *file_page UNUSED = &page->file;
	struct frame *frame = page->frame;

	// 페이지가 dirty 상태면 파일에 변경 내용 기록
	if (pml4_is_dirty(thread_current()->pml4, page->va)) {
        lock_acquire(&filesys_lock);
		file_write_at(file_page->file, page->frame->kva, file_page->read_bytes, file_page->ofs);
        lock_release(&filesys_lock);
		pml4_set_dirty(thread_current()->pml4, page->va, false); // dirty 비트 초기화
	}

	// frame 연결 해제
	page->frame->page = NULL;
	page->frame = NULL;

	// 페이지 테이블에서 매핑 제거
	pml4_clear_page(thread_current()->pml4, page->va);

	return true;
}

 

(5) syscall_handler에 SYS_MMAP 케이스 추가하기 (syscall.c)

case SYS_MMAP:
    f->R.rax = sys_mmap((void *)arg1, (size_t)arg2, (int)arg3, (int)arg4, (off_t)arg5);
    break;

 

(6) sys_mmap 구현하기 (syscall.c)

sys_mmap 함수 선언 추가하기

/* syscall.c 위쪽에 함수 선언 추가 */
void *sys_mmap(void *addr, size_t length, int writable, int fd, off_t offset);

sys_mmap용 모듈 참조 추가하기

#include "vm/file.h"	// do_mmap, do_munmap 지원

sys_mmap 구현하기

/* mmap 시스템 콜: 유저 주소 addr에 파일을 매핑 */
void *
sys_mmap(void *addr, size_t length, int writable, int fd, off_t offset) {
    // 유효하지 않은 주소 또는 페이지 정렬이 되지 않은 경우이거나,
    // 커널 영역 접근 또는 매핑 범위가 커널을 침범한 경우
    if (!addr || pg_round_down(addr) != addr ||
    	is_kernel_vaddr(addr) || is_kernel_vaddr(addr + length))
        return NULL;

    // offset이 페이지 정렬이 되지 않은 경우
    if (offset != pg_round_down(offset) || offset % PGSIZE != 0)
        return NULL;

    // 이미 SPT에 등록된 주소인 경우 (중복 매핑 방지)
    if (spt_find_page(&thread_current()->spt, addr))
        return NULL;

	// stdin(0), stdout(1), stderr(2)는 mmap 대상이 아님
	if (fd < 3)
        return NULL;

    // 파일 존재 여부 및 길이 검증
    struct file *file = process_get_file(fd);
    if (file == NULL || file_length(file) == 0 || (long)length <= 0)
        return NULL;

    // 실제 매핑 처리 함수 호출
    return do_mmap(addr, length, writable, file, offset);
}

 

(7) do_mmap 구현하기 (file.c)

do_mmap용 모듈 참조 추가하기

#include "userprog/process.h"	// lazy_load_segment 지원
#include "threads/vaddr.h"		// PGSIZE 지원
#include "userprog/syscall.h"	// filesys_lock 지원

do_mmap 구현하기

/* 파일 내용을 addr부터 시작하는 유저 주소에 lazy load 방식으로 매핑 */
void *
do_mmap(void *addr, size_t length, int writable,
        struct file *file, off_t offset) {

	lock_acquire(&filesys_lock);  // 파일 동시 접근 보호

    // 원본 파일을 reopen (기존 파일이 닫힐 수 있으므로 별도로 핸들링)
    struct file *mfile = file_reopen(file);
    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 lazy_load_arg *aux;
    while (read_bytes > 0 || zero_bytes > 0) {
        // 현재 페이지에 읽을 바이트 및 0으로 채울 바이트 계산
        size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
        size_t page_zero_bytes = PGSIZE - page_read_bytes;

        // lazy load용 인자 구조체 동적 할당
        aux = (struct lazy_load_arg *)malloc(sizeof(struct lazy_load_arg));
        if (!aux)
            goto err;

        // 인자 값 설정
        aux->file = mfile;
        aux->ofs = offset;
        aux->read_bytes = page_read_bytes;
        aux->zero_bytes = page_zero_bytes;

        // 초기화 정보 등록 (lazy_load_segment 사용)
        if (!vm_alloc_page_with_initializer(VM_FILE, addr, writable, lazy_load_segment, aux)) {
            goto err;
        }

        // 다음 페이지 처리 준비
        read_bytes -= page_read_bytes;
        zero_bytes -= page_zero_bytes;
        addr += PGSIZE;
        offset += page_read_bytes;
    }

	lock_release(&filesys_lock);
    return ori_addr;  // 성공 시 매핑 시작 주소 반환

err:
    free(aux);               // 실패 시 자원 해제
    lock_release(&filesys_lock);
    return NULL;
}

 

(8) lazy_load_segment 외부 공유하기 (process.h, process.c)

기존 process.c의 lazy_load_segment는 static으로 해당 파일 안에서만 사용했지만, file.c의 do_mmap이 lazy_load_segment를 사용함에 따라, 기존에 있던 static을 제거하고 process.h에 함수 선언을 추가해줍니다.

/* process.c에서 lazy_load_segment의 static을 제거
	이후 process.h에 아래 함수 선언 추가 */
bool lazy_load_segment(struct page *page, void *aux);

 

(9) syscall_handler에 SYS_MUNMAP 케이스 추가하기 (syscall.c)

case SYS_MUNMAP:
    sys_munmap((void *)arg1);
    break;

 

(10) sys_munmap 구현하기 (syscall.c)

sys_munmap 함수 선언 추가하기

/* syscall.c 위쪽에 함수 선언 추가 */
void sys_munmap(void *addr);

sys_munmap 구현하기

void sys_munmap(void *addr) {
	// 실제 언매핑 함수 호출
    do_munmap(addr);
}

 

(11) do_munmap 구현하기 (file.c)

/* addr부터 시작하는 매핑 영역을 해제 (mmap 해제) */
void
do_munmap(void *addr) {
    struct thread *curr = thread_current();
    struct page *page;

    // addr부터 연속된 매핑된 페이지들을 해제
    while ((page = spt_find_page(&curr->spt, addr))) {
        if (page)
            destroy(page);  // 페이지 자원 정리 및 해제

        addr += PGSIZE;     // 다음 페이지로 이동
    }
}

 

(12) supplemental_page_table_copy 수정하기

페이지 타입이 VM_FILE일 때의 조건문을 추가해줍니다.

/* src SPT의 모든 페이지를 dst SPT로 복사 (fork 시 사용) */
bool
supplemental_page_table_copy(struct supplemental_page_table *dst UNUSED,
		struct supplemental_page_table *src UNUSED) {
	
	struct hash_iterator i;
	hash_first(&i, &src->spt_hash);

	while (hash_next(&i)) {
		struct page *src_page = hash_entry(hash_cur(&i), struct page, hash_elem);
		enum vm_type type = src_page->operations->type;
		void *upage = src_page->va;
        bool writable = src_page->writable;

		if (type == VM_UNINIT) {
			// lazy load 페이지는 초기화 정보만 복사
			vm_alloc_page_with_initializer(
				src_page->uninit.type,
				src_page->va,
				src_page->writable,
				src_page->uninit.init,
				src_page->uninit.aux);
		}
		else if (type == VM_FILE) {
			// file-backed 페이지는 복사된 aux 정보로 등록
            struct lazy_load_arg *aux = malloc(sizeof(struct lazy_load_arg));
            aux->file = src_page->file.file;
            aux->ofs = src_page->file.ofs;
            aux->read_bytes = src_page->file.read_bytes;

			// dst SPT에 페이지 등록
            if (!vm_alloc_page_with_initializer(type, upage, writable, NULL, aux))
                return false;

			// 초기화 및 매핑 설정 (공유 프레임 사용)
            struct page *dst_page = spt_find_page(dst, upage);
            file_backed_initializer(dst_page, type, NULL);
            dst_page->frame = src_page->frame;
            pml4_set_page(thread_current()->pml4, dst_page->va, src_page->frame->kva, src_page->writable);
        }
		else {
            // 이미 초기화된 페이지는 새로 할당하고 데이터 복사
            if (vm_alloc_page(type, upage, writable) &&
                vm_claim_page(upage)) {
                struct page *dst_page = spt_find_page(dst, upage);
                memcpy(dst_page->frame->kva, src_page->frame->kva, PGSIZE);
            } else {
                return false;
            }
        }
	}
	return true;
}

 

Swap In/Out

(1) Swap Table 인터페이스 추가 (anon.c)

Swap Table용 모듈 참조 추가하기

#include <bitmap.h>			// 비트맵 자료구조 지원
#include "threads/vaddr.h"	// PGSIZE 지원
#include "threads/mmu.h"	// pml4 관련 함수 지원

Swap Table용 매크로 추가하기

#define SECTOR_PER_PAGE (PGSIZE / DISK_SECTOR_SIZE)	// 한 페이지당 디스크 섹터 수

Swap Table용 전역 변수 추가하기

static struct bitmap *swap_table;	// 스왑 슬롯의 사용 여부를 추적하는 비트맵
static struct lock swap_lock;		// swap_table 접근 동기화를 위한 전역 락

기존 anon_page 구조체에 page_no 추가하기 (anon.h)

struct anon_page {
    size_t page_no;  // 디스크 페이지 번호
};

 

(2) anon_init 구현하기 (anon.c)

스왑 디스크 영역 할당 및 선언한 전역 변수들을 초기화합니다.

/* 익명 페이지용 스왑 공간 초기화 */
void
vm_anon_init(void) {
	// 스왑 디스크 영역 할당 (디스크 1번, 파티션 1)
	swap_disk = disk_get(1, 1);

	// 스왑 공간 전체 크기만큼 비트맵 생성 (페이지 단위 관리)
	swap_table = bitmap_create(disk_size(swap_disk) / SECTOR_PER_PAGE);

	// 스왑 공간 접근 동기화를 위한 락 초기화
	lock_init(&swap_lock);
}

 

(3) anon_initializer 구현하기 (anon.c)

/* 익명 페이지 초기화: 초기 상태 설정 및 스왑 미할당 표시 */
bool
anon_initializer(struct page *page, enum vm_type type, void *kva) {
	struct uninit_page *uninit = &page->uninit;

	// uninit 영역을 깨끗한 상태로 초기화
	memset(uninit, 0, sizeof(struct uninit_page));

	// 익명 페이지 전용 operations 등록
	page->operations = &anon_ops;

	// 스왑 공간 미할당 상태로 설정
	struct anon_page *anon_page = &page->anon;
	anon_page->page_no = BITMAP_ERROR;

	return true;
}

 

(4) anon_swap_in 구현하기 (anon.c)

/* 익명 페이지를 스왑 디스크에서 메모리로 로드 (swap in) */
static bool
anon_swap_in(struct page *page, void *kva) {
	struct anon_page *anon_page = &page->anon;

	lock_acquire(&swap_lock);  // 스왑 영역 동기화

	// 스왑 슬롯이 유효하지 않으면 실패
	if (anon_page->page_no == BITMAP_ERROR){
		lock_release(&swap_lock);	
		return false;
	}

	// 해당 스왑 슬롯이 실제로 사용 중인지 확인
	if (!bitmap_test(swap_table, anon_page->page_no)){
		lock_release(&swap_lock);	
		return false;
	}

	// 디스크에서 한 페이지(8 섹터) 단위로 읽어오기
	for (size_t i = 0; i < SECTOR_PER_PAGE; i++)
		disk_read(swap_disk, (anon_page->page_no * SECTOR_PER_PAGE) + i,
        		kva + (i * DISK_SECTOR_SIZE));

	// 해당 슬롯을 free 상태로 표시
	bitmap_set(swap_table, anon_page->page_no, false);

	lock_release(&swap_lock);

	// 페이지가 더 이상 스왑에 존재하지 않음을 표시
	anon_page->page_no = BITMAP_ERROR;

	return true;
}

 

(5) anon_swap_out 구현하기 (anon.c)

/* 익명 페이지를 스왑 디스크로 내보냄 (swap out) */
static bool
anon_swap_out(struct page *page) {
	struct anon_page *anon_page = &page->anon;

	lock_acquire(&swap_lock);  // 스왑 공간 동기화

	// 빈 스왑 슬롯 검색 및 사용 표시 (flip)
	size_t page_no = bitmap_scan_and_flip(swap_table, 0, 1, false);

	// 스왑 공간이 부족한 경우 → 실패
	if (page_no == BITMAP_ERROR){
		lock_release(&swap_lock);
		return false;
	}

	// 페이지 내용을 8개의 섹터 단위로 디스크에 기록
	for (size_t i = 0; i < SECTOR_PER_PAGE; i++)
		disk_write(swap_disk, (page_no * SECTOR_PER_PAGE) + i,
        		page->va + (i * DISK_SECTOR_SIZE));

	// 스왑 슬롯 번호 저장
	anon_page->page_no = page_no;

	// frame 연결 해제 및 페이지 테이블에서 매핑 제거
	page->frame->page = NULL;
	page->frame = NULL;
	pml4_clear_page(thread_current()->pml4, page->va);

	lock_release(&swap_lock);
}

 

(6) anon_destroy 구현하기 (anon.c)

/* 익명 페이지 제거 시, 스왑 슬롯과 frame 자원을 정리 */
static void
anon_destroy(struct page *page) {
	struct anon_page *anon_page = &page->anon;

    // 스왑 슬롯이 할당되어 있었다면 비트맵에서 해제
    if (anon_page->page_no != BITMAP_ERROR)
        bitmap_reset(swap_table, anon_page->page_no);

    // frame이 존재하면 frame 리스트에서 제거하고 해제
    if (page->frame) {
		lock_acquire(&swap_lock);
        list_remove(&page->frame->frame_elem);    // frame 테이블에서 제거
		lock_release(&swap_lock);

        page->frame->page = NULL;
        free(page->frame);                        // frame 구조체 메모리 해제
        page->frame = NULL;
    }
}

 

(7) vm_get_victim 구현하기 (vm.c)

/* 교체할 victim frame을 선택 (2차 기회 방식) */
static struct frame *
vm_get_victim(void) {
	struct frame *victim = NULL;

	lock_acquire(&frame_lock);  // frame 테이블 접근 동기화

	// frame_table 순회하며 교체 대상 탐색
	for (next = list_begin(&frame_table); next != list_end(&frame_table); next = list_next(next)) {
		victim = list_entry(next, struct frame, frame_elem);

		// 최근 접근된 페이지라면 accessed 비트만 초기화 (생존 기회 부여)
		if (pml4_is_accessed(thread_current()->pml4, victim->page->va)) {
			pml4_set_accessed(thread_current()->pml4, victim->page->va, false);
		} else {
			// 접근되지 않은 페이지라면 victim으로 선정
			lock_release(&frame_lock);
			return victim;
		}
	}

	// 순회 끝까지 갔을 경우 마지막으로 본 frame 반환 (fallback)
	lock_release(&frame_lock);
	return victim;
}

전역 탐색 포인터 next 선언하기

/* vm.c 위쪽에 추가 */
struct list_elem *next = NULL;	// victim 선정용 전역 포인터

 

(8) vm_evict_frame 구현하기 (vm.c)

/* victim frame을 선택해 페이지를 스왑 아웃한 후 반환 */
static struct frame *
vm_evict_frame(void) {
	struct frame *victim = vm_get_victim();  // 교체할 frame 선택

	// frame에 매핑된 페이지가 있으면 스왑 아웃
	if (victim->page)
		swap_out(victim->page);

	return victim;  // 빈 frame 반환
}

 

 

Copy On Write

(1) supplemental_page_table_copy 수정하기 (vm.c)

else {
    // 초기화된 페이지인 경우, dst SPT에 페이지 메타데이터만 등록
    if (!vm_alloc_page(type, upage, writable))
        return false;

    // kva는 새로 생성하지 않고, 기존 frame의 kva를 매핑만 수행
    if (!vm_copy_claim_page(dst, upage, src_page->frame->kva, writable))
        return false;
}

 

(2) vm_copy_claim_page 구현하기 (vm.c)

기존 kva를 재사용하고, 새로운 frame 구조체만 할당합니다. 다시말해 물리 메모리 복사 없이 가상 주소만 kva로 매핑합니다.

vm_copy_claim_page 함수 선언하기

/* vm.c 위쪽에 함수 선언 추가 */
static bool vm_copy_claim_page(struct supplemental_page_table *dst, void *va, void *kva, bool writable);

vm_copy_claim_page 함수 구현하기

/* 기존 kva를 사용하여 dst SPT의 va에 매핑만 수행 (frame 할당은 새로) */
static bool 
vm_copy_claim_page(struct supplemental_page_table *dst, void *va, void *kva, bool writable) {
    // dst SPT에서 va에 해당하는 page 찾기
    struct page *page = spt_find_page(dst, va);
    if (page == NULL)
        return false;

    // 새로운 frame 구조체 할당 (물리 메모리는 재사용)
    struct frame *frame = (struct frame *)malloc(sizeof(struct frame));
    if (!frame)
        return false;

    // page ↔ frame 연결 설정
    page->accessible = writable;   // 접근 권한 저장
    frame->page = page;
    page->frame = frame;
    frame->kva = kva;              // 기존 kva를 그대로 사용

    // 사용자 페이지 테이블에 매핑
    if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, false)) {
        free(frame);
        return false;
    }

    // frame_table에 등록
    list_push_back(&frame_table, &frame->frame_elem); 

    // swap-in 동작으로 실제 페이지 내용을 불러옴 (실제 사용 시 보장)
    return swap_in(page, frame->kva);
}

기존 page 구조체에 accessible 필드 추가 (vm.h)

/* writable 필드 아래에 추가 */
bool accessible;	// 자식 프로세스 페이지 쓰기 가능 여부

 

(3) vm_try_handle_fault 수정 (vm.c)

존재하는 페이지에 대한 쓰기 접근을 자식 프로세스의 COW 상황으로 보고, write-protect 핸들러로 처리하도록 변경합니다.

/* 존재하는 페이지에 대해 쓰기 접근 시 write-protect 핸들러 호출 */
if (!not_present && write)
	return vm_handle_wp(page);

 

(4) vm_handle_wp 구현하기 (vm.c)

COW 상황에서 호출되며, 기존 물리 메모리를 복제하여 새로운 메모리를 할당하고 가상 주소는 새 kva로 재매핑합니다. 마지막으로 Copy-On-Write의 핵심 처리로써, 쓰기 가능한 전용 복사본을 제공해 공유를 끊습니다.

/* 쓰기 보호(Copy-On-Write) 발생 시, 새 페이지를 할당하고 복사 */
static bool
vm_handle_wp(struct page *page UNUSED) {
    // 쓰기 불가능한 페이지라면 처리 불가
    if (!page->accessible)
        return false;

    // 기존 물리 메모리 주소 보관
    void *kva = page->frame->kva;

    // 새로운 사용자용 물리 페이지 할당
    page->frame->kva = palloc_get_page(PAL_USER | PAL_ZERO);

    // 할당 실패 시 스왑 아웃 후 재시도
    if (page->frame->kva == NULL)
        page->frame = vm_evict_frame();  

    // 기존 내용 복사 (쓰기 시점 복제)
    memcpy(page->frame->kva, kva, PGSIZE);

    // 페이지 테이블에 새로운 매핑 등록
    if (!pml4_set_page(thread_current()->pml4, page->va, page->frame->kva, page->accessible))
        return false;

    return true;
}

 

(5) anon_destroy 수정하기 (anon.c)

// anon_destroy의 맨 밑에 추가
pml4_clear_page(thread_current()->pml4, page->va);

 

 

기대 테스트 결과

저작자표시 비영리 변경금지 (새창열림)

'크래프톤 정글 > Code 정글(C언어)' 카테고리의 다른 글

[Pintos] tests 디렉터리의 모든 txt파일 CRLF 없애기  (0) 2025.06.09
[Pintos] Virtual Memory 구현하기 Part1: Lazy Load 방식으로 프로그램 실행하기 (Memory Management, Anonymous Page, Stack Growth)  (1) 2025.06.06
[Pintos] OSTEP 기반 Virtual Memory 배경지식 정리: 왜 VM이 필요한가  (0) 2025.05.31
[Pintos] Virtual Memory Layout 정리  (0) 2025.05.30
[Pintos] Virtual Memory 전체적인 큰 그림 그리기  (1) 2025.05.30
'크래프톤 정글/Code 정글(C언어)' 카테고리의 다른 글
  • [Pintos] tests 디렉터리의 모든 txt파일 CRLF 없애기
  • [Pintos] Virtual Memory 구현하기 Part1: Lazy Load 방식으로 프로그램 실행하기 (Memory Management, Anonymous Page, Stack Growth)
  • [Pintos] OSTEP 기반 Virtual Memory 배경지식 정리: 왜 VM이 필요한가
  • [Pintos] Virtual Memory Layout 정리
그냥사람_
그냥사람_
IT 관련 포스팅을 합니다. 크래프톤 정글 8기 정경호
  • 그냥사람_
    그냥코딩
    그냥사람_
  • 전체
    오늘
    어제
    • 글 전체보기 N
      • 크래프톤 정글 N
        • 로드 투 정글(입학시험)
        • CS기초(키워드, 개념정리)
        • 컴퓨터구조(CSAPP)
        • Code 정글(C언어)
        • Equipped in 정글(나만무) N
        • 마이 정글(WIL, 에세이)
      • 자료구조&알고리즘
        • 자료구조
        • 알고리즘
      • 일상
  • 블로그 메뉴

    • 홈
  • 링크

    • Github
  • hELLO· Designed By정상우.v4.10.3
그냥사람_
[Pintos] Virtual Memory 구현하기 Part2: 파일과 페이지 공유 및 교체하기 (Memory Mapped Files, Swap In/Out, Copy On Write)
상단으로

티스토리툴바