feat: allow frames to have multiple owner threads.

This commit is contained in:
2024-12-05 14:44:59 +00:00
parent 598189fddb
commit 71d91994c1

View File

@@ -32,11 +32,18 @@ struct list_elem *next_victim = NULL;
/* Protects access to 'lru_list'. */ /* Protects access to 'lru_list'. */
struct lock lru_lock; 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 struct frame_metadata
{ {
void *frame; /* The kernel virtual address holding the frame. */ void *frame; /* The kernel virtual address holding the frame. */
void *upage; /* The user virtual address pointing to 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 struct hash_elem hash_elem; /* Tracks the position of the frame metadata
within 'frame_table', whose key is the within 'frame_table', whose key is the
kernel virtual address of the frame. */ 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 /* Mark page as 'not present' and flag the page directory as having
been modified *before* eviction begins to prevent the owner of the been modified *before* eviction begins to prevent the owner of the
victim page from accessing/modifying it mid-eviction. */ 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. // TODO: Lock PTE of victim page for victim process.
size_t swap_slot = swap_out (victim->frame); 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 zero flag is set, zero out the victim page. */
if (flags & PAL_ZERO) 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->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); lock_release (&lru_lock);
return frame_metadata->frame; return frame_metadata->frame;
@@ -190,24 +214,33 @@ frame_free (void *frame)
static struct frame_metadata * static struct frame_metadata *
get_victim (void) get_victim (void)
{ {
struct list_elem *e = next_victim; struct list_elem *ve = next_victim;
struct frame_metadata *frame_metadata; struct frame_metadata *frame_metadata;
uint32_t *pd; bool found = false;
void *upage; while (!found)
for (;;)
{ {
frame_metadata = list_entry (e, struct frame_metadata, list_elem); frame_metadata = list_entry (ve, struct frame_metadata, list_elem);
pd = frame_metadata->owner->pagedir; void *upage = frame_metadata->upage;
upage = frame_metadata->upage; ve = lru_next (ve);
e = lru_next (e);
if (!pagedir_is_accessed (pd, upage)) /* Check whether any owner thread has accessed the page. */
break; found = true;
struct list_elem *oe;
pagedir_set_accessed (pd, upage, false); 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; return frame_metadata;
} }