diff --git a/src/vm/frame.c b/src/vm/frame.c index 98339f8..bc961a5 100644 --- a/src/vm/frame.c +++ b/src/vm/frame.c @@ -32,11 +32,18 @@ struct list_elem *next_victim = NULL; /* Protects access to 'lru_list'. */ struct lock lru_lock; +struct frame_owner +{ + struct thread *thread; /* Pointer to the thread referenced by the owner.*/ + struct list_elem elem; /* List element for the owners list in + frame_metadata. */ +}; + struct frame_metadata { void *frame; /* The kernel virtual address holding the frame. */ void *upage; /* The user virtual address pointing to the frame. */ - struct thread *owner; /* Pointer to the thread that owns the frame. */ + struct list owners; /* List of owners of the frame. */ struct hash_elem hash_elem; /* Tracks the position of the frame metadata within 'frame_table', whose key is the kernel virtual address of the frame. */ @@ -96,12 +103,26 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner) /* Mark page as 'not present' and flag the page directory as having been modified *before* eviction begins to prevent the owner of the victim page from accessing/modifying it mid-eviction. */ - pagedir_clear_page (victim->owner->pagedir, victim->upage); + struct list_elem *e; + for (e = list_begin (&victim->owners); e != list_end (&victim->owners); + e = list_next (e)) + { + struct frame_owner *frame_owner + = list_entry (e, struct frame_owner, elem); + pagedir_clear_page (frame_owner->thread->pagedir, victim->upage); + } // TODO: Lock PTE of victim page for victim process. size_t swap_slot = swap_out (victim->frame); - page_set_swap (victim->owner, victim->upage, swap_slot); + for (e = list_begin (&victim->owners); e != list_end (&victim->owners); + e = list_next (e)) + { + struct frame_owner *frame_owner + = list_entry (e, struct frame_owner, elem); + page_set_swap (frame_owner->thread->pagedir, victim->upage, + swap_slot); + } /* If zero flag is set, zero out the victim page. */ if (flags & PAL_ZERO) @@ -142,7 +163,10 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner) } frame_metadata->upage = upage; - frame_metadata->owner = owner; + list_init (&frame_metadata->owners); + struct frame_owner *frame_owner = malloc (sizeof (struct frame_owner)); + frame_owner->thread = owner; + list_push_back (&frame_metadata->owners, &frame_owner->elem); lock_release (&lru_lock); return frame_metadata->frame; @@ -190,24 +214,33 @@ frame_free (void *frame) static struct frame_metadata * get_victim (void) { - struct list_elem *e = next_victim; + struct list_elem *ve = next_victim; struct frame_metadata *frame_metadata; - uint32_t *pd; - void *upage; - for (;;) + bool found = false; + while (!found) { - frame_metadata = list_entry (e, struct frame_metadata, list_elem); - pd = frame_metadata->owner->pagedir; - upage = frame_metadata->upage; - e = lru_next (e); + frame_metadata = list_entry (ve, struct frame_metadata, list_elem); + void *upage = frame_metadata->upage; + ve = lru_next (ve); - if (!pagedir_is_accessed (pd, upage)) - break; - - pagedir_set_accessed (pd, upage, false); + /* Check whether any owner thread has accessed the page. */ + found = true; + struct list_elem *oe; + for (oe = list_begin (&frame_metadata->owners); + oe != list_end (&frame_metadata->owners); oe = list_next (oe)) + { + struct frame_owner *frame_owner + = list_entry (oe, struct frame_owner, elem); + uint32_t *pd = frame_owner->thread->pagedir; + if (pagedir_is_accessed (pd, upage)) + { + found = false; + pagedir_set_accessed (pd, upage, false); + } + } } - next_victim = e; + next_victim = ve; return frame_metadata; }