[TIL] [WEEK11-12] Pintos Project(3) Anonymous Page 1.

woo__jยท2024๋…„ 6์›” 12์ผ
0

Pintos Project

๋ชฉ๋ก ๋ณด๊ธฐ
10/14

๐Ÿ“ ๋‘ ๋ฒˆ์งธ ๊ณผ์ œ, Anonymous Page

์ด๋ฒˆ ํŒŒํŠธ์—์„œ๋Š” Anonymous Page(non-disk based image)๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

Anonymous Page? ๐Ÿค”
์ต๋ช… ๋งคํ•‘์—๋Š” ๋ฐฑ์—… ํŒŒ์ผ์ด๋‚˜ ์žฅ์น˜๊ฐ€ ์—†๋‹ค. file-backed page์™€ ๋‹ฌ๋ฆฌ ์ด๋ฆ„์ด ์žˆ๋Š” ํŒŒ์ผ ์†Œ์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ต๋ช…์ด๋ผ๊ณ  ํ•˜๋ฉฐ, ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ์—์„œ ์Šคํƒ๊ณผ ํž™ ์˜์—ญ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.
= ์–ด๋–ค ํŒŒ์ผ๊ณผ๋„ ๋งคํ•‘๋˜์ง€ ์•Š์€ ๋ฉ”๋ชจ๋ฆฌ ํŽ˜์ด์ง€๋กœ, ํ”„๋กœ์„ธ์Šค์˜ ๋™์  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์š”์ฒญ์— ์‘๋‹ตํ•ด ์ƒ์„ฑ๋œ๋‹ค.


๐Ÿ› ๏ธ Page Initialization with Lazy Loading

Lazy Loading์ด๋ž€ ๋ฉ”๋ชจ๋ฆฌ ๋กœ๋”ฉ์„ ์ง€์—ฐ์‹œ์ผœ ํ•„์š”ํ•œ ์ˆœ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋”ฉํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด๋‹ค.
์ฆ‰, ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹นํ•ด ๋Œ€์‘ํ•˜๋Š” ํŽ˜์ด์ง€ ๊ตฌ์กฐ์ฒด๋Š” ์žˆ์œผ๋‚˜ ๊ทธ๊ฒƒ๊ณผ ์—ฐ๊ฒฐ๋œ ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„๊ณผ ํŽ˜์ด์ง€์˜ ์‹ค์ œ ์ปจํ…์ธ ๋Š” ์•„์ง ๋กœ๋“œ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋‹ค. ์ด ์ƒํƒœ์—์„œ page fault๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
์ด ๋•Œ ํŽ˜์ด์ง€์˜ ์‹ค์ œ ์ปจํ…์ธ ๋ฅผ ๋กœ๋“œํ•˜๋Š” ๊ฒŒ Lazy Loading์ด๋‹ค.

Lazy Loading์„ ํ•˜๋Š” ์ด์œ ๋Š”? ๐Ÿค”
: ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํŽ˜์ด์ง€๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋˜์ง€ ์•Š๋Š”๋‹ค. lazy loading์€ ํ•„์š”ํ•œ ์‹œ์ ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•จ์œผ๋กœ์จ ์‹œ์Šคํ…œ์˜ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„๋ฅผ ์ค„์ด๊ณ , ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ณด๋‹ค ๋” ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

PintOS์—๋Š” 3๊ฐ€์ง€์˜ ํŽ˜์ด์ง€ ํƒ€์ž…์ด ์žˆ๋Š”๋ฐ, ๊ฐ ํƒ€์ž…๋ณ„ ์ดˆ๊ธฐํ™” ๋ฃจํ‹ด์ด ๋‹ค๋ฅด๋‹ค.
ํŽ˜์ด์ง€์˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •์ด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์•Œ์•„๋ณด์ž.

  1. vm_alloc_page_with_initializer()
    ์ปค๋„์ด ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€ ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด vm_alloc_page_with_initializer()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    ํ•ด๋‹น ํ•จ์ˆ˜๋Š” page ๊ตฌ์กฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ ์ ˆํ•œ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ ์„ค์ •ํ•œ๋‹ค. ๋˜ํ•œ ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๋ฅผ spt์— ์ถ”๊ฐ€ํ•œ๋‹ค.
    -> ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ณ  ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ '๋‹ด์•„๋งŒ' ๋‘๋Š”๋ฐ, ์ด๋ ‡๊ฒŒ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€ ํƒ€์ž…์€ uninit์ด๋‹ค.

  2. page fault ๋ฐœ์ƒ -> vm_try_handle_fault - ...
    ์œ ์ € ํ”„๋กœ๊ทธ๋žจ์ด ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€์— ์ฒ˜์Œ ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด page fault๊ฐ€ ๋ฐœ์ƒ๋˜๋ฉด์„œ lazy loading์ด ์ผ์–ด๋‚˜๋ฉฐ, ์ด ๋•Œ ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„์ด ํ• ๋‹น๋˜๋ฉด์„œ uninit page์— ๋‹ด๊ฒจ์žˆ๋Š” ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

  3. ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” ๋ฐ lazy_load_segment
    ํŽ˜์ด์ง€ ์œ ํ˜•์— ๋งž๋Š” ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , ๋™์‹œ์— ๋‚ด์šฉ์ด ๋กœ๋“œ๋œ๋‹ค.

์œ„ ๊ณผ์ •์„ ํ‘œ๋กœ ์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
load_segment์—์„œ while๋ฌธ์œผ๋กœ vm_alloc_page_with_initializer๋ฅผ ํ˜ธ์ถœํ•ด ํ”„๋กœ์„ธ์Šค๋ฅผ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ๋ฉด์„œ spt์— ์ ์žฌํ•œ๋‹ค.
vm_alloc_page_with_initializer์—์„œ๋Š” ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ด type์— ๋งž๋Š” ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ ๋‹ด์€ ๋‹ค์Œ uninit_new๋ฅผ ํ˜ธ์ถœํ•ด uninit_page๋กœ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.


1) vm_alloc_page_with_initializer()
page ๊ตฌ์กฐ์ฒด ์ƒ์„ฑ ๋ฐ ์ ์ ˆํ•œ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ ๋‹ด์•„ uninit ํŽ˜์ด์ง€๋กœ ์ดˆ๊ธฐํ™”

bool vm_alloc_page_with_initializer(enum vm_type type, void *upage, bool writable,
									vm_initializer *init, void *aux)
{
	ASSERT(VM_TYPE(type) != VM_UNINIT)

	struct supplemental_page_table *spt = &thread_current()->spt;

	/* Check wheter the upage is already occupied or not. */
	/* upage๊ฐ€ ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ธ์ง€ ํ™•์ธ */
	if (spt_find_page(spt, upage) == NULL)
	{
		/* ํŽ˜์ด์ง€ ์ƒ์„ฑ */
		struct page *p = (struct page *)malloc(sizeof(struct page));

		/* ํŽ˜์ด์ง€ ํƒ€์ž…์— ๋”ฐ๋ผ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€ ๋‹ด๊ธฐ */
		bool (*page_initializer)(struct page *, enum vm_type, void *);

		switch (VM_TYPE(type))
		{
		case VM_ANON:
			page_initializer = anon_initializer;
			break;

		case VM_FILE:
			page_initializer = file_backed_initializer;
			break;
		}

		/* ์ƒ์„ฑํ•œ ํŽ˜์ด์ง€๋ฅผ uninit page๋กœ ์ดˆ๊ธฐํ™” */
		uninit_new(p, upage, init, type, aux, page_initializer);

		/* ํŽ˜์ด์ง€ ๊ตฌ์กฐ์ฒด์˜ ํ•„๋“œ ์ˆ˜์ • */
		/* ํ•„๋“œ ๊ฐ’์„ ์ˆ˜์ •ํ•  ๋• uninit ํ˜ธ์ถœ ์ดํ›„์— ํ•ด์•ผ ํ•œ๋‹ค = uninit_new ํ•จ์ˆ˜ ์•ˆ์—์„œ ๊ตฌ์กฐ์ฒด ๋‚ด์šฉ์ด ๋ชจ๋‘ ์ƒˆ๋กœ ํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์— */
		p->writable = writable;

		/* ์ƒ์„ฑํ•œ ํŽ˜์ด์ง€ spt์— ์ถ”๊ฐ€ */
		return spt_insert_page(spt, p);
	}
err:
	return false;
}

ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ uninit_new()๋ฅผ ํ˜ธ์ถœํ•ด uninit page๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š”๋ฐ, ์–ด๋–ป๊ฒŒ ์ดˆ๊ธฐํ™”ํ• ๊นŒ?

void
uninit_new (struct page *page, void *va, vm_initializer *init,
		enum vm_type type, void *aux,
		bool (*initializer)(struct page *, enum vm_type, void *)) {
	ASSERT (page != NULL);

	*page = (struct page) {
		.operations = &uninit_ops,
		.va = va,
		.frame = NULL, /* no frame for now */
		.uninit = (struct uninit_page) {
			.init = init,
			.type = type,
			.aux = aux,
			.page_initializer = initializer,
		}
	};
}

page ๊ตฌ์กฐ์ฒด์˜ ๋ฉค๋ฒ„๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ, page ๊ตฌ์กฐ์ฒด๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

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 bucket_elem; /* ํ•ด์‹œ ํ…Œ์ด๋ธ” ์š”์†Œ */
	bool writable;

	/* 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
	};
};

์—ฌ๊ธฐ์„œ ์ž์„ธํžˆ ๋ด์•ผํ•  ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์žˆ๋‹ค.

  • operations: ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์—ฐ์‚ฐ์„ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๊ตฌ์กฐ์ฒด
  • union: ํŽ˜์ด์ง€ ์œ ํ˜•์˜ ๊ณต์šฉ์ฒด

๐Ÿค” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ž€ ๋ญ˜๊นŒ?
: ํ•จ์ˆ˜ ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ์‹คํ–‰๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ์ธ๋ฐ, ์ด๊ฑธ ์™œ ์“ฐ๋Š” ๊ฑฐ์ง€?
-> c์–ธ์–ด์—์„œ๋Š” ํด๋ž˜์Šค์™€ ์ƒ์†์˜ ๊ฐœ๋…์ด ์—†๋‹ค.
๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํด๋ž˜์Šค ์ƒ์†์„ ๋„์ž…ํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ์ ์šฉ์‹œํ‚จ ๊ฒƒ์ด๋‹ค.

page_operations ๊ตฌ์กฐ์ฒด๋ฅผ ๋ณด๋ฉด swap_in, swap_out, destroy๊ฐ€ ์žˆ๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.
ํŽ˜์ด์ง€ ์œ ํ˜•๋งˆ๋‹ค ๊ฐ ๋ฃจํ‹ด์ด ๋‹ค๋ฅผํ…Œ๋‹ˆ, ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ํ™œ์šฉํ•ด ํŽ˜์ด์ง€ ์œ ํ˜•์— ๋งž๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹ค.

๋‹ค์Œ์œผ๋กœ union์€ ๊ณต์šฉ์ฒด๋กœ, ํŽ˜์ด์ง€ ์œ ํ˜•์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•œ๋‹ค.
๊ฐ ํŽ˜์ด์ง€ ์œ ํ˜• ๋ณ„ ํ•„์š”ํ•œ ๋ฉค๋ฒ„๋ณ€์ˆ˜๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ค ๊ณต์šฉ์ฒด๋ฅผ ๊ฐ€์ง€๋ƒ์— ๋”ฐ๋ผ ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

์ด์ œ ํŽ˜์ด์ง€์˜ ๊ตฌ์กฐ์ฒด๊นŒ์ง€ ๋ดค์œผ๋‹ˆ ๋‹ค์‹œ uninit_new๋กœ ๋Œ์•„๊ฐ€๋ณด์ž.

void
uninit_new (struct page *page, void *va, vm_initializer *init,
		enum vm_type type, void *aux,
		bool (*initializer)(struct page *, enum vm_type, void *)) {
	ASSERT (page != NULL);

	*page = (struct page) {
		.operations = &uninit_ops,
		.va = va,
		.frame = NULL, /* no frame for now */
		.uninit = (struct uninit_page) {
			.init = init,
			.type = type,
			.aux = aux,
			.page_initializer = initializer,
		}
	};
}

๋‹ค์‹œ ๋ด๋ณด๋‹ˆ page ๊ตฌ์กฐ์ฒด์˜ operations๋ฅผ uninit์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์„ ํ•˜๋Š” &uninit_ops๋กœ ํ• ๋‹นํ•˜๊ณ ,
union ๊ณต์šฉ์ฒด๋ฅผ uninit_page๋กœ ๋‘ ์œผ๋กœ์จ 4๊ฐ€์ง€์˜ ์ถ”๊ฐ€ ๋ฉค๋ฒ„๋ณ€์ˆ˜๊ฐ€ ์ž‘์šฉํ•˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

  • init
    : page์˜ ๋‚ด์šฉ์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜
    = ์ด๋Š” vm_alloc_page_with_initializer์—์„œ ์ธ์ž๋กœ ๋ฐ›์€ lazy_load_segment๊ฐ€ ๋“ค์–ด๊ฐˆ ๊ฒƒ์ด๋‹ค.
  • type
    : ํŽ˜์ด์ง€ ์œ ํ˜•
    = ์ด๋Š” uninit์ด ์•„๋‹Œ, ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๋‹ด์€ ์œ ํ˜•
  • aux
    : init์— ํ•„์š”ํ•œ ๋ณด์กฐ ์ธ์ž
  • initializer
    : ํŽ˜์ด์ง€ ์œ ํ˜•์— ๋”ฐ๋ฅธ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜
    = vm_alloc_page_with_initializer์—์„œ ๋‹ด์€ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜

์—ฌ๊ธฐ์„œ ์ฃผ์˜๊นŠ๊ฒŒ ๋ด์•ผํ•  ๊ฒƒ์€ &uninit_ops์™€ init, ๊ทธ๋ฆฌ๊ณ  initializer๋‹ค.

  • init
    : lazy_load_segment๊ฐ€ ๋‹ด๊ธฐ๊ฒŒ ๋˜๋Š”๋ฐ, ์ด ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋Š” page fault๊ฐ€ ๋ฐœ์ƒํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋˜์–ด์•ผ ํ•˜๋Š” ์‹œ์ ์ผ ๊ฒƒ์ด๋‹ค. lazy loading์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ด๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ๋ณด๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.
  • initializer
    : ์ด๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„˜๊ฒจ์ฃผ๋Š” type์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜๋ฅผ ๋‹ด๊ฒŒ ๋œ๋‹ค.
    vm_alloc_page_with_initializer์—์„œ ์ธ์ž๋กœ ๋ฐ›์€ type์ด anon type์ด๋ผ๋ฉด anon_initializer๊ฐ€, file_backed type์ด๋ผ๋ฉด file_baced_initializer ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.
    ํ•จ์ˆ˜ ์ž์ฒด๊ฐ€ ์ฃผ์†Œ๊ฐ’์„ ์ง€๋‹ˆ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์†Œ๊ฐ’ ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ํ•จ์ˆ˜๋ช… ์ž์ฒด๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค.

  • &uninit_ops
    : page ๊ตฌ์กฐ์ฒด์˜ operations ๋ฉค๋ฒ„๋ณ€์ˆ˜๋Š” ํ•ด๋‹น ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์—ฐ์‚ฐ์„ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๊ตฌ์กฐ์ฒด๋ผ๊ณ  ํ–ˆ์—ˆ๋‹ค. uninit page์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์€ ์–ด๋–ป๊ฒŒ ์ด๋ค„์ง€๋Š”์ง€ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ํƒ€๊ณ  ๋“ค์–ด๊ฐ€๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

static const struct page_operations uninit_ops = {
	.swap_in = uninit_initialize,
	.swap_out = NULL,
	.destroy = uninit_destroy,
	.type = VM_UNINIT,
};

uninit page๋ฅผ swap_in ํ•  ๋•Œ uninit_initialize ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
uninit_initialize ํ•จ์ˆ˜๋ฅผ ๋ด๋ณด์ž.

static bool
uninit_initialize (struct page *page, void *kva) {
	struct uninit_page *uninit = &page->uninit;

	/* Fetch first, page_initialize may overwrite the values */
	vm_initializer *init = uninit->init;
	void *aux = uninit->aux;

	return uninit->page_initializer (page, uninit->type, kva) && (init ? init (page, aux) : true);
}

๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฑธ ์ž˜ ๋ณด๋ฉด uninit page์— ๋‹ด๊ฒจ์žˆ๋Š” page_initializer๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€ ํƒ€์ž…์— ๋งž๊ฒŒ ์ดˆ๊ธฐํ™”ํ•จ๊ณผ ๋™์‹œ์— init์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋‹ค. init์€ ์œ„์—์„œ ๋งํ–ˆ๋‹ค์‹ถ์ด lazy_load_segment์ธ๋ฐ, ์ด ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ๋กœ๋“œ๊ฐ€ ์ง„ํ–‰๋œ๋‹ค.
๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ฒซ ๋ฒˆ์งธ page_fault๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ์˜๋ฏธ์ผ ๊ฒƒ์ด๋‹ค.

์ด์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋Š” ํ•จ์ˆ˜์ธ load_segment์™€ lazy_load_segment ํ•จ์ˆ˜๋ฅผ ๋ณผ ์ฐจ๋ก€๋‹ค.


๐Ÿ› ๏ธ load_segment() & lazy_load_segment()

1) load_segment()
์œ„์—์„œ load_segment๊ฐ€ ์ž ๊น ๋‚˜์™”๋Š”๋ฐ, ํ”„๋กœ์„ธ์Šค๋ฅผ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ spt์— ์ ์žฌํ•œ๋‹ค๊ณ  ์„ค๋ช…ํ–ˆ์—ˆ๋‹ค.
์ž์„ธํžˆ ์„ค๋ช…ํ•˜๋ฉด ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋กœ๋“œํ•˜๋Š” ํ•จ์ˆ˜์ธ๋ฐ, ๊ทธ ๋‚ด์šฉ์„ ์ ์žฌํ•  page๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— vm_alloc_page_with_initializer๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์šฐ๋ฆฌ๋Š” ๋ฐ”๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜์ง€ ์•Š๊ธฐ๋กœ ํ–ˆ๋‹ค. lazy loading์„ ํ•˜๊ธฐ๋กœ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— vm_alloc_page_with_initializer๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ธ์ž๋กœ lazy_load_segment์™€ ๊ทธ๋ฅผ ์œ„ํ•œ ๋ณด์กฐ ์ธ์ž๋“ค์„ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค.

๋ณด์กฐ ์ธ์ž๋“ค์€ ํ˜„์žฌ ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ์šฐ๋ฆฌ๊ฐ€ lazy_load_segment๋ฅผ ์œ„ํ•ด ํ•„์š”ํ•œ ์ •๋ณด๋“ค์„ ์ƒ๊ฐํ•ด ๊ทธ ์ •๋ณด๋“ค์„ ํฌํ•จํ•œ ๊ตฌ์กฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๋„˜๊ฒจ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

ํ•ด๋‹น ์ •๋ณด๋“ค์€ ์–ด๋–ค๊ฒŒ ์žˆ์„๊นŒ?

  • file: ํŒŒ์ผ ๋‚ด์šฉ์ด ๋‹ด๊ธด ํŒŒ์ผ ๊ฐ์ฒด
  • ofs: ํŽ˜์ด์ง€์—์„œ ์ฝ๊ธฐ ์‹œ์ž‘ํ•  ์œ„์น˜
  • read_bytes: ํŽ˜์ด์ง€์—์„œ ์ฝ์–ด์•ผ ํ•˜๋Š” ๋ฐ”์ดํŠธ ์ˆ˜
  • zero_bytes: ํŽ˜์ด์ง€์—์„œ read_bytes๋งŒํผ ์ฝ๊ณ , ๋‚จ์€ ๊ณต๊ฐ„์„ 0์œผ๋กœ ์ฑ„์›Œ์•ผ ํ•˜๋Š” ๋ฐ”์ดํŠธ ์ˆ˜
/* lazy_load_segment๋ฅผ ์œ„ํ•œ ๋ณด์กฐ ์ธ์ž๋“ค */
struct lazy_load_arg
{
    struct file *file;   /* file ๋‚ด์šฉ์ด ๋‹ด๊ธด ํŒŒ์ผ ๊ฐ์ฒด */
    off_t ofs;           /* ํŽ˜์ด์ง€์—์„œ ์ฝ๊ธฐ ์‹œ์ž‘ํ•  ์œ„์น˜ */
    uint32_t read_bytes; /* ํŽ˜์ด์ง€์—์„œ ์ฝ์–ด์•ผ ํ•˜๋Š” ๋ฐ”์ดํŠธ ์ˆ˜ */
    uint32_t zero_bytes; /* ํŽ˜์ด์ง€์—์„œ read_bytes๋งŒํผ ์ฝ๊ณ  ๋‚จ์€ ๊ณต๊ฐ„์„ 0์œผ๋กœ ์ฑ„์›Œ์•ผ ํ•˜๋Š” ๋ฐ”์ดํŠธ ์ˆ˜ */
};

์ด๋Ÿฌํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ธฐ ์œ„ํ•œ ๊ตฌ์กฐ์ฒด์ธ lazy_load_arg๋ฅผ ์„ ์–ธํ•˜๊ณ  load_segment์—์„œ ํ•ด๋‹น ์ •๋ณด๋“ค์„ ๋‹ด์€ ๋’ค ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ์ž.

static bool
load_segment(struct file *file, off_t ofs, uint8_t *upage,
			 uint32_t read_bytes, uint32_t zero_bytes, bool writable)
{
	ASSERT((read_bytes + zero_bytes) % PGSIZE == 0);
	ASSERT(pg_ofs(upage) == 0);
	ASSERT(ofs % PGSIZE == 0);

	while (read_bytes > 0 || zero_bytes > 0)
	{
		size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
		size_t page_zero_bytes = PGSIZE - page_read_bytes;

		/* lazy_load_segment์— ์ธ์ž๋กœ ์ „๋‹ฌํ•ด ์ค„ ๋ณด์กฐ ์ธ์ž๋ฅผ ๋‹ด์•„์ฃผ๊ธฐ */
		struct lazy_load_arg *lazy_load_arg = (struct lazy_load_arg *)malloc(sizeof(struct lazy_load_arg));
		lazy_load_arg->file = file;
		lazy_load_arg->ofs = ofs;
		lazy_load_arg->read_bytes = page_read_bytes;
		lazy_load_arg->zero_bytes = page_zero_bytes;

		if (!vm_alloc_page_with_initializer(VM_ANON, upage,
											writable, lazy_load_segment, lazy_load_arg))
			return false;

		read_bytes -= page_read_bytes;
		zero_bytes -= page_zero_bytes;
		upage += PGSIZE;
		ofs += page_read_bytes;
	}
	return true;
}

์ด๋ ‡๊ฒŒ ๋˜๋ฉด page fault๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ lazy_load_segment๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋  ๊ฒƒ์ด๋‹ค.
๊ทธ๋Ÿผ ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋Š” ํ•จ์ˆ˜์ธ lazy_load_segment๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž.

2) lazy_load_segment()
์ฒซ ๋ฒˆ์งธ page fault ๋ฐœ์ƒ ์‹œ, ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™”์™€ ํ•จ๊ป˜ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋กœ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ํŽ˜์ด์ง€๋กœ ๋กœ๋“œํ•œ๋‹ค.
ํ•ด๋‹น ํ•จ์ˆ˜ ์ด์ „์— ํŽ˜์ด์ง€์™€ ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„์˜ ๋งคํ•‘์€ ์ด๋ฏธ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ ์ด๋ค„์ง€๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์—์„  ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„์— ํŒŒ์ผ ๋‚ด์šฉ์„ ๋กœ๋“œํ•˜๊ธฐ๋งŒ ํ•œ๋‹ค.

์ด์ „์— lazy_load_segment๋ฅผ ์œ„ํ•œ ๋ณด์กฐ ์ธ์ž๋“ค์„ ๋ฐ›์•„์™”๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ํ™œ์šฉํ•ด ์ฝ์–ด์˜ฌ ํŒŒ์ผ์— ๋Œ€ํ•ด ๋‚ด์šฉ์„ ๋กœ๋“œํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.

bool lazy_load_segment(struct page *page, void *aux)
{
	struct lazy_load_arg *lazy_load_arg = (struct lazy_load_arg *)aux;

	/* file์˜ offset์„ lazy_load_arg์˜ ofs์œผ๋กœ ์ด๋™์‹œํ‚ด(์ฝ๊ธฐ ์‹œ์ž‘ํ•  ์œ„์น˜) */
	file_seek(lazy_load_arg->file, lazy_load_arg->ofs);

	/* ํŽ˜์ด์ง€์— ๋งคํ•‘๋œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์˜ ํ”„๋ ˆ์ž„์— ์ด๋™์‹œํ‚จ ofs์—์„œ๋ถ€ํ„ฐ ํŒŒ์ผ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ด */
	/* ์ œ๋Œ€๋กœ ์ฝ์–ด์˜ค์ง€ ๋ชป ํ–ˆ๋‹ค๋ฉด -> ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ Free ์‹œํ‚ค๊ณ  False ๋ฐ˜ํ™˜ */
	if (file_read(lazy_load_arg->file, page->frame->kva, lazy_load_arg->read_bytes) != (int)(lazy_load_arg->read_bytes))
	{
		palloc_free_page(page->frame->kva);
		return false;
	}
	/* ๋‚จ๋Š” ๋ถ€๋ถ„์€ 0์œผ๋กœ ์ดˆ๊ธฐํ™” */
	memset(page->frame->kva + lazy_load_arg->read_bytes, 0, lazy_load_arg->zero_bytes);

	return true;
}

์ด๋ ‡๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋ถ€๋ถ„๊นŒ์ง€ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ, ์‚ฌ์‹ค ์•„์ง ์ „์ฒด์ ์ธ ๊ทธ๋ฆผ์ด ๊ทธ๋ ค์ง€์ง€ ์•Š์•˜๋‹ค.
๊ทธ๋ž˜์„œ ๊ฐ ํ•จ์ˆ˜๋“ค์ด ์–ด๋””์„œ ํ˜ธ์ถœ๋˜๊ณ , ์—ฐ๊ฒฐ๋˜๋Š”์ง€ ํŒ€์›์˜ ๋„์›€์„ ๋ฐ›์•„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •๋ฆฌ๋ฅผ ํ•ด๋ดค๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๋‹ค๋ฃจ์ง€ ์•Š์€ ๋ถ€๋ถ„์ด ๋ณด์ผ ๊ฒƒ์ด๋‹ค. setup_stack()?


๐Ÿ› ๏ธ setup_stack()

ํ”„๋กœ์„ธ์Šค๋ฅผ ๋กœ๋”ฉํ•  ๋•Œ, ์ฆ‰ ์‹คํ–‰ํ•  ๋•Œ load ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜๋กœ ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋œ๋‹ค.
setup_stack()์€ stack์— ์ดˆ๊ธฐ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
์ด ๋ง์€, ์ฒซ ๋ฒˆ์งธ ์Šคํƒ ํŽ˜์ด์ง€๋ฅผ Lazy Loading์œผ๋กœ ๋กœ๋“œํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์–ด์ฐจํ”ผ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋  ๋•Œ setup_stack()์„ ํ˜ธ์ถœํ•˜๊ณ  ๋‚˜์„œ ์ปค๋งจ๋“œ ๋ผ์ธ์˜ ์ธ์ž๋“ค ์Šคํƒ์— ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ์ฃผ์†Œ์— ๋ฐ”๋กœ ์ ‘๊ทผํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
๊ทธ๋Ÿฌ๋‹ˆ๊นŒ page fault๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  lazy loadingํ•˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„์„ ํ• ๋‹น ๋ฐ›์•„ ํŽ˜์ด์ง€์™€ ๋งคํ•‘ํ•ด์ค€๋‹ค.

์ฃผ์˜ํ•  ์ : ์Šคํƒ์€ ์•„๋ž˜๋กœ ์„ฑ์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์Šคํƒ์˜ ์‹œ์ž‘์ (USER_STACK)์—์„œ PGSIZE๋งŒํผ '์•„๋ž˜'๋กœ ๋‚ด๋ฆฐ ์ง€์ ์—์„œ ์ƒ์„ฑํ•œ๋‹ค.

๋˜ํ•œ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹น๋ฐ›์„ ๋•Œ ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ์Šคํƒ์˜ ํŽ˜์ด์ง€์ž„์„ ํ‘œ์‹œํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์กฐ ๋งˆ์ปค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹น ๋ฐ›์„ ๋•Œ ํŽ˜์ด์ง€์˜ ํƒ€์ž…๊ณผ ํ•จ๊ป˜ VM_MARKER_0์„ ์‚ฌ์šฉํ•ด ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.
๋‚˜์ค‘์— ์ด ๋งˆ์ปค๋ฅผ ํ†ตํ•ด ์Šคํƒ์˜ ํŽ˜์ด์ง€์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

ํ• ๋‹น๋ฐ›์€ ํŽ˜์ด์ง€์— ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„์„ ๋งคํ•‘ํ•˜๋Š”๋ฐ ์„ฑ๊ณตํ–ˆ๋‹ค๋ฉด ์Šคํƒ ํฌ์ธํ„ฐ(rsp)๋ฅผ USER_STACK์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.
์•ž์œผ๋กœ ์ด rsp๋ถ€ํ„ฐ ์ธ์ž๋“ค์„ pushํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

/* ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋  ๋•Œ load()์—์„œ ํ˜ธ์ถœ, STACK์˜ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜ */
static bool
setup_stack(struct intr_frame *if_)
{
	bool success = false;
	/* ์Šคํƒ์€ ์•„๋ž˜๋กœ ์ปค์ง€๋‹ˆ๊นŒ, ์Šคํƒ ์‹œ์ž‘์  USER_STACK์—์„œ PGSIZE๋งŒํผ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ„ ์ง€์ ์—์„œ ํŽ˜์ด์ง€ ์ƒ์„ฑ = stack_bottom */
	void *stack_bottom = (void *)(((uint8_t *)USER_STACK) - PGSIZE);

	/* stack_bottm์— ์Šคํƒ ๋งคํ•‘ ํ›„ ํŽ˜์ด์ง€ ์š”์ฒญ */
	/* ์„ฑ๊ณต ์‹œ, rsp๋ฅผ ๊ทธ์— ๋งž๊ฒŒ ์„ค์ • */
	/* ๋˜ํ•œ ํŽ˜์ด์ง€๊ฐ€ ์Šคํƒ์— ์žˆ์Œ์„ ํ‘œ์‹œํ•ด์•ผ ํ•จ */

	/* stack_bottom์— ํŽ˜์ด์ง€ ํ• ๋‹น ๋ฐ›์Œ (์Šคํƒ์€ ์•„๋ž˜๋กœ ์ปค์ง€๋‹ˆ๊นŒ) */
	/* VM_MARKER_0: ์Šคํƒ์ด ์ €์žฅ๋œ ๋ฉ”๋ชจ๋ฆฌ ํŽ˜์ด์ง€ ์‹๋ณ„ */
	if (vm_alloc_page(VM_ANON | VM_MARKER_0, stack_bottom, 1))
	{
		/* ํ• ๋‹น๋ฐ›์€ ํŽ˜์ด์ง€์— ๋ฌผ๋ฆฌ ํ”„๋ ˆ์ž„ ๋งคํ•‘ */
		success = vm_claim_page(stack_bottom);
		if (success)
		{
			/* rsp ๋ณ€๊ฒฝ */
			if_->rsp = USER_STACK;
			thread_current()->stack_bottom = stack_bottom;
		}
	}

	return success;
}

์—ฌ๊ธฐ๊นŒ์ง€ lazy loading์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•จ์œผ๋กœ์จ page fault๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.
์ด์ œ page fault๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ง€๊ธˆ๊นŒ์ง€ ๊ตฌํ˜„ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก handler๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

ํ•ด๋‹น ๋ถ€๋ถ„๋ถ€ํ„ฐ๋Š” ๋‹ค์Œ ๊ธ€์—์„œ ์ •๋ฆฌํ•ด์•ผ๊ฒ ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด