Merge branch 'vm/memory-mapped-files' into vm/virtual-memory/saleh
This commit is contained in:
@@ -10,12 +10,15 @@
|
||||
#include "threads/synch.h"
|
||||
#include "userprog/process.h"
|
||||
#include "userprog/pagedir.h"
|
||||
#include "vm/page.h"
|
||||
#include "vm/mmap.h"
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <syscall-nr.h>
|
||||
|
||||
#define MAX_SYSCALL_ARGS 3
|
||||
#define EXIT_FAILURE -1
|
||||
#define MMAP_FAILURE -1
|
||||
|
||||
struct open_file
|
||||
{
|
||||
@@ -45,6 +48,8 @@ static int syscall_write (int fd, const void *buffer, unsigned size);
|
||||
static void syscall_seek (int fd, unsigned position);
|
||||
static unsigned syscall_tell (int fd);
|
||||
static void syscall_close (int fd);
|
||||
static mapid_t syscall_mmap (int fd, void *addr);
|
||||
static void syscall_munmap (mapid_t mapping);
|
||||
|
||||
static struct open_file *fd_get_file (int fd);
|
||||
static void validate_user_pointer (const void *ptr, size_t size,
|
||||
@@ -77,6 +82,8 @@ static const struct syscall_arguments syscall_lookup[] =
|
||||
[SYS_SEEK] = {(syscall_function) syscall_seek, 2},
|
||||
[SYS_TELL] = {(syscall_function) syscall_tell, 1},
|
||||
[SYS_CLOSE] = {(syscall_function) syscall_close, 1},
|
||||
[SYS_MMAP] = {(syscall_function) syscall_mmap, 2},
|
||||
[SYS_MUNMAP] = {(syscall_function) syscall_munmap, 1}
|
||||
};
|
||||
|
||||
/* The number of syscall functions (i.e, number of elements) within the
|
||||
@@ -391,6 +398,79 @@ syscall_close (int fd)
|
||||
}
|
||||
}
|
||||
|
||||
/* Handles the syscall for memory mapping a file. */
|
||||
static mapid_t
|
||||
syscall_mmap (int fd, void *addr)
|
||||
{
|
||||
/* Ensure the FD is for a file in the filesystem (not STDIN or STDOUT). */
|
||||
if (fd == STDOUT_FILENO || fd == STDIN_FILENO)
|
||||
return MMAP_FAILURE;
|
||||
|
||||
/* Validate that there is a file associated with the given FD. */
|
||||
struct open_file *file_info = fd_get_file (fd);
|
||||
if (file_info == NULL)
|
||||
return MMAP_FAILURE;
|
||||
|
||||
/* Ensure that the address is page-aligned and it's neither NULL nor zero. */
|
||||
if (addr == 0 || addr == NULL || pg_ofs (addr) != 0)
|
||||
return MMAP_FAILURE;
|
||||
|
||||
/* Reopen the file to obtain a separate and independent reference to the file
|
||||
for the mapping. */
|
||||
struct file *file = file_reopen (file_info->file);
|
||||
if (file == NULL)
|
||||
return MMAP_FAILURE;
|
||||
|
||||
/* Get the size of the file. Mmap fails if the file is empty. */
|
||||
off_t file_size = file_length (file);
|
||||
if (file_size == 0)
|
||||
return MMAP_FAILURE;
|
||||
|
||||
/* Check and ensure that there is enough space in the user virtual memory to
|
||||
hold the entire file. */
|
||||
for (off_t ofs = 0; ofs < file_size; ofs += PGSIZE)
|
||||
{
|
||||
if (page_get (addr + ofs) != NULL)
|
||||
return MMAP_FAILURE;
|
||||
}
|
||||
|
||||
/* Map the file data into the user virtual memory starting from addr. */
|
||||
for (off_t ofs = 0; ofs < file_size; ofs += PGSIZE)
|
||||
{
|
||||
off_t read_bytes = file_size - ofs < PGSIZE ? file_size - ofs : PGSIZE;
|
||||
off_t zero_bytes = PGSIZE - read_bytes;
|
||||
|
||||
if (page_insert (file, ofs, addr + ofs, read_bytes, zero_bytes, true,
|
||||
PAGE_FILE) == NULL)
|
||||
return MMAP_FAILURE;
|
||||
}
|
||||
|
||||
/* Create a new mapping for the file. */
|
||||
struct mmap_entry *mmap = mmap_insert (file, addr);
|
||||
if (mmap == NULL)
|
||||
return MMAP_FAILURE;
|
||||
|
||||
|
||||
return mmap->mapping;
|
||||
}
|
||||
|
||||
/* Handles the syscall for unmapping a memory mapped file.
|
||||
|
||||
Pre: mapping is a valid mapping identifier returned by mmap syscall. */
|
||||
static void
|
||||
syscall_munmap (mapid_t mapping)
|
||||
{
|
||||
/* Get the mmap entry from the mapping identifier. */
|
||||
struct mmap_entry *mmap = mmap_get (mapping);
|
||||
|
||||
/* Delete the mmap entry from the hash table. */
|
||||
hash_delete (&thread_current ()->mmap_files, &mmap->elem);
|
||||
|
||||
/* Unmap the mmap entry: free the pages and write back to the file if
|
||||
necessary. NOTE. freeing and cleaning up is also handled by mmap_unmap. */
|
||||
mmap_unmap (mmap);
|
||||
}
|
||||
|
||||
/* Hashing function needed for the open_file table. Returns a hash for an entry,
|
||||
based on its FD. */
|
||||
unsigned
|
||||
|
||||
Reference in New Issue
Block a user