From 2ab4e9a7751d9c659451b30ddb1007a7c881494b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=B5=E1=86=B7=E1=84=92=E1=85=A7=E1=86=BC?= =?UTF-8?q?=E1=84=8C=E1=85=AE=E1=86=AB?= <> Date: Fri, 28 Nov 2025 21:54:58 +0900 Subject: [PATCH] =?UTF-8?q?[HJ]=20feat=20:=20SPT=20=EB=B0=8F=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=EB=A6=AC=ED=8B=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pintos/include/lib/kernel/hash.h | 66 +++++----- pintos/include/vm/vm.h | 129 +++++++++--------- pintos/vm/vm.c | 219 +++++++++++++++---------------- 3 files changed, 204 insertions(+), 210 deletions(-) diff --git a/pintos/include/lib/kernel/hash.h b/pintos/include/lib/kernel/hash.h index a26fdee..933fe6c 100644 --- a/pintos/include/lib/kernel/hash.h +++ b/pintos/include/lib/kernel/hash.h @@ -23,11 +23,12 @@ #include #include #include + #include "list.h" /* Hash element. */ struct hash_elem { - struct list_elem list_elem; + struct list_elem list_elem; }; /* Converts pointer to hash element HASH_ELEM into a pointer to @@ -35,66 +36,63 @@ struct hash_elem { * name of the outer structure STRUCT and the member name MEMBER * of the hash element. See the big comment at the top of the * file for an example. */ -#define hash_entry(HASH_ELEM, STRUCT, MEMBER) \ - ((STRUCT *) ((uint8_t *) &(HASH_ELEM)->list_elem \ - - offsetof (STRUCT, MEMBER.list_elem))) +#define hash_entry(HASH_ELEM, STRUCT, MEMBER) \ + ((STRUCT*)((uint8_t*)&(HASH_ELEM)->list_elem - offsetof(STRUCT, MEMBER.list_elem))) /* Computes and returns the hash value for hash element E, given * auxiliary data AUX. */ -typedef uint64_t hash_hash_func (const struct hash_elem *e, void *aux); +typedef uint64_t hash_hash_func(const struct hash_elem* e, void* aux); /* Compares the value of two hash elements A and B, given * auxiliary data AUX. Returns true if A is less than B, or * false if A is greater than or equal to B. */ -typedef bool hash_less_func (const struct hash_elem *a, - const struct hash_elem *b, - void *aux); +typedef bool hash_less_func(const struct hash_elem* a, const struct hash_elem* b, void* aux); /* Performs some operation on hash element E, given auxiliary * data AUX. */ -typedef void hash_action_func (struct hash_elem *e, void *aux); +typedef void hash_action_func(struct hash_elem* e, void* aux); /* Hash table. */ struct hash { - size_t elem_cnt; /* Number of elements in table. */ - size_t bucket_cnt; /* Number of buckets, a power of 2. */ - struct list *buckets; /* Array of `bucket_cnt' lists. */ - hash_hash_func *hash; /* Hash function. */ - hash_less_func *less; /* Comparison function. */ - void *aux; /* Auxiliary data for `hash' and `less'. */ + size_t elem_cnt; /* Number of elements in table. */ + size_t bucket_cnt; /* Number of buckets, a power of 2. */ + struct list* buckets; /* Array of `bucket_cnt' lists. */ + hash_hash_func* hash; /* Hash function. */ + hash_less_func* less; /* Comparison function. */ + void* aux; /* Auxiliary data for `hash' and `less'. */ }; /* A hash table iterator. */ struct hash_iterator { - struct hash *hash; /* The hash table. */ - struct list *bucket; /* Current bucket. */ - struct hash_elem *elem; /* Current hash element in current bucket. */ + struct hash* hash; /* The hash table. */ + struct list* bucket; /* Current bucket. */ + struct hash_elem* elem; /* Current hash element in current bucket. */ }; /* Basic life cycle. */ -bool hash_init (struct hash *, hash_hash_func *, hash_less_func *, void *aux); -void hash_clear (struct hash *, hash_action_func *); -void hash_destroy (struct hash *, hash_action_func *); +bool hash_init(struct hash*, hash_hash_func*, hash_less_func*, void* aux); +void hash_clear(struct hash*, hash_action_func*); +void hash_destroy(struct hash*, hash_action_func*); /* Search, insertion, deletion. */ -struct hash_elem *hash_insert (struct hash *, struct hash_elem *); -struct hash_elem *hash_replace (struct hash *, struct hash_elem *); -struct hash_elem *hash_find (struct hash *, struct hash_elem *); -struct hash_elem *hash_delete (struct hash *, struct hash_elem *); +struct hash_elem* hash_insert(struct hash*, struct hash_elem*); +struct hash_elem* hash_replace(struct hash*, struct hash_elem*); +struct hash_elem* hash_find(struct hash*, struct hash_elem*); +struct hash_elem* hash_delete(struct hash*, struct hash_elem*); /* Iteration. */ -void hash_apply (struct hash *, hash_action_func *); -void hash_first (struct hash_iterator *, struct hash *); -struct hash_elem *hash_next (struct hash_iterator *); -struct hash_elem *hash_cur (struct hash_iterator *); +void hash_apply(struct hash*, hash_action_func*); +void hash_first(struct hash_iterator*, struct hash*); +struct hash_elem* hash_next(struct hash_iterator*); +struct hash_elem* hash_cur(struct hash_iterator*); /* Information. */ -size_t hash_size (struct hash *); -bool hash_empty (struct hash *); +size_t hash_size(struct hash*); +bool hash_empty(struct hash*); /* Sample hash functions. */ -uint64_t hash_bytes (const void *, size_t); -uint64_t hash_string (const char *); -uint64_t hash_int (int); +uint64_t hash_bytes(const void*, size_t); +uint64_t hash_string(const char*); +uint64_t hash_int(int); #endif /* lib/kernel/hash.h */ diff --git a/pintos/include/vm/vm.h b/pintos/include/vm/vm.h index e061b73..64da674 100644 --- a/pintos/include/vm/vm.h +++ b/pintos/include/vm/vm.h @@ -1,32 +1,35 @@ #ifndef VM_VM_H #define VM_VM_H #include + #include "threads/palloc.h" enum vm_type { - /* page not initialized */ - VM_UNINIT = 0, - /* page not related to the file, aka anonymous page */ - VM_ANON = 1, - /* page that realated to the file */ - VM_FILE = 2, - /* page that hold the page cache, for project 4 */ - VM_PAGE_CACHE = 3, - - /* Bit flags to store state */ - - /* Auxillary bit flag marker for store information. You can add more - * markers, until the value is fit in the int. */ - VM_MARKER_0 = (1 << 3), - VM_MARKER_1 = (1 << 4), - - /* DO NOT EXCEED THIS VALUE. */ - VM_MARKER_END = (1 << 31), + /* page not initialized */ + VM_UNINIT = 0, + /* page not related to the file, aka anonymous page */ + VM_ANON = 1, + /* page that realated to the file */ + VM_FILE = 2, + /* page that hold the page cache, for project 4 */ + VM_PAGE_CACHE = 3, + + /* Bit flags to store state */ + + /* Auxillary bit flag marker for store information. You can add more + * markers, until the value is fit in the int. */ + VM_MARKER_0 = (1 << 3), + VM_MARKER_1 = (1 << 4), + + /* DO NOT EXCEED THIS VALUE. */ + VM_MARKER_END = (1 << 31), }; -#include "vm/uninit.h" +#include // SPT 구조체에 pages 추가를 위한 헤더 파일 + #include "vm/anon.h" #include "vm/file.h" +#include "vm/uninit.h" #ifdef EFILESYS #include "filesys/page_cache.h" #endif @@ -41,28 +44,31 @@ struct thread; * uninit_page, file_page, anon_page, and page cache (project4). * DO NOT REMOVE/MODIFY PREDEFINED MEMBER OF THIS STRUCTURE. */ struct page { - const struct page_operations *operations; - void *va; /* Address in terms of user space */ - struct frame *frame; /* Back reference for frame */ - - /* Your implementation */ - - /* 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; + 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 hash_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; + struct page_cache page_cache; #endif - }; + }; }; /* The representation of "frame" */ struct frame { - void *kva; - struct page *page; + void* kva; + struct page* page; }; /* The function table for page operations. @@ -70,43 +76,42 @@ struct frame { * Put the table of "method" into the struct's member, and * call it whenever you needed. */ struct page_operations { - bool (*swap_in) (struct page *, void *); - bool (*swap_out) (struct page *); - void (*destroy) (struct page *); - enum vm_type type; + bool (*swap_in)(struct page*, void*); + bool (*swap_out)(struct page*); + void (*destroy)(struct page*); + enum vm_type type; }; -#define swap_in(page, v) (page)->operations->swap_in ((page), v) -#define swap_out(page) (page)->operations->swap_out (page) +#define swap_in(page, v) (page)->operations->swap_in((page), v) +#define swap_out(page) (page)->operations->swap_out(page) #define destroy(page) \ - if ((page)->operations->destroy) (page)->operations->destroy (page) + if ((page)->operations->destroy) (page)->operations->destroy(page) /* 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 pages; }; #include "threads/thread.h" -void supplemental_page_table_init (struct supplemental_page_table *spt); -bool supplemental_page_table_copy (struct supplemental_page_table *dst, - struct supplemental_page_table *src); -void supplemental_page_table_kill (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); -void spt_remove_page (struct supplemental_page_table *spt, struct page *page); - -void vm_init (void); -bool vm_try_handle_fault (struct intr_frame *f, void *addr, bool user, - bool write, bool not_present); +void supplemental_page_table_init(struct supplemental_page_table* spt); +bool supplemental_page_table_copy(struct supplemental_page_table* dst, + struct supplemental_page_table* src); +void supplemental_page_table_kill(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); +void spt_remove_page(struct supplemental_page_table* spt, struct page* page); + +void vm_init(void); +bool vm_try_handle_fault(struct intr_frame* f, void* addr, bool user, bool write, bool not_present); #define vm_alloc_page(type, upage, writable) \ - vm_alloc_page_with_initializer ((type), (upage), (writable), NULL, NULL) -bool vm_alloc_page_with_initializer (enum vm_type type, void *upage, - bool writable, vm_initializer *init, void *aux); -void vm_dealloc_page (struct page *page); -bool vm_claim_page (void *va); -enum vm_type page_get_type (struct page *page); - -#endif /* VM_VM_H */ + vm_alloc_page_with_initializer((type), (upage), (writable), NULL, NULL) +bool vm_alloc_page_with_initializer(enum vm_type type, void* upage, bool writable, + vm_initializer* init, void* aux); +void vm_dealloc_page(struct page* page); +bool vm_claim_page(void* va); +enum vm_type page_get_type(struct page* page); + +#endif /* VM_VM_H */ diff --git a/pintos/vm/vm.c b/pintos/vm/vm.c index 94d58f9..c22c218 100644 --- a/pintos/vm/vm.c +++ b/pintos/vm/vm.c @@ -1,190 +1,181 @@ /* vm.c: Generic interface for virtual memory objects. */ -#include "threads/malloc.h" #include "vm/vm.h" + +#include "threads/malloc.h" #include "vm/inspect.h" /* Initializes the virtual memory subsystem by invoking each subsystem's * intialize codes. */ -void -vm_init (void) { - vm_anon_init (); - vm_file_init (); -#ifdef EFILESYS /* For project 4 */ - pagecache_init (); +void vm_init(void) { + vm_anon_init(); + vm_file_init(); +#ifdef EFILESYS /* For project 4 */ + pagecache_init(); #endif - register_inspect_intr (); - /* DO NOT MODIFY UPPER LINES. */ - /* TODO: Your code goes here. */ + register_inspect_intr(); + /* DO NOT MODIFY UPPER LINES. */ + /* TODO: Your code goes here. */ } /* Get the type of the page. This function is useful if you want to know the * type of the page after it will be initialized. * This function is fully implemented now. */ -enum vm_type -page_get_type (struct page *page) { - int ty = VM_TYPE (page->operations->type); - switch (ty) { - case VM_UNINIT: - return VM_TYPE (page->uninit.type); - default: - return ty; - } +enum vm_type page_get_type(struct page* page) { + int ty = VM_TYPE(page->operations->type); + switch (ty) { + case VM_UNINIT: + return VM_TYPE(page->uninit.type); + default: + return ty; + } } -/* Helpers */ -static struct frame *vm_get_victim (void); -static bool vm_do_claim_page (struct page *page); -static struct frame *vm_evict_frame (void); +/* Helpers */ //<- 여기에 helper 함수들을 추가한다. +static struct frame* vm_get_victim(void); +static bool vm_do_claim_page(struct page* page); +static struct frame* vm_evict_frame(void); + +/* SPT 해시 테이블 보조 함수 prototype 선언 */ +unsigned page_hash(const struct hash_elem* p_, void* aux UNUSED); +bool page_less(const struct hash_elem* a_, const struct hash_elem* b_, void* aux UNUSED); /* Create the pending page object with initializer. If you want to create a * page, do not create it directly and make it through this function or * `vm_alloc_page`. */ -bool -vm_alloc_page_with_initializer (enum vm_type type, void *upage, bool writable, - vm_initializer *init, void *aux) { +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) - ASSERT (VM_TYPE(type) != VM_UNINIT) + struct supplemental_page_table* spt = &thread_current()->spt; - struct supplemental_page_table *spt = &thread_current ()->spt; + /* Check wheter the upage is already occupied or not. */ + if (spt_find_page(spt, upage) == NULL) { + /* TODO: Create the page, fetch the initialier according to the VM type, + * TODO: and then create "uninit" page struct by calling uninit_new. You + * TODO: should modify the field after calling the uninit_new. */ - /* Check wheter the upage is already occupied or not. */ - if (spt_find_page (spt, upage) == NULL) { - /* TODO: Create the page, fetch the initialier according to the VM type, - * TODO: and then create "uninit" page struct by calling uninit_new. You - * TODO: should modify the field after calling the uninit_new. */ - - /* TODO: Insert the page into the spt. */ - } + /* TODO: Insert the page into the spt. */ + } err: - return false; + return false; } -/* Find VA from spt and return page. On error, return NULL. */ -struct page * -spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) { - struct page *page = NULL; - /* TODO: Fill this function. */ +/* CPU에서 건넨 VA로 해당 데이터가 Physical Memory에 해당 Page가 존재하는지 SPT에서 찾는 메소드 */ +struct page* spt_find_page(struct supplemental_page_table* spt UNUSED, void* va UNUSED) { + struct page dummy_page; + struct hash_elem* e; + + dummy_page.va = pg_round_down(va); + + e = hash_find(&spt->pages, &dummy_page.hash_elem); + if (e == NULL) return NULL; - return page; + struct page* page = hash_entry(e, struct page, hash_elem); + + return page; } -/* Insert PAGE into spt with validation. */ -bool -spt_insert_page (struct supplemental_page_table *spt UNUSED, - struct page *page UNUSED) { - int succ = false; - /* TODO: Fill this function. */ +/* 해당 thread의 SPT에 인자로 받은 page를 SPT 테이블에 삽입 메소드*/ +bool spt_insert_page(struct supplemental_page_table* spt UNUSED, struct page* page UNUSED) { + // 성공시 NULL을 반환하는 ㅈ같은 함수 + struct hash_elem* result = hash_insert(&spt->pages, &page->hash_elem); - return succ; + return (result == NULL) ? true : false; } -void -spt_remove_page (struct supplemental_page_table *spt, struct page *page) { - vm_dealloc_page (page); - return true; +void spt_remove_page(struct supplemental_page_table* spt, struct page* page) { + vm_dealloc_page(page); + return true; } /* Get the struct frame, that will be evicted. */ -static struct frame * -vm_get_victim (void) { - struct frame *victim = NULL; - /* TODO: The policy for eviction is up to you. */ +static struct frame* vm_get_victim(void) { + struct frame* victim = NULL; + /* TODO: The policy for eviction is up to you. */ - return victim; + return victim; } /* Evict one page and return the corresponding frame. * Return NULL on error.*/ -static struct frame * -vm_evict_frame (void) { - struct frame *victim UNUSED = vm_get_victim (); - /* TODO: swap out the victim and return the evicted frame. */ +static struct frame* vm_evict_frame(void) { + struct frame* victim UNUSED = vm_get_victim(); + /* TODO: swap out the victim and return the evicted frame. */ - return NULL; + return NULL; } /* palloc() and get frame. If there is no available page, evict the page * and return it. This always return valid address. That is, if the user pool * memory is full, this function evicts the frame to get the available memory * space.*/ -static struct frame * -vm_get_frame (void) { - struct frame *frame = NULL; - /* TODO: Fill this function. */ - - ASSERT (frame != NULL); - ASSERT (frame->page == NULL); - return frame; +static struct frame* vm_get_frame(void) { + struct frame* frame = NULL; + /* TODO: Fill this function. */ + + ASSERT(frame != NULL); + ASSERT(frame->page == NULL); + return frame; } /* Growing the stack. */ -static void -vm_stack_growth (void *addr UNUSED) { -} +static void vm_stack_growth(void* addr UNUSED) {} /* Handle the fault on write_protected page */ -static bool -vm_handle_wp (struct page *page UNUSED) { -} +static bool vm_handle_wp(struct page* page UNUSED) {} /* Return true on success */ -bool -vm_try_handle_fault (struct intr_frame *f UNUSED, void *addr UNUSED, - bool user UNUSED, bool write UNUSED, bool not_present UNUSED) { - struct supplemental_page_table *spt UNUSED = &thread_current ()->spt; - struct page *page = NULL; - /* TODO: Validate the fault */ - /* TODO: Your code goes here */ - - return vm_do_claim_page (page); +bool vm_try_handle_fault(struct intr_frame* f UNUSED, void* addr UNUSED, bool user UNUSED, + bool write UNUSED, bool not_present UNUSED) { + struct supplemental_page_table* spt UNUSED = &thread_current()->spt; + struct page* page = NULL; + /* TODO: Validate the fault */ + /* TODO: Your code goes here */ + + return vm_do_claim_page(page); } /* Free the page. * DO NOT MODIFY THIS FUNCTION. */ -void -vm_dealloc_page (struct page *page) { - destroy (page); - free (page); +void vm_dealloc_page(struct page* page) { + destroy(page); + free(page); } /* Claim the page that allocate on VA. */ -bool -vm_claim_page (void *va UNUSED) { - struct page *page = NULL; - /* TODO: Fill this function */ +bool vm_claim_page(void* va UNUSED) { + struct page* page = NULL; + /* TODO: Fill this function */ - return vm_do_claim_page (page); + return vm_do_claim_page(page); } /* Claim the PAGE and set up the mmu. */ -static bool -vm_do_claim_page (struct page *page) { - struct frame *frame = vm_get_frame (); +static bool vm_do_claim_page(struct page* page) { + struct frame* frame = vm_get_frame(); - /* Set links */ - frame->page = page; - page->frame = frame; + /* Set links */ + frame->page = page; + page->frame = frame; - /* TODO: Insert page table entry to map page's VA to frame's PA. */ + /* TODO: Insert page table entry to map page's VA to frame's PA. */ - return swap_in (page, frame->kva); + return swap_in(page, frame->kva); } /* Initialize new supplemental page table */ -void -supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) { +// thread별로 SPT 초기화 메소드 +void supplemental_page_table_init(struct supplemental_page_table* spt UNUSED) { + hash_init(&spt->pages, page_hash, page_less, NULL); } /* Copy supplemental page table from src to dst */ -bool -supplemental_page_table_copy (struct supplemental_page_table *dst UNUSED, - struct supplemental_page_table *src UNUSED) { -} +bool supplemental_page_table_copy(struct supplemental_page_table* dst UNUSED, + struct supplemental_page_table* src UNUSED) {} /* Free the resource hold by the supplemental page table */ -void -supplemental_page_table_kill (struct supplemental_page_table *spt UNUSED) { - /* TODO: Destroy all the supplemental_page_table hold by thread and - * TODO: writeback all the modified contents to the storage. */ +void supplemental_page_table_kill(struct supplemental_page_table* spt UNUSED) { + /* TODO: Destroy all the supplemental_page_table hold by thread and + * TODO: writeback all the modified contents to the storage. */ }