210218 개발일지(73일차) - 운영체제(OS) 프로젝트 #3-1 Lazy load segment

고재개발·2021년 2월 21일
0

OS Project

목록 보기
18/28

project#2까지 구현한 흐름

lazy load segment를 알아보기 전에 load segment를 알아보자.

load segment


pintos에서는 load_segment() 함수를 활용해 kernel주소(kpage)에 file을 모두 load 시킨다. 그리고 유저스택 page(upage)와 kernel주소(kpage)을 install_page() 함수로 매핑(mapping) 시켜준다.

위의 Flowchart에서 load_segment()가 호출되는 순간 file이 전부 kpage에 올라가는 것이다.
Project3에서는 필요할 때만(요청이 올 때만), 필요한 file만 kpage에 올리고 싶어서 lazy_load_segment() 함수를 구현하고자 한다.

<pintos에서 제공되는 기존 load_segment 코드>

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);

    file_seek(file, ofs);
    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;

        /* Get a page of memory. */
        uint8_t *kpage = palloc_get_page(PAL_USER);
        if (kpage == NULL)
            return false;

        /* Load this page. */
        if (file_read(file, kpage, page_read_bytes) != (int)page_read_bytes)
        {
            palloc_free_page(kpage);
            return false;
        }
        memset(kpage + page_read_bytes, 0, page_zero_bytes);

        /* Add the page to the process's address space. */
        if (!install_page(upage, kpage, writable))
        {
            printf("fail\n");
            palloc_free_page(kpage);
            return false;
        }

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

lazy load segment

위의 설명한대로 구현하기 위해선, thread 구조체에 spt(=supplemental page table)를 추가해준다. 이는 원하는 시점(제대로 된 page fault 발생)에 file을 load하기 위해 필요하다.
1. 처음에 load_segment를 실행해주면, vm_alloc_page_with_initializer() 함수의 인자로 lazy_load_segment 함수와 file에 대한 각종 정보들을 전달해준다.
2. vm_alloc_page_with_initializer() 함수에서 여러 정보들을 spt에 넣어준다.
3. 이후 정상적인 page fault가 발생하면, lazy_load_segment() 함수를 불러와서 원하는 file을 kpage에 load 시켜주도록 한다.

따라서, load_segment 코드도 일부 바뀐다. 바뀐 load_segment 코드와 lazy_load_segment 함수를 아래에서 확인해보자.

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 container* container;
        container = palloc_get_page(PAL_ZERO | PAL_USER);
        
        container->file = file;
        container->page_read_bytes = page_read_bytes;
        container->writable = writable;
        container->offset = ofs;

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

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


static bool
lazy_load_segment(struct page *page, void *aux)
{   
    struct frame *frame = page->frame;
    /* 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. */
    struct container *container = (struct container*) aux;
    
    struct file *file = container->file;
    size_t page_read_bytes = container->page_read_bytes;
    size_t page_zero_bytes = PGSIZE - page_read_bytes;
    bool writable = container->writable;
    off_t offset = container->offset;

    file_seek(file, offset);

    if (file_read(file, frame->kva, page_read_bytes) != (int)page_read_bytes)
    {
        return false;
    }
    memset(frame->kva + page_read_bytes, 0, page_zero_bytes);

    return true;
}
profile
고재개발

0개의 댓글