Compare commits

..

12 Commits

6 changed files with 118 additions and 137 deletions

View File

@@ -212,6 +212,7 @@ donate_priority (struct thread *donee) {
ASSERT (intr_get_level () == INTR_OFF); ASSERT (intr_get_level () == INTR_OFF);
struct thread *donor = thread_current (); struct thread *donor = thread_current ();
list_remove (&donor->donor_elem);
list_push_back (&donee->donors_list, &donor->donor_elem); list_push_back (&donee->donors_list, &donor->donor_elem);
while (donee != NULL) while (donee != NULL)
@@ -260,6 +261,7 @@ lock_acquire (struct lock *lock)
ASSERT (!lock_held_by_current_thread (lock)); ASSERT (!lock_held_by_current_thread (lock));
struct thread *t = thread_current (); struct thread *t = thread_current ();
ASSERT (t->waiting_lock == NULL);
enum intr_level old_level = intr_disable (); enum intr_level old_level = intr_disable ();
if (lock->holder != NULL) if (lock->holder != NULL)
@@ -341,7 +343,6 @@ lock_release (struct lock *lock)
released, transfer the remaining orphaned donors to its donor list. */ released, transfer the remaining orphaned donors to its donor list. */
if (max_donor != NULL) if (max_donor != NULL)
{ {
list_remove (&max_donor->donor_elem);
while (!list_empty (&orphan_list)) while (!list_empty (&orphan_list))
list_push_back (&max_donor->donors_list, list_pop_front (&orphan_list)); list_push_back (&max_donor->donors_list, list_pop_front (&orphan_list));
} }

View File

@@ -373,7 +373,9 @@ thread_exit (void)
and schedule another process. That process will destroy us and schedule another process. That process will destroy us
when it calls thread_schedule_tail(). */ when it calls thread_schedule_tail(). */
intr_disable (); intr_disable ();
list_remove (&thread_current()->allelem); struct thread *t = thread_current ();
list_remove (&t->allelem);
list_remove (&t->donor_elem);
thread_current ()->status = THREAD_DYING; thread_current ()->status = THREAD_DYING;
schedule (); schedule ();
NOT_REACHED (); NOT_REACHED ();
@@ -679,6 +681,7 @@ init_thread (struct thread *t, const char *name, int nice, int priority,
t->base_priority t->base_priority
= thread_mlfqs ? calculate_bsd_priority (recent_cpu, nice) : priority; = thread_mlfqs ? calculate_bsd_priority (recent_cpu, nice) : priority;
list_init (&t->donors_list); list_init (&t->donors_list);
list_push_back (&t->donors_list, &t->donor_elem);
t->waiting_lock = NULL; t->waiting_lock = NULL;
t->nice = nice; t->nice = nice;

View File

@@ -145,14 +145,6 @@ page_fault (struct intr_frame *f)
write = (f->error_code & PF_W) != 0; write = (f->error_code & PF_W) != 0;
user = (f->error_code & PF_U) != 0; user = (f->error_code & PF_U) != 0;
/* Kernel page fault is further handled by the kernel itself. */
if (!user)
{
f->eip = (void *)f->eax;
f->eax = 0xffffffff;
return;
}
/* To implement virtual memory, delete the rest of the function /* To implement virtual memory, delete the rest of the function
body, and replace it with code that brings in the page to body, and replace it with code that brings in the page to
which fault_addr refers. */ which fault_addr refers. */

View File

@@ -8,6 +8,7 @@
#include <string.h> #include <string.h>
#include "userprog/gdt.h" #include "userprog/gdt.h"
#include "userprog/pagedir.h" #include "userprog/pagedir.h"
#include "userprog/syscall.h"
#include "userprog/tss.h" #include "userprog/tss.h"
#include "filesys/directory.h" #include "filesys/directory.h"
#include "filesys/file.h" #include "filesys/file.h"
@@ -46,6 +47,9 @@ struct process_start_data
tokens while maintaining state. */ tokens while maintaining state. */
char file_name[FNAME_MAX_LEN + 1]; /* Name of the file of the process to char file_name[FNAME_MAX_LEN + 1]; /* Name of the file of the process to
be started. */ be started. */
struct semaphore load_sema;
bool success;
}; };
static thread_func start_process NO_RETURN; static thread_func start_process NO_RETURN;
@@ -61,11 +65,7 @@ process_execute (const char *cmd)
char *cmd_copy; char *cmd_copy;
tid_t tid; tid_t tid;
struct process_start_data *data = malloc (sizeof (struct process_start_data)); struct process_start_data data;
if (data == NULL)
{
return TID_ERROR;
}
/* Make a copy of command. /* Make a copy of command.
Otherwise there's a race between the caller and load(). */ Otherwise there's a race between the caller and load(). */
@@ -79,21 +79,39 @@ process_execute (const char *cmd)
/* Retrieve first argument of command, which is the file name /* Retrieve first argument of command, which is the file name
of the process. */ of the process. */
char *file_name = strtok_r (cmd_copy, " ", &data->cmd_saveptr); char *file_name = strtok_r (cmd_copy, " ", &data.cmd_saveptr);
/* Validates that the current file to be executed is a valid file */ /* NOTE: Currently, the file being executed is closed in load () and then
if (filesys_open (file_name) == NULL) reopened here. Because load is an exported public function, this
might be necessary. */
lock_acquire (&filesys_lock);
/* Validates that the current file to be executed is a valid file */
bool valid_file = filesys_open (file_name) != NULL;
lock_release (&filesys_lock);
if (!valid_file)
return TID_ERROR; return TID_ERROR;
/* Create a new thread to execute the command, by initializing /* Create a new thread to execute the command, by initializing
it running the function 'start_process' with the appropriate it running the function 'start_process' with the appropriate
arguments. For details of arguments, see 'start_process'. */ arguments. For details of arguments, see 'start_process'. */
data->cmd = cmd_copy; data.cmd = cmd_copy;
strlcpy (data->file_name, file_name, FNAME_MAX_LEN + 1); strlcpy (data.file_name, file_name, FNAME_MAX_LEN + 1);
sema_init (&data.load_sema, 0);
data.success = false;
tid = thread_create (file_name, PRI_DEFAULT, start_process, &data);
tid = thread_create (file_name, PRI_DEFAULT, start_process, data);
if (tid == TID_ERROR) if (tid == TID_ERROR)
palloc_free_page (cmd_copy); {
palloc_free_page (cmd_copy);
}
else
{
sema_down (&data.load_sema);
if (!data.success)
tid = TID_ERROR;
}
return tid; return tid;
} }
@@ -111,7 +129,6 @@ static void
start_process (void *proc_start_data) start_process (void *proc_start_data)
{ {
struct intr_frame if_; struct intr_frame if_;
bool success;
struct process_start_data *data = proc_start_data; struct process_start_data *data = proc_start_data;
@@ -120,34 +137,38 @@ start_process (void *proc_start_data)
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG; if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
if_.cs = SEL_UCSEG; if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS; if_.eflags = FLAG_IF | FLAG_MBS;
success = load (data->file_name, &if_.eip, &if_.esp);
lock_acquire (&filesys_lock);
/* Prevent writing to the file being executed. */
struct file *exec_file = filesys_open (data->file_name);
thread_current ()->exec_file = exec_file;
file_deny_write (exec_file);
lock_release (&filesys_lock);
/* If load failed, quit. */ data->success = load (data->file_name, &if_.eip, &if_.esp);
if (!success)
/* If load failed, free process startup data and quit. */
if (!data->success)
{ {
palloc_free_page (data->cmd); palloc_free_page (data->cmd);
goto fail; sema_up (&data->load_sema);
thread_exit ();
} }
/* Initialize user process stack and free page used to store the /* Initialize user process stack and free page used to store the
command that executed the process. */ command that executed the process. */
success = process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name); bool success = process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name);
palloc_free_page (data->cmd); palloc_free_page (data->cmd);
data->success = success;
sema_up (&data->load_sema);
/* If stack initialization failed, free resources and quit. */ /* If stack initialization failed, free process resources and quit. */
if (!success) if (!success)
{ {
process_exit (); thread_exit ();
goto fail;
} }
/* NOTE: Currently, the file being executed is closed in load () and then
reopened here. Because load is an exported public function, this
might be necessary. */
struct file *exec_file = filesys_open (data->file_name);
thread_current ()->exec_file = exec_file;
file_deny_write (exec_file);
/* Start the user process by simulating a return from an /* Start the user process by simulating a return from an
interrupt, implemented by intr_exit (in interrupt, implemented by intr_exit (in
threads/intr-stubs.S). Because intr_exit takes all of its threads/intr-stubs.S). Because intr_exit takes all of its
@@ -156,11 +177,6 @@ start_process (void *proc_start_data)
and jump to it. */ and jump to it. */
asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory"); asm volatile ("movl %0, %%esp; jmp intr_exit" : : "g" (&if_) : "memory");
NOT_REACHED (); NOT_REACHED ();
/* If starting the process failed, free its common resources and exit. */
fail:
free (data);
thread_exit ();
} }
/* Helper function that initializes the stack of a newly created /* Helper function that initializes the stack of a newly created
@@ -291,7 +307,9 @@ process_wait (tid_t child_tid UNUSED)
break; break;
} }
if (child_result == NULL) if (child_result == NULL)
return -1; {
return -1;
}
/* Wait for child to die. */ /* Wait for child to die. */
sema_down (&child_result->sema); sema_down (&child_result->sema);
/* We need lock release in process_exit, so we need to acquire (and possibly /* We need lock release in process_exit, so we need to acquire (and possibly
@@ -305,6 +323,7 @@ process_wait (tid_t child_tid UNUSED)
int exit_status = child_result->exit_status; int exit_status = child_result->exit_status;
lock_release (&child_result->lock); lock_release (&child_result->lock);
free (child_result); free (child_result);
return exit_status; return exit_status;
} }
@@ -312,11 +331,23 @@ process_wait (tid_t child_tid UNUSED)
void void
process_exit (void) process_exit (void)
{ {
struct thread *cur = thread_current (); struct thread *cur = thread_current ();
uint32_t *pd; uint32_t *pd;
printf ("%s: exit(%d)\n", cur->name, cur->exit_status); printf ("%s: exit(%d)\n", cur->name, cur->exit_status);
file_close (cur->exec_file);
/* Clean up all open files */
hash_destroy (&cur->open_files, fd_cleanup);
/* Close the executable file. */
if (cur->exec_file != NULL)
{
lock_acquire (&filesys_lock);
file_close (cur->exec_file);
lock_release (&filesys_lock);
}
/* Update process result. */ /* Update process result. */
if (cur->result != NULL) if (cur->result != NULL)
@@ -341,10 +372,11 @@ process_exit (void)
/* Free child process results or signal parent's death. */ /* Free child process results or signal parent's death. */
struct list_elem *e; struct list_elem *e;
for (e = list_begin (&cur->child_results); for (e = list_begin (&cur->child_results);
e != list_end (&cur->child_results); e = list_next (e)) e != list_end (&cur->child_results);)
{ {
struct process_result *result struct process_result *result
= list_entry (e, struct process_result, elem); = list_entry (e, struct process_result, elem);
struct list_elem *next = list_next (e);
lock_acquire (&result->lock); lock_acquire (&result->lock);
/* Child has died (and was not waited for). Free the result. */ /* Child has died (and was not waited for). Free the result. */
if (sema_try_down (&result->sema)) if (sema_try_down (&result->sema))
@@ -358,6 +390,7 @@ process_exit (void)
sema_up (&result->sema); sema_up (&result->sema);
lock_release (&result->lock); lock_release (&result->lock);
} }
e = next;
} }
/* Destroy the current process's page directory and switch back /* Destroy the current process's page directory and switch back
@@ -476,6 +509,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
off_t file_ofs; off_t file_ofs;
bool success = false; bool success = false;
int i; int i;
lock_acquire (&filesys_lock);
/* Allocate and activate page directory. */ /* Allocate and activate page directory. */
t->pagedir = pagedir_create (); t->pagedir = pagedir_create ();
@@ -575,6 +609,7 @@ 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); file_close (file);
lock_release (&filesys_lock);
return success; return success;
} }

View File

@@ -11,12 +11,8 @@
#include "userprog/process.h" #include "userprog/process.h"
#include "userprog/pagedir.h" #include "userprog/pagedir.h"
#include <stdio.h> #include <stdio.h>
#include <stdbool.h>
#include <syscall-nr.h> #include <syscall-nr.h>
#define MAX_SYSCALL_ARGS 3
static struct lock filesys_lock;
static unsigned fd_counter = MIN_USER_FD; static unsigned fd_counter = MIN_USER_FD;
struct open_file struct open_file
@@ -49,11 +45,7 @@ static unsigned syscall_tell (int fd);
static void syscall_close (int fd); static void syscall_close (int fd);
static struct open_file *fd_get_file (int fd); static struct open_file *fd_get_file (int fd);
static void validate_user_pointer (const void *ptr, size_t size, static void *validate_user_pointer (const void *ptr, size_t size);
bool check_write);
static void validate_user_string (const char *str, bool check_write);
static int get_user (const uint8_t *);
static bool put_user (uint8_t *, uint8_t);
/* A struct defining a syscall_function pointer along with its arity. */ /* A struct defining a syscall_function pointer along with its arity. */
typedef struct typedef struct
@@ -103,8 +95,8 @@ static void
syscall_handler (struct intr_frame *f) syscall_handler (struct intr_frame *f)
{ {
/* First, read the system call number from the stack. */ /* First, read the system call number from the stack. */
validate_user_pointer (f->esp, sizeof (uintptr_t), false); validate_user_pointer (f->esp, 1);
uintptr_t syscall_number = *(int *)f->esp; unsigned syscall_number = *(int *) f->esp;
/* Ensures the number corresponds to a system call that can be handled. */ /* Ensures the number corresponds to a system call that can be handled. */
if (syscall_number >= LOOKUP_SIZE) if (syscall_number >= LOOKUP_SIZE)
@@ -114,10 +106,10 @@ syscall_handler (struct intr_frame *f)
/* Next, read and copy the arguments from the stack pointer. */ /* Next, read and copy the arguments from the stack pointer. */
validate_user_pointer (f->esp + sizeof (uintptr_t), validate_user_pointer (f->esp + sizeof (uintptr_t),
syscall.arity * sizeof (uintptr_t), false); syscall.arity * sizeof (uintptr_t));
uintptr_t args[MAX_SYSCALL_ARGS] = { 0 }; uintptr_t args[3] = {0};
for (int i = 0; i < syscall.arity && i < MAX_SYSCALL_ARGS; i++) for (int i=0; i < syscall.arity; i++)
args[i] = *(uintptr_t *)(f->esp + sizeof (uintptr_t) * (i + 1)); args[i] = *(uintptr_t *) (f->esp + sizeof (uintptr_t) * (i + 1));
/* Call the function that handles this system call with the arguments. When /* Call the function that handles this system call with the arguments. When
there is a return value it is stored in f->eax. */ there is a return value it is stored in f->eax. */
@@ -148,11 +140,9 @@ syscall_exit (int status)
static pid_t static pid_t
syscall_exec (const char *cmd_line) syscall_exec (const char *cmd_line)
{ {
validate_user_string (cmd_line, false); validate_user_pointer (cmd_line, 1);
lock_acquire (&filesys_lock);
pid_t pid = process_execute(cmd_line); pid_t pid = process_execute(cmd_line);
lock_release (&filesys_lock);
return pid; return pid;
} }
@@ -171,7 +161,7 @@ syscall_wait (pid_t pid)
static bool static bool
syscall_create (const char *file UNUSED, unsigned initial_size UNUSED) syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
{ {
validate_user_string (file, false); validate_user_pointer (file, 1);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_create (file, initial_size); bool status = filesys_create (file, initial_size);
@@ -186,7 +176,7 @@ syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
static bool static bool
syscall_remove (const char *file) syscall_remove (const char *file)
{ {
validate_user_string (file, false); validate_user_pointer (file, 1);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_remove (file); bool status = filesys_remove (file);
@@ -202,7 +192,7 @@ syscall_remove (const char *file)
static int static int
syscall_open (const char *file) syscall_open (const char *file)
{ {
validate_user_string (file, false); validate_user_pointer (file, 1);
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
struct file *ptr = filesys_open (file); struct file *ptr = filesys_open (file);
@@ -257,7 +247,7 @@ syscall_read (int fd, void *buffer, unsigned size)
if (fd < 0 || fd == STDOUT_FILENO) if (fd < 0 || fd == STDOUT_FILENO)
return -1; return -1;
validate_user_pointer (buffer, size, true); validate_user_pointer (buffer, size);
if (fd == STDIN_FILENO) if (fd == STDIN_FILENO)
{ {
@@ -294,7 +284,7 @@ syscall_write (int fd, const void *buffer, unsigned size)
if (fd <= 0) if (fd <= 0)
return 0; return 0;
validate_user_pointer (buffer, size, false); validate_user_pointer (buffer, size);
if (fd == STDOUT_FILENO) if (fd == STDOUT_FILENO)
{ {
@@ -388,6 +378,20 @@ fd_less (const struct hash_elem *a_, const struct hash_elem *b_,
return a->fd < b->fd; return a->fd < b->fd;
} }
/* Function to clean up an open file entry. Closes the file and frees the
associated memory. */
void
fd_cleanup (struct hash_elem *e, void *aux UNUSED)
{
struct open_file *file_info = hash_entry (e, struct open_file, elem);
lock_acquire (&filesys_lock);
file_close (file_info->file);
lock_release (&filesys_lock);
free (file_info);
}
/* Gets a file from its descriptor (FD number). If there is no file with the fd /* Gets a file from its descriptor (FD number). If there is no file with the fd
FD it returns NULL. */ FD it returns NULL. */
static struct open_file * static struct open_file *
@@ -408,75 +412,17 @@ fd_get_file (int fd)
} }
/* Validates if a block of memory starting at PTR and of size SIZE bytes is /* Validates if a block of memory starting at PTR and of size SIZE bytes is
fully contained within valid user virtual memory. thread_exit () if the fully contained within user virtual memory. Kills the thread (by calling
memory is invalid. thread_exit) if the memory is invalid. Otherwise, returns the PTR given.
If the size is 0, the function does no checks and returns PTR. */ If the size is 0, the function does no checks and returns PTR.*/
static void static void *
validate_user_pointer (const void *ptr, size_t size, bool check_write) validate_user_pointer (const void *ptr, size_t size)
{ {
if (size == 0) if (size > 0 && (ptr == NULL ||
return; !is_user_vaddr (ptr) ||
/* ptr < ptr + size - 1, so sufficient to check that (ptr + size -1) is a !is_user_vaddr (ptr + size - 1) ||
valid user virtual memory address. */ pagedir_get_page (thread_current()->pagedir, ptr) == NULL))
void *last = ptr + size - 1;
if (!is_user_vaddr (last))
thread_exit (); thread_exit ();
ptr = pg_round_down (ptr);
while (ptr <= last)
{
int result;
/* Check read access to pointer. */
if ((result = get_user (ptr)) == -1)
thread_exit ();
/* Check write access to pointer (if required). */
if (check_write && !put_user (ptr, result))
thread_exit ();
ptr += PGSIZE;
}
}
/* Validates of a C-string starting at ptr is fully contained within valid return (void *) ptr;
user virtual memory. thread_exit () if the memory is invalid. */
static void
validate_user_string (const char *ptr, bool check_write)
{
while (true)
{
if (!is_user_vaddr (ptr))
thread_exit ();
int result;
if ((result = get_user ((const uint8_t *)ptr)) == -1)
thread_exit ();
if (check_write && !put_user ((uint8_t *)ptr, result))
thread_exit ();
if (*ptr == '\0')
return;
ptr++;
}
} }
/* PROVIDED BY SPEC.
Reads a byte at user virtual address UADDR.
UADDR must be below PHYS_BASE.
Returns the byte value if successful, -1 if a segfault occurred. */
static int
get_user (const uint8_t *uaddr)
{
int result;
asm ("movl $1f, %0; movzbl %1, %0; 1:" : "=&a"(result) : "m"(*uaddr));
return result;
}
/* PROVIDED BY SPEC.
Writes BYTE to user address UDST.
UDST must be below PHYS_BASE.
Returns true if successful, false if a segfault occurred. */
static bool
put_user (uint8_t *udst, uint8_t byte)
{
int error_code;
asm ("movl $1f, %0; movb %b2, %1; 1:"
: "=&a"(error_code), "=m"(*udst)
: "q"(byte));
return error_code != -1;
}

View File

@@ -2,14 +2,18 @@
#define USERPROG_SYSCALL_H #define USERPROG_SYSCALL_H
#include <hash.h> #include <hash.h>
#include "threads/synch.h"
#define MIN_USER_FD 2 #define MIN_USER_FD 2
typedef int pid_t; typedef int pid_t;
struct lock filesys_lock;
void syscall_init (void); void syscall_init (void);
unsigned fd_hash (const struct hash_elem *element, void *aux); unsigned fd_hash (const struct hash_elem *element, void *aux);
bool fd_less (const struct hash_elem *a, const struct hash_elem *b, void *aux); bool fd_less (const struct hash_elem *a, const struct hash_elem *b, void *aux);
void fd_cleanup (struct hash_elem *e, void *aux);
#endif /* userprog/syscall.h */ #endif /* userprog/syscall.h */