spt, va
함수는 spt에 va에 해당되는 페이지가 있는지를 검사하는 함수다. 따라서 매개변수는 이상할게 없다. 그리고 내가 발견한 함수는 hash_find라는 함수다. 내부를 보면 알아서 버킷을 찾고, chaining 방식으로 만들어진 list를 순회하는것으로 보인다. 따라서 이 함수를 재활용하면 되겠다고 생각했다.
그런데 hash_find의 매개변수는 다음과 같다.
hash_find (struct hash *h, struct hash_elem *e) {
return find_elem (h, find_bucket (h, e), e);
}
내가 알기로는 hash_elem은 페이지 안에 있는 멤버다. 즉, 이 함수를 사용할때는 페이지 구조체가 있어야한다. 그런데 내가 받은 매변수는 spt, va밖에 없다. 버킷으로 접근해 va를 갖는 페이지를 찾기 전에, 이 정보를 알 방법이 없다고 느껴졌다.
내가 부족했던건 va를 이용해 페이지를 만들 생각은 못했던 것이다. hash_elem만 전달하면 된다는 사실을 모른채, 페이지 구조체를 만들어야한다는 생각과 초기화에 필요한 정보가 부족하다는 사실이 머리를 혼란스럽게 만들었다.
struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */
/* Your implementation */
struct hash_elem elem; /* need to concat with pages in bucket */
/* Per-type data are binded into the union.
* Each function automatically detects the current union */
union {
struct uninit_page uninit;
struct anon_page anon;
struct file_page file;
#ifdef EFILESYS
struct page_cache page_cache;
#endif
};
};
그런데 알고보면 hash_elem과 va값만 있으면 되기 때문에, page 구조체를 만들어서 임시로 사용하면 된다. 임시로 사용하기 때문에 지역변수로 선언하는것이 맞다.
hash_find에서 호출하고 있는 find_elem을 들여다보자.
/* Searches BUCKET in H for a hash element equal to E. Returns
it if found or a null pointer otherwise. */
static struct hash_elem *
find_elem (struct hash *h, struct list *bucket, struct hash_elem *e) {
struct list_elem *i;
for (i = list_begin (bucket); i != list_end (bucket); i = list_next (i)) {
struct hash_elem *hi = list_elem_to_hash_elem (i);
if (!h->less (hi, e, h->aux) && !h->less (e, hi, h->aux))
return hi;
}
return NULL;
}
하는 일은 버킷이 가리키는 리스트를 순회하면서 e와 hi를 비교하는것뿐이다. 그리고 비교하는 값은 va일테고, 대소를 판단하는 함수는 hash→less다. 따라서 page 구조체의 모든 멤버를 초기화할 필요가 없다.
다음은 호출되고 있는 find_bucket 함수를 보자.
/* Returns the bucket in H that E belongs in. */
static struct list *
find_bucket (struct hash *h, struct hash_elem *e) {
size_t bucket_idx = h->hash (e, h->aux) & (h->bucket_cnt - 1);
return &h->buckets[bucket_idx];
}
마찬가지로 hash 안에 있는 함수를 이요하고 있지, e로 직접 무언가를 하고 있지 않다. h→hash에서 하는것은 va 값을 이용해 인덱스로 바꿔주는 작업뿐이다. 여기서도 va 값 외에는 필요가 없다.
결론은 va값 빼고는 필요가 없으니, va만 초기화해주어도 충분하다.