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/synch.h"
#include "threads/vaddr.h"
#include "vm/page.h"
#ifdef USERPROG
#include "userprog/process.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)
|| !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);
free (t->result);

View File

@@ -5,13 +5,13 @@
#include "userprog/gdt.h"
#include "threads/interrupt.h"
#include "threads/thread.h"
#include "userprog/pagedir.h"
#ifdef VM
#include "vm/stackgrowth.h"
#include "vm/frame.h"
#include "vm/page.h"
#include "devices/swap.h"
#include "threads/vaddr.h"
#include "userprog/pagedir.h"
#endif
/* Number of page faults processed. */
@@ -19,6 +19,7 @@ static long long page_fault_cnt;
static void kill (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
programs.
@@ -156,6 +157,7 @@ page_fault (struct intr_frame *f)
#ifdef VM
struct thread *t = thread_current ();
void *upage = pg_round_down (fault_addr);
if (user)
{
if (not_present)
@@ -167,7 +169,6 @@ page_fault (struct intr_frame *f)
if (page_in_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);
swap_in (kpage, swap_slot);
@@ -192,6 +193,15 @@ page_fault (struct intr_frame *f)
f->eax = 0xffffffff;
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
/* To implement virtual memory, delete the rest of the function
@@ -205,3 +215,32 @@ page_fault (struct intr_frame *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
#define USERPROG_EXCEPTION_H
#include <stdbool.h>
/* 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_W 0x2 /* 0: read, 1: write. */
@@ -8,5 +10,7 @@
void exception_init (void);
void exception_print_stats (void);
bool
try_fetch_page (void *upage, bool write);
#endif /* userprog/exception.h */

View File

@@ -24,6 +24,7 @@
#include "threads/vaddr.h"
#include "threads/synch.h"
#include "devices/timer.h"
#include "vm/page.h"
#ifdef VM
#include "vm/frame.h"
#endif
@@ -118,6 +119,7 @@ process_execute (const char *cmd)
static void *get_usr_kpage (enum palloc_flags flags, void *upage);
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 void *push_to_stack (void **esp, void *data, size_t data_size);
@@ -363,6 +365,7 @@ process_exit (void)
/* Clean up all open files */
hash_destroy (&cur->open_files, fd_cleanup);
hash_destroy (&cur->pages, page_cleanup);
/* Close the executable file, implicitly allowing it to be written to. */
if (cur->exec_file != NULL)
@@ -620,7 +623,6 @@ load (const char *file_name, void (**eip) (void), void **esp)
done:
/* We arrive here whether the load is successful or not. */
file_close (file);
lock_release (&filesys_lock);
return success;
}
@@ -694,7 +696,6 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
ASSERT (pg_ofs (upage) == 0);
ASSERT (ofs % PGSIZE == 0);
file_seek (file, ofs);
while (read_bytes > 0 || zero_bytes > 0)
{
/* Calculate how to fill this page.
@@ -703,43 +704,15 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
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){
/* Add the page metadata to the SPT to be lazy loaded later on */
if (page_insert (file, ofs, upage, page_read_bytes, page_zero_bytes,
writable, PAGE_EXECUTABLE) == 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. */
if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes){
return false;
}
memset (kpage + page_read_bytes, 0, page_zero_bytes);
/* Advance. */
read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes;
ofs += PGSIZE;
upage += PGSIZE;
}
return true;

View File

@@ -260,4 +260,3 @@ lru_prev (struct list_elem *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. */
return ((*pte & PTE_ADDR) >> ADDR_START_BIT);
}