feat: allow frames to have multiple owner threads.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user