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 *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 thread *owner; /* Pointer to the thread that owns the frame. */
|
||||||
|
bool pinned;
|
||||||
|
|
||||||
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. */
|
||||||
@@ -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_next (struct list_elem *e);
|
||||||
static struct list_elem *lru_prev (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);
|
static struct frame_metadata *get_victim (void);
|
||||||
|
|
||||||
/* Initialize the frame system by initializing the frame (hash) table with
|
/* 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->upage = upage;
|
||||||
frame_metadata->owner = owner;
|
frame_metadata->owner = owner;
|
||||||
|
frame_metadata->pinned = false;
|
||||||
lock_release (&lru_lock);
|
lock_release (&lru_lock);
|
||||||
|
|
||||||
return frame_metadata->frame;
|
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
|
/* 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
|
frame table as well as lru_list, and freeing the underlying page
|
||||||
memory & metadata struct. Panics if the frame isn't active in memory. */
|
memory & metadata struct. Panics if the frame isn't active in memory. */
|
||||||
@@ -201,6 +227,10 @@ get_victim (void)
|
|||||||
upage = frame_metadata->upage;
|
upage = frame_metadata->upage;
|
||||||
e = lru_next (e);
|
e = lru_next (e);
|
||||||
|
|
||||||
|
/* Skip pinned frames */
|
||||||
|
if (frame_metadata->pinned)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!pagedir_is_accessed (pd, upage))
|
if (!pagedir_is_accessed (pd, upage))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -228,14 +258,26 @@ frame_metadata_hash (const struct hash_elem *e, void *aux UNUSED)
|
|||||||
bool
|
bool
|
||||||
frame_metadata_less (const struct hash_elem *a_, const struct hash_elem *b_,
|
frame_metadata_less (const struct hash_elem *a_, const struct hash_elem *b_,
|
||||||
void *aux UNUSED)
|
void *aux UNUSED)
|
||||||
{
|
{
|
||||||
struct frame_metadata *a =
|
struct frame_metadata *a =
|
||||||
hash_entry (a_, struct frame_metadata, hash_elem);
|
hash_entry (a_, struct frame_metadata, hash_elem);
|
||||||
struct frame_metadata *b =
|
struct frame_metadata *b =
|
||||||
hash_entry (b_, struct frame_metadata, hash_elem);
|
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
|
/* Returns the next recently used element after the one provided, which
|
||||||
is achieved by iterating through lru_list like a circular queue
|
is achieved by iterating through lru_list like a circular queue
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
void frame_init (void);
|
void frame_init (void);
|
||||||
void *frame_alloc (enum palloc_flags, void *, struct thread *);
|
void *frame_alloc (enum palloc_flags, void *, struct thread *);
|
||||||
|
void frame_pin (void *frame);
|
||||||
|
void frame_unpin (void *frame);
|
||||||
void frame_free (void *frame);
|
void frame_free (void *frame);
|
||||||
|
|
||||||
#endif /* vm/frame.h */
|
#endif /* vm/frame.h */
|
||||||
|
|||||||
Reference in New Issue
Block a user