Update frame table to add a pinned flag and protect those from being evicted
This commit is contained in:
@@ -37,6 +37,8 @@ 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. */
|
||||
bool pinned;
|
||||
|
||||
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. */
|
||||
@@ -50,6 +52,7 @@ hash_less_func frame_metadata_less;
|
||||
|
||||
static struct list_elem *lru_next (struct list_elem *e);
|
||||
static struct list_elem *lru_prev (struct list_elem *e);
|
||||
static struct frame_metadata *frame_metadata_get (void *frame);
|
||||
static struct frame_metadata *get_victim (void);
|
||||
|
||||
/* Initialize the frame system by initializing the frame (hash) table with
|
||||
@@ -143,11 +146,34 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner)
|
||||
|
||||
frame_metadata->upage = upage;
|
||||
frame_metadata->owner = owner;
|
||||
frame_metadata->pinned = false;
|
||||
lock_release (&lru_lock);
|
||||
|
||||
return frame_metadata->frame;
|
||||
}
|
||||
|
||||
void
|
||||
frame_pin (void *frame)
|
||||
{
|
||||
struct frame_metadata *frame_metadata = frame_metadata_get (frame);
|
||||
if (frame_metadata == NULL)
|
||||
PANIC ("Attempted to pin a frame at an unallocated kernel address '%p'\n",
|
||||
frame);
|
||||
|
||||
frame_metadata->pinned = true;
|
||||
}
|
||||
|
||||
void
|
||||
frame_unpin (void *frame)
|
||||
{
|
||||
struct frame_metadata *frame_metadata = frame_metadata_get (frame);
|
||||
if (frame_metadata == NULL)
|
||||
PANIC ("Attempted to unpin a frame at an unallocated kernel address '%p'\n",
|
||||
frame);
|
||||
|
||||
frame_metadata->pinned = false;
|
||||
}
|
||||
|
||||
/* Attempt to deallocate a frame for a user process by removing it from the
|
||||
frame table as well as lru_list, and freeing the underlying page
|
||||
memory & metadata struct. Panics if the frame isn't active in memory. */
|
||||
@@ -201,6 +227,10 @@ get_victim (void)
|
||||
upage = frame_metadata->upage;
|
||||
e = lru_next (e);
|
||||
|
||||
/* Skip pinned frames */
|
||||
if (frame_metadata->pinned)
|
||||
continue;
|
||||
|
||||
if (!pagedir_is_accessed (pd, upage))
|
||||
break;
|
||||
|
||||
@@ -228,14 +258,26 @@ frame_metadata_hash (const struct hash_elem *e, void *aux UNUSED)
|
||||
bool
|
||||
frame_metadata_less (const struct hash_elem *a_, const struct hash_elem *b_,
|
||||
void *aux UNUSED)
|
||||
{
|
||||
struct frame_metadata *a =
|
||||
hash_entry (a_, struct frame_metadata, hash_elem);
|
||||
struct frame_metadata *b =
|
||||
hash_entry (b_, struct frame_metadata, hash_elem);
|
||||
{
|
||||
struct frame_metadata *a =
|
||||
hash_entry (a_, struct frame_metadata, hash_elem);
|
||||
struct frame_metadata *b =
|
||||
hash_entry (b_, struct frame_metadata, hash_elem);
|
||||
|
||||
return a->frame < b->frame;
|
||||
}
|
||||
return a->frame < b->frame;
|
||||
}
|
||||
|
||||
static struct frame_metadata *
|
||||
frame_metadata_get (void *frame)
|
||||
{
|
||||
struct frame_metadata key_metadata;
|
||||
key_metadata.frame = frame;
|
||||
|
||||
struct hash_elem *e = hash_find (&frame_table, &key_metadata.hash_elem);
|
||||
if (e == NULL) return NULL;
|
||||
|
||||
return hash_entry (e, struct frame_metadata, hash_elem);
|
||||
}
|
||||
|
||||
/* Returns the next recently used element after the one provided, which
|
||||
is achieved by iterating through lru_list like a circular queue
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
void frame_init (void);
|
||||
void *frame_alloc (enum palloc_flags, void *, struct thread *);
|
||||
void frame_pin (void *frame);
|
||||
void frame_unpin (void *frame);
|
||||
void frame_free (void *frame);
|
||||
|
||||
#endif /* vm/frame.h */
|
||||
|
||||
Reference in New Issue
Block a user