정글 일지

[Pintos_project3 (6)] load_segment & lazy_load_segment

미뿌감 2024. 11. 30. 16:04
728x90

1. 개요

처음 파일에 대한 접근이 들어오면 load_segment가 불리게 된다.

load_segment에서 파일의 byte 가 저장될 페이지를 할당한다. 추가적으로, aux를 이용해서 offset과 해당 페이지에서 읽을 byte 에 대한 정보를 포함해서 할당한다.

이를 이전에 구현한 vm_alloc_page_with_initializer를 이용해서 UNINIT 페이지를 할당하게 된다.

 

이후, 해당 virtual memory에 대한 page fault가 들어오게 되면, lazy_load_segment가 호출되게 된다.

이전에 저장해두었던 aux에서 읽어야 할 바이트 크기와 offset에 대한 정보를 가지고 온다.

 

file_seek로 파일 시작에서 offset만큼의 위치에서 파일을 읽기 시작한다. 

page->frame->kva로, 해당 가상 주소와 mapping되어 있는 physical memory에 memset으로 파일 정보를 저장한다. 

남은 page_zero_byte 크기는 0으로 초기화 한다.

 

2. 본문

// userprog/process.c

/* 파일 (FILE) 의 OFS 오프셋에서 시작하여, UPAGE 주소에 세그먼트를 로드한다. OFS = 파일 내용 중 시작 위치를 의미하겠죠?
 * 총 READ_BYTES + ZERO_BYTES 바이트의 VA가 초기화 됨
 * UPAGE에서 시작 ~ READ_BYTES 바이트 크기의 가상 메모리가 초기화. (OFS에서 부터 읽어온 데이터들)
 * UPAGE + READ_BYTES ~ ZERO_BYTES만큼의 데이터는 0으로 초기화
 * WRITABLB = true인 경우, user process에서 쓰기가 가능해야 함. 그렇지 않은 경우엔, read-only 로 설정
 * 성공시, true / 메모리 할당 오류 또는 디스크 읽기 오류, false
 * */
static bool /* 실행 파일의 세그먼트를 페이지 단위로 나누고 초기화 되지 않은 페이지로 설정.*/
load_segment (struct file *file, off_t ofs, uint8_t *upage,
		uint32_t read_bytes, uint32_t zero_bytes, bool writable) {
	ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
	ASSERT (pg_ofs (upage) == 0);
	ASSERT (ofs % PGSIZE == 0);

	while (read_bytes > 0 || zero_bytes > 0) {
		/* Do calculate how to fill this page.
		 * We will read PAGE_READ_BYTES bytes from FILE
		 * and zero the final PAGE_ZERO_BYTES bytes. */
		size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
		size_t page_zero_bytes = PGSIZE - page_read_bytes;

		/* TODO: Set up aux to pass information to the lazy_load_segment. */
        struct aux *aux = (struct aux *)malloc(sizeof(struct aux));
        aux->file = file;
        aux->offset = ofs;
        aux->page_read_bytes = page_read_bytes;

		if (!vm_alloc_page_with_initializer (VM_ANON, upage,
					writable, lazy_load_segment, aux))
			return false;

		/* Advance. */
		read_bytes -= page_read_bytes;
		zero_bytes -= page_zero_bytes;
		upage += PGSIZE;
        ofs += page_read_bytes;
	}
	return true;
}

 

해당 코드에 대한 이해를 위해 수기로 작성해서 이해하였다.

 

다음으로, lazy_load_segment에 대해서 알아보자.

주석으로 코드 흐름에 대해 작성해 두었다.

static bool 
lazy_load_segment (struct page *page, void *aux) {
	/* TODO: Load the segment from the file */
	/* TODO: This called when the first page fault occurs on address VA. */
	/* TODO: VA is available when calling this function. */

    /* <pseudo>
     * aux - file pointer, offset, read size 등을 가져오기.
     * 파일에서 데이터를 읽어서 페이지에 복사.
     * 남은 공간은 0 으로 채우기.
     * UNINIT PAGE 상태에 필요했던, aux 해제
     * 
     * page ->  va 에서, UNINIT 페이지를 찾기
     * 실제 file에 접근해서 데이터를 가지고 와서 RAM에 할당하고, page와 연관짓기
     */

    struct aux *aux_p = aux;
    struct file *file = aux_p->file;
    off_t offset = aux_p->offset;
    size_t page_read_bytes = aux_p->page_read_bytes;
    size_t page_zero_bytes = PGSIZE - page_read_bytes;

    file_seek(file, offset); // 파일을 offset부터 읽기
    if (file_read(file, page->frame->kva, page_read_bytes) != (off_t)page_read_bytes) { // 물리 메모리에서 정상적으로 읽어오는지 확인.
        palloc_free_page(page->frame->kva); // 제대로 못 읽었다면 free 시키고 false return
        return false;
    }

    memset(page->frame->kva + page_read_bytes, 0, page_zero_bytes);  //남은 페이지 데이터들은 0으로 초기화
	// page->frame->kva 로, 해당 VA에 해당하는 physical address에 파일에 대한 정보를 mapping 시킨다.
    return true;
}

 

3. 결과

아직까지 결과는 123 of 141 tests failed로 동일하다.

728x90