배경

lazy_load_segment에서 aux에 들어가는 구조체(segment_load_info)는 동적 할당받아 사용한다. 따라서 반드시 해제해주어야한다. 문제는 해제가 여러군데에서 일어나야 한다는 점이다.

struct segment_load_info {
            struct file *file;  // 불러올 파일
            off_t offset;       // 읽기 시작할 부분
            size_t read_bytes;  // 읽을 크기
            size_t zero_bytes;  // 0으로 채울 크기
        };

생성

aux 구조체(segment_load_info) 는 load_segment 에서 생성된다. 그리고 생성에 실패하면, 즉시 해제한다.

/* 프레임 초기화를 위한 정보 */
		struct load_info aux = malloc(sizeof(*aux));
		aux.file = file;
		aux.offset = offset;
		size_t read_bytes = read_bytes;
		size_t zero_bytes = zero_bytes;

		/* 사용자 가상 페이지를 lazy loading 대상으로 등록. */
		if (!vm_alloc_page_with_initializer (VM_ANON, upage,
					writable, lazy_load_segment, aux)) {
			
			/* aux 구조체 해제*/
			free(aux);
			return false;
		}

성공했을 경우 어디서 정리해야하는가

생성에 성공했다면, 해제되는 시점은 아래와 같아.

case1: page fault 발생

page fault가 일어나면, lazy_load_segment에서 프레임에 데이터를 적재한다. 즉, 더이상 aux 구조체가 필요없어진다. 따라서 lazy_load_segemnt에서 정리해주어야한다.

static bool
lazy_load_segment(struct page *page, void *aux)
{
	/* page와 aux를 이용해 데이터를 프레임으로 올리는 함수 */
	struct segment_load_info* info = aux;
	bool success = false;

	/* 프레임에 파일 내용 로드 */
	if (file_read(info->file, page->frame->kva, info->read_bytes) != info->read_bytes)
		{
			goto done;
		}
	
	/* 남는 공간은 0으로 초기화 */
	memset((uint8_t *)page->frame->kva + info->read_bytes, 0, info->zero_bytes);
	
	success = true;

done:		
	/* 결과와 상관없이 aux 구조체를 해제 */
	free(info);
	return success;
}

lazy_load_segment에서 정리해야하는걸 알아내는데 힌트가 있다. load_segment에서 lazy_load_segment는 aux를 사용하는 callback 함수로 넘겨진다. 따라서, aux를 사용하는것은 load_segment임을 알 수 있다.

if (!vm_alloc_page_with_initializer (VM_ANON, upage,
					writable, lazy_load_segment, aux))
					...

case2: 프로세스를 정리