Merge branch 'vm/lazy-loading' into vm/page-swap-synch

This commit is contained in:
Themis Demetriades
2024-12-04 19:11:37 +00:00
parent 4bf6914cfa
commit 1e236a5c47
7 changed files with 59 additions and 43 deletions

View File

@@ -15,6 +15,7 @@
#include "threads/switch.h" #include "threads/switch.h"
#include "threads/synch.h" #include "threads/synch.h"
#include "threads/vaddr.h" #include "threads/vaddr.h"
#include "vm/page.h"
#ifdef USERPROG #ifdef USERPROG
#include "userprog/process.h" #include "userprog/process.h"
#include "userprog/syscall.h" #include "userprog/syscall.h"
@@ -264,7 +265,8 @@ thread_create (const char *name, int priority,
if (!hash_init (&t->open_files, fd_hash, fd_less, NULL) if (!hash_init (&t->open_files, fd_hash, fd_less, NULL)
|| !hash_init (&t->child_results, process_result_hash, || !hash_init (&t->child_results, process_result_hash,
process_result_less, t)) process_result_less, t)
|| !hash_init (&t->pages, page_hash, page_less, NULL))
{ {
palloc_free_page (t); palloc_free_page (t);
free (t->result); free (t->result);

View File

@@ -5,13 +5,13 @@
#include "userprog/gdt.h" #include "userprog/gdt.h"
#include "threads/interrupt.h" #include "threads/interrupt.h"
#include "threads/thread.h" #include "threads/thread.h"
#include "userprog/pagedir.h"
#ifdef VM #ifdef VM
#include "vm/stackgrowth.h" #include "vm/stackgrowth.h"
#include "vm/frame.h" #include "vm/frame.h"
#include "vm/page.h" #include "vm/page.h"
#include "devices/swap.h" #include "devices/swap.h"
#include "threads/vaddr.h" #include "threads/vaddr.h"
#include "userprog/pagedir.h"
#endif #endif
/* Number of page faults processed. */ /* Number of page faults processed. */
@@ -19,6 +19,7 @@ static long long page_fault_cnt;
static void kill (struct intr_frame *); static void kill (struct intr_frame *);
static void page_fault (struct intr_frame *); static void page_fault (struct intr_frame *);
bool try_fetch_page (void *upage, bool write);
/* Registers handlers for interrupts that can be caused by user /* Registers handlers for interrupts that can be caused by user
programs. programs.
@@ -156,6 +157,7 @@ page_fault (struct intr_frame *f)
#ifdef VM #ifdef VM
struct thread *t = thread_current (); struct thread *t = thread_current ();
void *upage = pg_round_down (fault_addr);
if (user) if (user)
{ {
if (not_present) if (not_present)
@@ -167,7 +169,6 @@ page_fault (struct intr_frame *f)
if (page_in_swap (t, fault_addr)) if (page_in_swap (t, fault_addr))
{ {
size_t swap_slot = page_get_swap (t, fault_addr); size_t swap_slot = page_get_swap (t, fault_addr);
void *upage = pg_round_down (fault_addr);
void *kpage = frame_alloc (0, upage, t); void *kpage = frame_alloc (0, upage, t);
swap_in (kpage, swap_slot); swap_in (kpage, swap_slot);
@@ -192,6 +193,15 @@ page_fault (struct intr_frame *f)
f->eax = 0xffffffff; f->eax = 0xffffffff;
return; return;
} }
/* If the fault address is in a user page that is not present, then it might
just need to be lazily loaded. So, we check our SPT to see if the page
is expected to have data loaded in memory. */
if (not_present && is_user_vaddr (upage) && upage != NULL)
{
if (try_fetch_page (upage, write))
return;
}
#endif #endif
/* To implement virtual memory, delete the rest of the function /* To implement virtual memory, delete the rest of the function
@@ -205,3 +215,32 @@ page_fault (struct intr_frame *f)
kill (f); kill (f);
} }
bool
try_fetch_page (void *upage, bool write)
{
/* Check if the page is in the supplemental page table. That is, it is a page
that is expected to be in memory. */
struct page_entry *page = page_get (upage);
if (page == NULL)
return false;
/* An attempt to write to a non-writeable should fail. */
if (write && !page->writable)
return false;
/* Load the page into memory based on the type of data it is expecting. */
bool success = false;
switch (page->type) {
case PAGE_EXECUTABLE:
success = page_load (page, page->writable);
break;
default:
return false;
}
if (success && page->writable &&
!pagedir_is_writable(thread_current()->pagedir, upage))
pagedir_set_writable(thread_current()->pagedir, upage, true);
return success;
}

View File

@@ -1,6 +1,8 @@
#ifndef USERPROG_EXCEPTION_H #ifndef USERPROG_EXCEPTION_H
#define USERPROG_EXCEPTION_H #define USERPROG_EXCEPTION_H
#include <stdbool.h>
/* Page fault error code bits that describe the cause of the exception. */ /* Page fault error code bits that describe the cause of the exception. */
#define PF_P 0x1 /* 0: not-present page. 1: access rights violation. */ #define PF_P 0x1 /* 0: not-present page. 1: access rights violation. */
#define PF_W 0x2 /* 0: read, 1: write. */ #define PF_W 0x2 /* 0: read, 1: write. */
@@ -8,5 +10,7 @@
void exception_init (void); void exception_init (void);
void exception_print_stats (void); void exception_print_stats (void);
bool
try_fetch_page (void *upage, bool write);
#endif /* userprog/exception.h */ #endif /* userprog/exception.h */

View File

@@ -24,6 +24,7 @@
#include "threads/vaddr.h" #include "threads/vaddr.h"
#include "threads/synch.h" #include "threads/synch.h"
#include "devices/timer.h" #include "devices/timer.h"
#include "vm/page.h"
#ifdef VM #ifdef VM
#include "vm/frame.h" #include "vm/frame.h"
#endif #endif
@@ -118,6 +119,7 @@ process_execute (const char *cmd)
static void *get_usr_kpage (enum palloc_flags flags, void *upage); static void *get_usr_kpage (enum palloc_flags flags, void *upage);
static void free_usr_kpage (void *kpage); static void free_usr_kpage (void *kpage);
bool install_page (void *upage, void *kpage, bool writable);
static bool process_init_stack (char *cmd_saveptr, void **esp, char *file_name); 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); static void *push_to_stack (void **esp, void *data, size_t data_size);
@@ -363,6 +365,7 @@ process_exit (void)
/* Clean up all open files */ /* Clean up all open files */
hash_destroy (&cur->open_files, fd_cleanup); hash_destroy (&cur->open_files, fd_cleanup);
hash_destroy (&cur->pages, page_cleanup);
/* Close the executable file, implicitly allowing it to be written to. */ /* Close the executable file, implicitly allowing it to be written to. */
if (cur->exec_file != NULL) if (cur->exec_file != NULL)
@@ -620,7 +623,6 @@ load (const char *file_name, void (**eip) (void), void **esp)
done: done:
/* We arrive here whether the load is successful or not. */ /* We arrive here whether the load is successful or not. */
file_close (file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
return success; return success;
} }
@@ -688,58 +690,29 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file)
or disk read error occurs. */ or disk read error occurs. */
static bool static bool
load_segment (struct file *file, off_t ofs, uint8_t *upage, load_segment (struct file *file, off_t ofs, uint8_t *upage,
uint32_t read_bytes, uint32_t zero_bytes, bool writable) uint32_t read_bytes, uint32_t zero_bytes, bool writable)
{ {
ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0); ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
ASSERT (pg_ofs (upage) == 0); ASSERT (pg_ofs (upage) == 0);
ASSERT (ofs % PGSIZE == 0); ASSERT (ofs % PGSIZE == 0);
file_seek (file, ofs); while (read_bytes > 0 || zero_bytes > 0)
while (read_bytes > 0 || zero_bytes > 0)
{ {
/* Calculate how to fill this page. /* Calculate how to fill this page.
We will read PAGE_READ_BYTES bytes from FILE We will read PAGE_READ_BYTES bytes from FILE
and zero the final PAGE_ZERO_BYTES bytes. */ and zero the final PAGE_ZERO_BYTES bytes. */
size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
size_t page_zero_bytes = PGSIZE - page_read_bytes; size_t page_zero_bytes = PGSIZE - page_read_bytes;
/* Check if virtual page already allocated */
struct thread *t = thread_current ();
uint8_t *kpage = pagedir_get_page (t->pagedir, upage);
if (kpage == NULL){
/* Get a new page of memory. */
kpage = get_usr_kpage (0, upage);
if (kpage == NULL){
return false;
}
/* Add the page to the process's address space. */
if (!install_page (upage, kpage, writable))
{
free_usr_kpage (kpage);
return false;
}
} else {
/* Check if writable flag for the page should be updated */
if(writable && !pagedir_is_writable(t->pagedir, upage)){
pagedir_set_writable(t->pagedir, upage, writable);
}
}
/* Load data into the page. */ /* Add the page metadata to the SPT to be lazy loaded later on */
if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes){ if (page_insert (file, ofs, upage, page_read_bytes, page_zero_bytes,
return false; writable, PAGE_EXECUTABLE) == NULL)
} return false;
memset (kpage + page_read_bytes, 0, page_zero_bytes);
/* Advance. */ /* Advance. */
read_bytes -= page_read_bytes; read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes; zero_bytes -= page_zero_bytes;
ofs += PGSIZE;
upage += PGSIZE; upage += PGSIZE;
} }
return true; return true;

View File

@@ -536,4 +536,4 @@ put_user (uint8_t *udst, uint8_t byte)
: "=&a"(error_code), "=m"(*udst) : "=&a"(error_code), "=m"(*udst)
: "q"(byte)); : "q"(byte));
return error_code != -1; return error_code != -1;
} }

View File

@@ -260,4 +260,3 @@ lru_prev (struct list_elem *e)
return list_prev (e); return list_prev (e);
} }

View File

@@ -154,4 +154,3 @@ page_get_swap (struct thread *owner, void *upage)
/* Masks the address bits and returns truncated value. */ /* Masks the address bits and returns truncated value. */
return ((*pte & PTE_ADDR) >> ADDR_START_BIT); return ((*pte & PTE_ADDR) >> ADDR_START_BIT);
} }