2024.05.19 - [๐งญ KAIST JUNGLE/โญ Pintos] - [PintOS] Virtual Memory - ๋ค์ด๊ฐ๊ธฐ(Project 3, TIL)
[PintOS] Virtual Memory - ๋ค์ด๊ฐ๊ธฐ(Project 3, TIL)
Virtual Memory๋ ์ ํ์ํ ๊น?๊ฐ์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋ ๊ฒฝ์ฐ๋ฅผ ์์ํด ๋ณด์. ์์ ์ฌ์ ํ๋ ์ด์ด์ ๊ฒ์ ํ๋ก์ธ์ค์์ ๊ฐ์ ๋ฌผ๋ฆฌ์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์์ ๊ฐ๊ฐ ์ฌ์ ์๊ฐ๊ณผ ์บ๋ฆญํฐ์ ์ฒด๋ ฅ ์ ๋ณด๊ฐ ๋ด๊ธฐ๋ฉด ์ด๋ป๊ฒ
seungineer.tistory.com
์งํ ์ํฉ
โ Memory Management
โ Anonymous Page
โ Stack Growth
โ Memory Mapped Files
โ Swap In/Out
Project3์ Virtual Memory๋ฅผ ๋ชจ๋ ๊ตฌํํ ํ์ ๋์ mechanism
Project2๊น์ง ๊ตฌํ๋ ํ์ฌ Pintos์ ๋ชจ์ต์ ์ด๋จ๊น?
๊ตฌํ ์ , ํ ์ด๋ฏธ์ง๋ฅผ ๋น๊ตํด ๋ดค์ ๋ ๊ตฌํํด์ผ ํ ๊ฒ์ด ์ง์ ์ ์ผ๋ก ๋ณด์ธ๋ค. Page table์ ํ์ฅ๊ณผ hash, bucket์ ์ถ๊ฐ์ด๋ค.
Implement Supplemental Page Table
๊ตฌํ
ํ์ฌ Pintos์์ VA๋ฅผ PA๋ก ๋งคํํ๋ ๊ฒ์ ๊ด๋ฆฌํ๋ pml4๋ก๋ ๋ถ์กฑํ๋ค. Page fault๊ฐ ๋ฐ์ํ์ ๋ ์ฒ๋ฆฌํ page์ ๋ํ ๋ณด์ถฉ์ ์ธ ์ค๋ช ์ด ํ์ํ๊ธฐ์ Supplemental Page Table(SPT)์ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค. Pintos Instruction์ ์ฐธ๊ณ ํ๋ฉด, SPT ์ค๊ณ ํ ์ด๋ฅผ ํ ๋๋ก ํจ์ ์ธ ๊ฐ๋ฅผ ๊ตฌํํด์ผ ํ๋ค.
void supplemental_page_table_init (struct supplemental_page_table *spt);
struct page *spt_find_page (struct supplemental_page_table *spt, void *va);
bool spt_insert_page (struct supplemental_page_table *spt, struct page *page);
- supplemental_page_table_init : spt ๊ตฌ์ฑ ์์๋ฅผ ์ด๊ธฐํํ๋ ํจ์๋ก initd(), __do_fork() ํจ์์์ ํธ์ถ๋จ
- *spt_find_page : ์ธ์์ spt์์ va์ ๋์๋๋ 'page ๊ตฌ์กฐ์ฒด'๋ฅผ ์ฐพ์์ ๋ฐํํจ
- spt_insert_page : ์ธ์๋ก์ spt์ page ๊ตฌ์กฐ์ฒด๋ฅผ ์ฝ์ ํจ
/* Initialize new supplemental page table */
void supplemental_page_table_init(struct supplemental_page_table *spt UNUSED) {
hash_init(spt, page_hash, page_less, NULL);
}
struct page
*spt_find_page(struct supplemental_page_table *spt UNUSED, void *va UNUSED) {
struct page *page = NULL;
page = malloc(sizeof(struct page));
struct hash_elem *hash_element;
page->va = pg_round_down(va); // ํ์ด์ง๋ฅผ ์ฐพ์๋๋ rounddown -> up์ ํ ๋นํฌ๊ธฐ ๋ง์ถ๋
hash_element = hash_find(spt, &page->hash_elem);
free(page); // ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ ํด์
if (hash_element) {
return hash_entry(hash_element, struct page, hash_elem); // hash_entry๋ก hash_elem์ page๋ก ๋ณํ
}
return NULL;
}
/* Insert PAGE into spt with validation. */
bool spt_insert_page(struct supplemental_page_table *spt UNUSED,
struct page *page UNUSED) {
int succ = false;
// REVIEW INSERT_PAGE
if (hash_insert(&spt->hash_page, &page->hash_elem) == NULL) { // ์ ์ถ๊ฐ๋์์ผ๋ฉด NULL๋ฐํ
succ = true;
}
return succ;
}
ํจ์ ๋ด์ hash๊ฐ ๋ฌ๊ธ์์ด ๋ณด์ผ ์ ์์ง๋ง, ์์ ๊ตฌํ ํ ๋ฉ์ปค๋์ฆ ์ค๋ช ์ด๋ฏธ์ง๋ฅผ ์์ธํ ๋ณด๋ฉด hash๋ฅผ ํตํด์ vm_entry๊น์ง ๊ด๋ฆฌ๋๋ ๊ฒ์ ์ ์ ์๋ค. ๋๋ถ์ด Pintos์์๋ chaining hash table์ ์ ๊ณตํ๋ค(lib/kernel/hash.* ์ฐธ๊ณ ). ์ฌ๋ด์ผ๋ก ๋ฆฌ๋ ์ค์์๋ Red-Black tree ๊ตฌ์กฐ๋ก vm_entry๋ฅผ ๊ด๋ฆฌํ๋ค.
Frame Management
์ด์ Physical Memory์๋ Frame์ด๋ผ๋ ๋จ์๋ก ๊ตฌ๋ถ๋์ด ๊ด๋ฆฌ๋๋ค. frame ์ ์ฉ์ ์ํด struct frame์ kva(Kernel Virtual Address), page ๊ตฌ์กฐ์ฒด๋ฅผ ๋ด์ ์ ์๋๋ก ๊ตฌํํ๋ค. Instruction์๋ ์์ง๋ง frame๋ page์ ๋ง์ฐฌ๊ฐ์ง ๊ตฌ์กฐ๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด frame_elem๋ ์ถ๊ฐํ ํ์๊ฐ ์๋ค.
/* The representation of "frame" */
struct frame {
void *kva;
struct page *page;
struct list_elem *frame_elem;
};
frame ๊ด๋ จํ ๊ตฌํํด์ผ ํ๋ ํจ์
static struct frame *vm_get_frame (void);
bool vm_do_claim_page (struct page *page);
bool vm_claim_page (void *va);
์ ์ธ ํจ์(์ฌ์ค ๋ ๊ฐ์ ๊ฐ๊น๋ค ใ )๋ฅผ ๊ตฌํํ ๋ ์ฐ๋ฆฌ ์กฐ๋ vm_do_claim_page()์์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
static bool
vm_do_claim_page(struct page *page) { // va ํ์ด์ง๋ฅผ๋ง๋ค๊ณ ํ๋ ์์ ํ ๋นํ ํ์ด์ง
struct frame *frame = vm_get_frame();
/* Set links */
frame->page = page;
page->frame = frame;
struct thread *current = thread_current();
// bool writable = is_writable(current->pml4); <- ๊ธฐ์กด
// pml4_set_page(current->pml4, page->va, frame->kva, writable); <- ๊ธฐ์กด, ์๋๊ฐ ์์
pml4_set_page(current->pml4, page->va, frame->kva, page->writable);
return swap_in(page, frame->kva);
}
์ฃผ์ ์ฒ๋ฆฌ๋ ๊ธฐ์กด ์ฝ๋๋ฅผ ๋ณด๋ฉด, is_writable() ํจ์๋ฅผ ์ฌ์ฉํด์ ํ์ฌ thread์ pml4๊ฐ ๊ฐ๋ฆฌํค๋ PA์ writable ์ ๋ฌด๋ฅผ ํ์ธํด ์ค๋ค. ์ผํ ๋ณด๋ฉด ํฉ๋นํ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง ์ด๋ ๋ง๋ ์ ๋๋ ๊ฒ์ด๋ค(ใ ใ ). ํจ์๋ช ๋๋ก '์์ฒญํ ํ์ด์ง'์ write ์ฌ๋ถ๋ฅผ ๋ด์ผ ํ๋๋ฐ ํ์ฌ thread ์ ๋ณด๋ฅผ ๋ณด๊ธฐ ๋๋ฌธ์ด๋ค. ์ง๊ธ ์๊ฐํด ๋ณด๋ฉด ๋งค์ฐ ์ฌ์ด ์ค๋ต์ธ๋ฐ, ์๋ฌ๋ฅผ ์ ๋ฐํ ์ฝ๋์์ ๋งค์ฐ ๋ฉ๋ฆฌ ๋จ์ด์ง ๋ฐ์ KERNEL PANIC์ด ๋ฐ์ํ๊ธฐ์ ๋๋ฒ๊น ์ ์ด๋ ค์์ด ์ปธ๋ค.
์์ ํ ์ฝ๋๋ฅผ ๋ณด๋ฉด ํ ๋นํ๊ณ ์ ํ๋ page์ writable field๋ก write ์ฌ๋ถ๋ฅผ ํ์ธํ๋ค. ํจ์๋ช ๊ณผ๋ ์ ํํ ์ผ์นํ๋ ๊ฒ์ ์ ์ ์๋ค.
์ ๋ ์์ฌํด, race condition ๐
make check ํ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ๋๋ง๋ค PASS/FAIL์ด ์ค๋ฝ๊ฐ๋ฝํ๋ ํ ์คํธ ์ผ์ด์ค๊ฐ ์์๋ค(์ฐ๋ฆฌ ํ์ ๊ฒฝ์ฐ syn-read....). ์ค๋ฝ๊ฐ๋ฝํ ๋ ๊ฐ์ฅ ์ฝ๊ฒ ์์ฌํ ์ ์๋ ๊ฒ race condition์ด๋ค. ์๋ ์ฝ๋์ ๊ฐ์ด file_write(file ,..., size) ํจ์๊ฐ ์คํ๋ ๋, ๋ ๊ฐ์ thread์์ ๋์์ ๊ฐ์ ํ์ผ์ write๋ฅผ ์๋ํ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด filesys_lock์ ์ฌ์ฉํ๋ค.
์ด๋ ๊ฒ lock์ ๊ฑด๋ค๊ณ ํ๋ค lock์ ๊ฑธ๊ธฐ ์ ๋ค๋ฅธ ์ฝ๋์์ write ๋ถ๋ถ์ ์๋ชป ์์ ํ๋ค๋ฉด, ์ด๋ ๊ฒ lock์ ๊ฑธ์ด์ค๋ ์๋ฏธ๊ฐ ์๋ค(!..). ๊ทธ๋์ race condition ์ก๊ธฐ๊ฐ ์์ฒญ ์ด๋ ค์ ๋ค.
int write(int fd, const void *buffer, unsigned size)
{
check_address(buffer);
int bytes_write = 0;
if (fd == STDOUT_FILENO)
{
putbuf(buffer, size);
bytes_write = size;
}
else
{
if (fd < 2)
return -1;
struct file *file = process_get_file(fd);
if (file == NULL)
return -1;
lock_acquire(&filesys_lock); // race condition ๋ฐฉ์ง
bytes_write = file_write(file, buffer, size);
lock_release(&filesys_lock); // race condition ๋ฐฉ์ง
}
return bytes_write;
}
์ด ์ธ์๋ ๋ฌด์ํ ๋ง์ race condition ๋ฐ์ ๊ฐ๋ฅ ์์น์ lock_acquire(), lock_release()๋ฅผ ํด์ฃผ์๋ค.
Pintos demand paging ์ผ๋ถ ๊ตฌํ ๊ณผ์
Pintos ์์ ํจ์ ํ๋ฆ์ ์๋์ Proj3 ์ค๊ฐ๋ฐํ(WIL) ์๋ฃ๋ฅผ ํตํด ํ์ธํ ์ ์๋ค.
'๐งญ KAIST JUNGLE > Pintos' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[PintOS] Virtual Memory - Final (Project 3, WIL) (0) | 2024.05.28 |
---|---|
[PintOS] Virtual Memory - ๋ค์ด๊ฐ๊ธฐ(Project 3, TIL) (0) | 2024.05.19 |
[PintOS] User Program - System Call2 (Project 2, TIL) (0) | 2024.05.14 |
[PintOS] User Program - System Call (Project 2, TIL) (1) | 2024.05.08 |
[PintOS] User Program - Arguments parsing (Project 2, TIL) (0) | 2024.05.06 |