미소를뿌리는감자의 코딩
[Pintos_project3 (1)] supplemental_page_table_init 본문
1. 개요
project3의 첫 번째 관문으로 supplemental_page_table_init을 작성하는 것이었다.
// vm/vm.c
/* Initialize new supplemental page table */
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
/* [pseudo]
아마도,,, virtual page entry 개수 만큼의 리스트 할당. 이를 통해 spt 초기화
*/
}
vm/vm.c에서 정의되어 있는 supplemental_page_table_init은 위와 같다.

spt는 가상 메모리 페이지의 상태를 저장하기 위한 목적으로 이용된다. 즉, Dirty bit, Acessed bit를 이용해서 수정되었는지, 그리고 접근 되었는 지를 추적한다.
따라서, supplemental_table_init은 virtual page entry 개수 만큼의 크기를 필요로 하는 자료 구조가 되지 않을까 라고 판단하였다.
따라서, 필요한 만큼의 데이터를 동적으로 할당할 수 있고 검색의 시간 복잡도가 O(1)인 해시를 이용해서 supplemental_page_table을 구성할 것이다.
2. 본문
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
/* [pseudo]
아마도,,, virtual page entry 개수 만큼의 리스트 할당. 이를 통해 spt 초기화
*/
hash_init(&spt->spt_hash, hash_func, less_func, NULL);
}
참고한 코드는 위와 같다.
여기서 사용되는 hash_init은 lib/kernel/hash.c에 선언되어 있다.
// lib/kernel/hash.c
/* Initializes hash table H to compute hash values using HASH and
compare hash elements using LESS, given auxiliary data AUX. */
bool
hash_init (struct hash *h,
hash_hash_func *hash, hash_less_func *less, void *aux) {
h->elem_cnt = 0;
h->bucket_cnt = 4;
h->buckets = malloc (sizeof *h->buckets * h->bucket_cnt);
h->hash = hash;
h->less = less;
h->aux = aux;
if (h->buckets != NULL) {
hash_clear (h, NULL);
return true;
} else
return false;
}
해시 테이블을 초기화 하는 역할을 하는 hash_init에 대해서 알아보자. 첫 번째 인자인 struct hash *h는 초기화할 해시 테이블을 가리키는 포인터이다. 따라서, &spt -> spt_hash로 초기화할 hash를 지정해 주었다.
hash_init을 하고자 하는 대상은, supplemental page table의 멤버 중 하나인 spt_hash가 될 것이다.
spt에서 hash 자료구조를 사용할 것이라는 것을 나타내 주어야 하기 때문에, include/vm/vm.h 에서 supplemental_page_table을 찾아, spt_hash를 추가해 준다. [ &spt -> spt_hash ] 를 나타내주기 위함.
/include/vm/vm.h
/* Representation of current process's memory space.
* We don't want to force you to obey any specific design for this struct.
* All designs up to you for this. */
struct supplemental_page_table {
struct hash spt_hash;
};
hash_func는 해시의 키에 따라 값을 계산하는 함수의 포인터이다. 나온 값을 어떤 기준으로 정렬할 것인지를 명시해주기 위해 less_func또한 정의해 주었다.
hash_init(&spt->spt_hash, hash_func, less_func, NULL);
hash.h에 선언해 주는 것도 잊지 않았다.
// include/lib/kernel/hash.h
/* project 3 */
uint64_t hash_func(const struct hash_elem *e, void *aux);
bool less_func(const struct hash_elem *a, const struct hash_elem *b, void *aux);
hash_func와 less_func에 대해서 알아보기에 앞서, hash_elem과 hash_entry에 대해서 알아보자.
hash_entry를 알아보려고 하는 이유는, hash_func에서 hash_entry를 사용하기 때문이다.
// include/lib/kernel/hash.h
/* Hash element. */
struct hash_elem {
struct list_elem list_elem;
};
#define hash_entry(HASH_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(HASH_ELEM)->list_elem \
- offsetof (STRUCT, MEMBER.list_elem)))
// 아래와 같이 hash_entry가 사용됨. 'e'의 자료구조는 hash_elem *
hash_entry(e, struct page, hash_elem);
HASH_ELEM : 해시 테이블에 저장된 데이터 요소인 hash_elem을 가리키기 위해 사용된다.
STRUCT : hash_elem을 포함하는 외부 구조체 타입인 page을 명시하기 위해 사용된다.
MEMBER: 외부 구조체인 STRUCT (page) 안에서 hash_elem이 정의된 멤버 변수의 이름을 나타낸다.
hash_entry의 목적은 hash_elem을 가리키고 있는 페이지의 시작주소를 얻기 위함이다.
따라서, 페이지의 hash_elem의 주소값 - (페이지에서 hash_elem까지의 주소값) 을 통해서, 페이지 시작 값을 계산해 준다.
아래는 struct page -> struct hash_elem -> struct list_elem 까지의 흐름을 나타내는 그림이다.

hash_entry 매크로는 hash_elem을 참조하는 외부 구조체인 page를 가리키는 포인터를 찾기 위한 용도이다.
처음에 코드가 잘 이해가 가지 않아서 갚게 파보았다.
또한 아래는 hash table의 구조를 그려보았다. 그림으로 그려보니 훨씬 이해가 잘 된다.
우선 hash_func에 대해서 먼저 알아보자.
// lib/kernel/hash.c
/*returns hash index*/
uint64_t hash_func(const struct hash_elem *e, void *aux) {
const struct page *p = hash_entry(e, struct page, hash_elem);
return hash_bytes(&p->va, sizeof(p->va));
}
hash_entry를 이용해서, hash_elem을 참조하는 외부구조체인 page의 시작 주소를 얻는다. p가 페이지를 가리키는 포인터가 될 것이다.
페이지가 가지고 있는 va (virtual address)를 얻어서, 이를 통해 64비트 해시 값을 얻는다.
다음으로 less_func에 대해서 알아보자.
/*asc. sort*/
bool less_func(const struct hash_elem *a, const struct hash_elem *b, void *aux) {
const struct page *pa = hash_entry(a, struct page, hash_elem);
const struct page *pb = hash_entry(b, struct page, hash_elem);
return pa->va < pb->va;
}
less_func는 페이지 pa, pb에 대해서, virtual address의 값을 비교해서 반환한다. 이를 통해 해시 테이블을 정렬할 수 있도록 한다.
/* Initialize new supplemental page table */
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
/* [pseudo]
아마도,,, virtual page entry 개수 만큼의 리스트 할당. 이를 통해 spt 초기화
*/
hash_init(&spt->spt_hash, hash_func, less_func, NULL);
}
이렇게 supplemental_page_table을 init하기 위한 함수를 알아보았다.
3. 결과

supplemental_page_table 초기화 밖에 안했기 때문에, 123 of 141 tests failed 임을 확인할 수 있다.
'정글 일지' 카테고리의 다른 글
[Pintos_project3 (4)] vm_alloc_page_with_initializer (0) | 2024.11.30 |
---|---|
[Pintos_project3 (3)] spt_insert_page (0) | 2024.11.29 |
[Pintos_project3 (2)] spt_find_page (0) | 2024.11.29 |
sftp로 ec2 서버 열기 - ubuntu 18.04 image (0) | 2024.11.12 |
[0주차] 크래프톤 정글 7기 회고 (2) | 2024.09.06 |