정글 일지
[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