fix: properly assign frame owners and deallocate in all required places
This commit is contained in:
100
src/vm/frame.c
100
src/vm/frame.c
@@ -50,6 +50,8 @@ 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 *get_victim (void);
|
||||
static void free_owners (struct list *owners);
|
||||
static struct frame_metadata *frame_metadata_find (void *frame);
|
||||
|
||||
/* Initialize the frame system by initializing the frame (hash) table with
|
||||
the frame_metadata hashing and comparison functions, as well as initializing
|
||||
@@ -95,15 +97,7 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner)
|
||||
page_insert_swapped (victim->upage, victim->frame, &victim->owners);
|
||||
|
||||
/* Free victim's owners. */
|
||||
struct list_elem *oe;
|
||||
for (oe = list_begin (&victim->owners);
|
||||
oe != list_end (&victim->owners);)
|
||||
{
|
||||
struct frame_owner *frame_owner
|
||||
= list_entry (oe, struct frame_owner, elem);
|
||||
oe = list_remove (oe);
|
||||
free (list_entry (oe, struct frame_owner, elem));
|
||||
}
|
||||
free_owners (&victim->owners);
|
||||
|
||||
/* If zero flag is set, zero out the victim page. */
|
||||
if (flags & PAL_ZERO)
|
||||
@@ -153,7 +147,6 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner)
|
||||
list_push_back (&frame_metadata->owners, &frame_owner->elem);
|
||||
frame_metadata->upage = upage;
|
||||
lock_release (&lru_lock);
|
||||
|
||||
return frame_metadata->frame;
|
||||
}
|
||||
|
||||
@@ -163,18 +156,15 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner)
|
||||
void
|
||||
frame_free (void *frame)
|
||||
{
|
||||
struct frame_metadata key_metadata;
|
||||
key_metadata.frame = frame;
|
||||
struct frame_metadata *frame_metadata = frame_metadata_find (frame);
|
||||
if (frame_metadata == NULL)
|
||||
PANIC ("Attempted to free a frame at kernel address %p, "
|
||||
"but this address is not allocated!\n",
|
||||
frame);
|
||||
|
||||
struct hash_elem *e =
|
||||
hash_delete (&frame_table, &key_metadata.hash_elem);
|
||||
if (e == NULL) PANIC ("Attempted to free a frame at kernel address %p, "
|
||||
"but this address is not allocated!\n", frame);
|
||||
|
||||
struct frame_metadata *frame_metadata =
|
||||
hash_entry (e, struct frame_metadata, hash_elem);
|
||||
|
||||
free_owners (&frame_metadata->owners);
|
||||
lock_acquire (&lru_lock);
|
||||
hash_delete (&frame_table, &frame_metadata->hash_elem);
|
||||
list_remove (&frame_metadata->list_elem);
|
||||
|
||||
/* If we're freeing the frame marked as the next victim, update
|
||||
@@ -193,6 +183,63 @@ frame_free (void *frame)
|
||||
palloc_free_page (frame);
|
||||
}
|
||||
|
||||
/* Add a thread to a frame's frame_metadata owners list. */
|
||||
bool
|
||||
frame_owner_insert (void *frame, struct thread *owner)
|
||||
{
|
||||
struct frame_metadata *frame_metadata = frame_metadata_find (frame);
|
||||
if (frame_metadata == NULL)
|
||||
return false;
|
||||
|
||||
struct frame_owner *frame_owner = malloc (sizeof (struct frame_owner));
|
||||
if (frame_owner == NULL)
|
||||
return false;
|
||||
frame_owner->owner = owner;
|
||||
list_push_back (&frame_metadata->owners, &frame_owner->elem);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Remove and deallocate a frame owner from the frame_metadata owners list.
|
||||
*/
|
||||
void
|
||||
frame_owner_remove (void *frame, struct thread *owner)
|
||||
{
|
||||
struct frame_metadata *frame_metadata = frame_metadata_find (frame);
|
||||
if (frame_metadata == NULL)
|
||||
PANIC ("Attempted to remove an owner from a frame at kernel "
|
||||
"address %p, but this address is not allocated!\n",
|
||||
frame);
|
||||
|
||||
struct list_elem *oe;
|
||||
for (oe = list_begin (&frame_metadata->owners);
|
||||
oe != list_end (&frame_metadata->owners);)
|
||||
{
|
||||
struct frame_owner *frame_owner
|
||||
= list_entry (oe, struct frame_owner, elem);
|
||||
oe = list_next (oe);
|
||||
if (frame_owner->owner == owner)
|
||||
{
|
||||
list_remove (&frame_owner->elem);
|
||||
free (frame_owner);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NOT_REACHED ();
|
||||
}
|
||||
|
||||
/* Find a frame_metadata entry in the frame table. */
|
||||
static struct frame_metadata *
|
||||
frame_metadata_find (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);
|
||||
}
|
||||
|
||||
/* TODO: Account for page aliases when checking accessed bit. */
|
||||
/* A pre-condition for calling this function is that the calling thread
|
||||
owns lru_lock and that lru_list is non-empty. */
|
||||
@@ -230,6 +277,19 @@ get_victim (void)
|
||||
return frame_metadata;
|
||||
}
|
||||
|
||||
static void
|
||||
free_owners (struct list *owners)
|
||||
{
|
||||
struct list_elem *oe;
|
||||
for (oe = list_begin (owners); oe != list_end (owners);)
|
||||
{
|
||||
struct frame_owner *frame_owner
|
||||
= list_entry (oe, struct frame_owner, elem);
|
||||
oe = list_remove (oe);
|
||||
free (frame_owner);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hash function for frame metadata, used for storing entries in the
|
||||
frame table. */
|
||||
unsigned
|
||||
|
||||
Reference in New Issue
Block a user