매개변수

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만 초기화해주어도 충분하다.