10월이다
아직 정글이다
간단하게 spt copy 구현했다
/* 보조 페이지 테이블을 src에서 dst로 복사한다. */
bool
supplemental_page_table_copy (struct supplemental_page_table *dst,
struct supplemental_page_table *src)
{
struct hash_iterator it;
hash_first(&it, &src->h);
while (hash_next(&it)) {
struct page *sp = hash_entry(hash_cur(&it), struct page, spt_elem);
void *va = sp->va;
bool writable = sp->writable;
/* 현재 상태 */
enum vm_type cur = VM_TYPE(sp->operations->type);
if (cur == VM_UNINIT) {
/* 초기화되면 어떤 타입이 될지 (ANON/FILE) */
enum vm_type after = page_get_type(sp);
vm_initializer *init = sp->uninit.init;
void *aux_copy = NULL;
if (VM_TYPE(after) == VM_FILE) {
/* lazy_load_segment용 aux deep-copy (파일 핸들 duplicate) */
/* 나중에는 file_reaopen()하고 file_close()로 대체 권장 */
aux_copy = dup_aux_for_file_uninit(sp->uninit.aux);
if (sp->uninit.aux && aux_copy == NULL) goto fail;
} else {
/* 보통 UNINIT(ANON)은 aux가 없거나 의미 없음 */
aux_copy = NULL;
}
if (!vm_alloc_page_with_initializer(after, va, writable, init, aux_copy))
goto fail;
/* UNINIT은 여기서 끝. 자식은 첫 PF 때 로드됨. */
continue;
}
/* 이미 메모리에 올라온 페이지(ANON 또는 FILE) → 자식에 ANON 생성 후 내용 복사 */
if (!vm_alloc_page_with_initializer(VM_ANON, va, writable, NULL, NULL))
goto fail;
if (!vm_claim_page(va))
goto fail;
struct page *dp = spt_find_page(dst, va);
if (dp == NULL || dp->frame == NULL) goto fail;
/* 부모 페이지는 이미 메모리에 있어야 함 (swap 미구현 가정) */
if (sp->frame == NULL) goto fail;
memcpy(dp->frame->kva, sp->frame->kva, PGSIZE);
}
return true;
fail:
/* 부분 생성된 dst 정리 */
supplemental_page_table_kill(dst);
return false;
}
대강 쪼개서 하는 일만 설명하겠다
/* 보조 페이지 테이블을 src에서 dst로 복사한다. */
bool
supplemental_page_table_copy (struct supplemental_page_table *dst,
struct supplemental_page_table *src)
{
struct hash_iterator it;
hash_first(&it, &src->h);
while (hash_next(&it)) {
struct page *sp = hash_entry(hash_cur(&it), struct page, spt_elem);
void *va = sp->va;
bool writable = sp->writable;
/* 현재 상태 */
enum vm_type cur = VM_TYPE(sp->operations->type);
해시 테이블가지고 순회돌면서 현재 상태 (writable, VM_TYPE 등)를 기록하며 넘어간다
if (cur == VM_UNINIT) {
enum vm_type after = page_get_type(sp); /* VM_ANON or VM_FILE */
vm_initializer *init = sp->uninit.init;
void *aux_copy = NULL;
if (VM_TYPE(after) == VM_FILE) {
aux_copy = dup_aux_for_file_uninit(sp->uninit.aux);
if (sp->uninit.aux && aux_copy == NULL) goto fail;
} else {
aux_copy = NULL;
}
페이지 폴트 났을때 어떤 타입으로 가져올지를 page_get_type
을 통해 가져온다
타입이 FILE
이면 aux도 필요하므로 깊은 복사 헬퍼 사용한다
타입이 ANON
이면 aux가 보통 필요 없다
if (!vm_alloc_page_with_initializer(after, va, writable, init, aux_copy))
goto fail;
continue;
}
vm_alloc_page_with_initializer
를 통해 자식 SPT에도 UNINIT 엔트리 생성한다
이미 부모가 메모리에 있을때(UNINIT
아닐때)다
if (!vm_alloc_page_with_initializer(VM_ANON, va, writable, NULL, NULL))
goto fail;
if (!vm_claim_page(va))
goto fail;
자식 SPT에서 새로운 ANON
페이지 생성 후, 즉시 claim해 프레임 확보한다
FILE
이어도 그냥 ANON
으로 받게 했다
프로젝트2에는 CoW가 없기에 그냥 이렇게 처리하는게 더 좋다
struct page *dp = spt_find_page(dst, va);
if (dp == NULL || dp->frame == NULL) goto fail;
if (sp->frame == NULL) goto fail;
memcpy(dp->frame->kva, sp->frame->kva, PGSIZE);
만든 페이지와 프레임 검증한다
부모쪽도 있어야 하기에 이쪽도 같이 검증해준다
이후 부모 프레임에서 자식 프레임으로 복사한다
}
return true;
fail:
supplemental_page_table_kill(dst);
return false;
}
실패하면 어제 만든 kill 함수로 싹 날린다
static void *dup_aux_for_file_uninit(const void *aux0) {
if (aux0 == NULL) return NULL;
const struct load_aux *src = aux0;
struct load_aux *dst = malloc(sizeof *dst);
if (!dst) return NULL;
*dst = *src;
if (dst->file) {
dst->file = file_duplicate(dst->file);
if (!dst->file) { free(dst); return NULL; }
}
return dst;
}
별건 없고 NULL가드랑 타입 캐스팅, 메모리 할당 해준다
얕은 복사로 구조체 베껴오고 *dst = *src;
이후, file_duplicate
를 통해 파일 핸들을 복사해온다