[크래프톤 정글 2기] Day 76
회고
어제 새벽 3시까지 동료 코드를 봐주다가 잠들었다. 그리고 아침 7시에 운동을 다녀왔다. 죽을 것 같았지만, 편의점에서 1+1 행사 중인 에너지 음료를 마시고 힘을 낼 수 있었다. 가슴 운동을 열심히 했다.
오늘은 프로젝트 3의 두 번째 파트인 Anonymous Page를 구현했다. 깃북을 읽고 개념을 공부하고 구현에 들어갔다. 익명 페이지라는 개념이 생소해서 이해하기 어려웠다. 이 파트에서 주요 구현 이슈는 익명 페이지보다는 lazy loading이다. 필요 시점까지 메모리의 로딩을 지연시키는 방식이다. 기존의 핀토스는 프로그램 로드 시에 모든 정보를 메모리에 로딩하지만, 이 파트에서 lazy loading를 구현하면서 프로그램 실행 초기에 필요한 자원을 모두 로드하지 않고 필요한 시점에 로드하면서 초기 로딩 부담을 완화시킬 수 있다.
lazy loading을 제대로 구현하기 전까지는 프로젝트 2에서 통과했던 모든 테스트 케이스들이 터진다. 로딩이 구현되지 않았기 때문에 당연한 결과이다. 따라서 이 파트의 목표는 프로그램을 제대로 실행시켜 보는 것이다! 주요 구현 사항은 lazy_load_segment와 load_segment, setup_stack 함수이다. 그리고 어제 구현했던 보조 페이지 테이블 관련 함수에서도 오류가 좀 있어서 수정해주었다.
load_segment()
기존에는 load_segment() 함수에서 파일을 읽고 물리 페이지에 저장한 다음 가상 페이지 주소와 매핑시켜 페이지 테이블에 저장했다. lazy loading 방식에서 load_segment()는 첫 페이지 폴트 시 파일의 어디를 읽을지를 지정해주면 된다. 파일 바이트를 순차적(반복문)으로 돌면서 해당 페이지에서 페이지 폴트가 발생할 시, lazy_load_segment()를 호출하도록 설정해준다고 보면 된다.
lazy_load_segment에서 어떤 파일을 읽을지 알 수 없기 때문에, 인자값 aux에 파일을 포함한 구조체를 만들어서 넘겨주었다. 이후 페이지 폴트가 발생하면 lazy_load_segment()에서 해당 페이지를 파일에서 읽고 처리해주면 된다.
struct file_segment {
struct file *file;
size_t page_read_bytes;
size_t page_zero_bytes;
bool writable;
};
트러블 슈팅
구현할 게 많아서 중간중간에 터진게 꽤 많았다. backtrace할 call stack이 없을 때도 있어서, 어디서 터졌는지 모를 때도 많았다. 해결 방법은 모조리 printf()를 찍어보면서 어디서 터졌는지 확인하는 것이다. 그렇게 하다가 file_read에서 터졌다는 것을 확인했다. file_read (file, kpage, page_read_bytes) 처럼 인자로 파일 구조체를 넘겨주어야 하는데, load_segment에서 생성한 file_segment 구조체에서 문제가 생겼다는 것을 알 수 있었다. file_segment 구조체를 생성할 때, malloc으로 동적 할당을 해주었는데, file_segment->file에 대해서도 동적 할당한 후, memcpy로 file 값을 복사해서 넘겨주어야 했다.
static bool
load_segment (struct file *file, off_t ofs, uint8_t *upage,
uint32_t read_bytes, uint32_t zero_bytes, bool writable) {
...
while (read_bytes > 0 || zero_bytes > 0) {
...
void *aux = NULL;
struct file_segment *file_segment = malloc (sizeof (file_segment));
file_segment->file = malloc (sizeof (struct file));
file_segment->page_read_bytes = page_read_bytes;
file_segment->page_zero_bytes = page_zero_bytes;
memcpy (file_segment->file, file, sizeof (struct file));
file_seek (file_segment->file, ofs);
aux = file_segment;
...
ofs += page_read_bytes; // 중요
}
}
동적 할당한 구조체는 lazy_load_segment에서 처리된 이후에는 필요없으므로 바로 free해주면 된다. 그리고 load_segment()의 while 문 마지막에 ofs += page_read_bytes;
를 반드시 추가해주어야 한다. 기존의 핀토스에서는 file_read하면 파일의 읽을 위치가 알아서 바뀌지만, lazy loading 방식에서는 우리가 바꿔주어야 한다. 모르는 사항이었는데, 어제 새벽까지 에러를 잡던 동료가 문제를 해결하고 알려주었다.