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