feat: incorporate lazy-loading data & helpers into supplemental page table
This commit is contained in:
@@ -143,6 +143,10 @@ struct thread
|
||||
struct hash open_files; /* Hash Table of FD -> Struct File. */
|
||||
#endif
|
||||
|
||||
#ifdef VM
|
||||
struct hash pages; /* Table of open user pages. */
|
||||
#endif
|
||||
|
||||
void *curr_esp;
|
||||
|
||||
/* Owned by thread.c. */
|
||||
|
||||
@@ -118,7 +118,6 @@ process_execute (const char *cmd)
|
||||
|
||||
static void *get_usr_kpage (enum palloc_flags flags, void *upage);
|
||||
static void free_usr_kpage (void *kpage);
|
||||
static bool install_page (void *upage, void *kpage, bool writable);
|
||||
|
||||
static bool process_init_stack (char *cmd_saveptr, void **esp, char *file_name);
|
||||
static void *push_to_stack (void **esp, void *data, size_t data_size);
|
||||
@@ -809,7 +808,7 @@ free_usr_kpage (void *kpage)
|
||||
with palloc_get_page().
|
||||
Returns true on success, false if UPAGE is already mapped or
|
||||
if memory allocation fails. */
|
||||
static bool
|
||||
bool
|
||||
install_page (void *upage, void *kpage, bool writable)
|
||||
{
|
||||
struct thread *t = thread_current ();
|
||||
|
||||
@@ -8,4 +8,6 @@ int process_wait (tid_t);
|
||||
void process_exit (void);
|
||||
void process_activate (void);
|
||||
|
||||
bool install_page (void *upage, void *kpage, bool writable);
|
||||
|
||||
#endif /* userprog/process.h */
|
||||
|
||||
110
src/vm/page.c
110
src/vm/page.c
@@ -1,10 +1,118 @@
|
||||
#include "page.h"
|
||||
#include "userprog/pagedir.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "filesys/file.h"
|
||||
#include "threads/pte.h"
|
||||
#include "threads/malloc.h"
|
||||
#include "threads/palloc.h"
|
||||
#include "userprog/process.h"
|
||||
#include "userprog/pagedir.h"
|
||||
#include "vm/frame.h"
|
||||
|
||||
#define SWAP_FLAG_BIT 9
|
||||
#define ADDR_START_BIT 12
|
||||
|
||||
/* Hashing function needed for the SPT table. Returns a hash for an entry,
|
||||
based on its upage. */
|
||||
unsigned
|
||||
page_hash (const struct hash_elem *e, UNUSED void *aux)
|
||||
{
|
||||
struct page_entry *page = hash_entry (e, struct page_entry, elem);
|
||||
return hash_ptr (page->upage);
|
||||
}
|
||||
|
||||
/* Comparator function for the SPT table. Compares two entries based on their
|
||||
upages. */
|
||||
bool
|
||||
page_less (const struct hash_elem *a_, const struct hash_elem *b_,
|
||||
void *aux UNUSED)
|
||||
{
|
||||
const struct page_entry *a = hash_entry (a_, struct page_entry, elem);
|
||||
const struct page_entry *b = hash_entry (b_, struct page_entry, elem);
|
||||
|
||||
return a->upage < b->upage;
|
||||
}
|
||||
|
||||
/* Allocate and insert a new page entry into the thread's page table. */
|
||||
struct page_entry *
|
||||
page_insert (struct file *file, off_t ofs, void *upage, uint32_t read_bytes,
|
||||
uint32_t zero_bytes, bool writable, enum page_type type)
|
||||
{
|
||||
struct page_entry *page = malloc(sizeof (struct page_entry));
|
||||
if (page == NULL)
|
||||
return NULL;
|
||||
|
||||
page->file = file;
|
||||
page->offset = ofs;
|
||||
page->upage = upage;
|
||||
page->read_bytes = read_bytes;
|
||||
page->zero_bytes = zero_bytes;
|
||||
page->writable = writable;
|
||||
page->type = type;
|
||||
|
||||
hash_insert (&thread_current ()->pages, &page->elem);
|
||||
return page;
|
||||
}
|
||||
|
||||
/* Gets a page_entry from the starting address of the page. Returns NULL if no
|
||||
such page_entry exists in the hash map.*/
|
||||
struct page_entry *
|
||||
page_get (void *upage)
|
||||
{
|
||||
struct page_entry fake_page_entry;
|
||||
fake_page_entry.upage = upage;
|
||||
|
||||
struct hash_elem *e
|
||||
= hash_find (&thread_current ()->pages, &fake_page_entry.elem);
|
||||
|
||||
if (e == NULL)
|
||||
return NULL;
|
||||
|
||||
return hash_entry (e, struct page_entry, elem);
|
||||
}
|
||||
|
||||
bool
|
||||
page_load (struct page_entry *page, bool writable)
|
||||
{
|
||||
/* Allocate a frame for the page. If a frame allocation fails, then
|
||||
frame_alloc should try to evict a page. If it is still NULL, the OS
|
||||
panics as this should not happen if eviction is working correctly. */
|
||||
void *frame = frame_alloc (0, page->upage, thread_current ());
|
||||
if (frame == NULL)
|
||||
PANIC ("Could not allocate a frame to load page into memory.");
|
||||
|
||||
/* Map the page to the frame. */
|
||||
if (!install_page (page->upage, frame, writable))
|
||||
{
|
||||
frame_free (frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Move the file pointer to the correct location in the file. Then, read the
|
||||
data from the file into the frame. Checks that we were able to read the
|
||||
expected number of bytes. */
|
||||
file_seek (page->file, page->offset);
|
||||
if (file_read (page->file, frame, page->read_bytes) != (int) page->read_bytes)
|
||||
{
|
||||
frame_free (frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Zero out the remaining bytes in the frame. */
|
||||
memset (frame + page->read_bytes, 0, page->zero_bytes);
|
||||
|
||||
/* Mark the page as loaded successfully. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Function to clean up a page_entry. Given the elem of that page_entry, frees
|
||||
the page_entry itself. */
|
||||
void
|
||||
page_cleanup (struct hash_elem *e, void *aux UNUSED)
|
||||
{
|
||||
free (hash_entry (e, struct page_entry, elem));
|
||||
}
|
||||
|
||||
/* Updates the 'owner' thread's page table entry for virtual address 'upage'
|
||||
to flag the page as being stored in swap, and stores the specified swap slot
|
||||
value in the entry at the address bits for later retrieval from disk. */
|
||||
|
||||
@@ -2,7 +2,36 @@
|
||||
#define VM_PAGE_H
|
||||
|
||||
#include "threads/thread.h"
|
||||
#include "filesys/off_t.h"
|
||||
|
||||
enum page_type {
|
||||
PAGE_EXECUTABLE,
|
||||
PAGE_EMPTY
|
||||
};
|
||||
|
||||
struct page_entry {
|
||||
enum page_type type; /* Type of Data that should go into the page */
|
||||
void *upage; /* Start Address of the User Page (Key of hash table). */
|
||||
|
||||
/* File Data */
|
||||
struct file *file; /* Pointer to the file for executables. */
|
||||
off_t offset; /* Offset of the page content within the file. */
|
||||
uint32_t read_bytes; /* Number of bytes to read within the page. */
|
||||
uint32_t zero_bytes; /* Number of bytes to zero within the page. */
|
||||
bool writable; /* Flag for whether this page is writable or not. */
|
||||
|
||||
struct hash_elem elem; /* An elem for the hash table. */
|
||||
};
|
||||
|
||||
unsigned page_hash (const struct hash_elem *e, void *aux);
|
||||
bool page_less (const struct hash_elem *a_, const struct hash_elem *b_,
|
||||
void *aux);
|
||||
struct page_entry *page_insert (struct file *file, off_t ofs, void *upage,
|
||||
uint32_t read_bytes, uint32_t zero_bytes,
|
||||
bool writable, enum page_type type);
|
||||
struct page_entry *page_get (void *upage);
|
||||
bool page_load (struct page_entry *page, bool writable);
|
||||
void page_cleanup (struct hash_elem *e, void *aux);
|
||||
void page_set_swap (struct thread *, void *, size_t);
|
||||
bool page_in_swap (struct thread *, void *);
|
||||
size_t page_get_swap (struct thread *, void *);
|
||||
|
||||
Reference in New Issue
Block a user