Compare commits

..

1 Commits

Author SHA1 Message Date
149b0a9d87 Remove filesys CI for gitlab 2024-11-14 03:25:33 +00:00
9 changed files with 91 additions and 194 deletions

View File

@@ -23,11 +23,6 @@ test_devices:
variables: variables:
DIR: devices DIR: devices
test_filesys:
extends: .pintos_tests
variables:
DIR: filesys
test_threads: test_threads:
extends: .pintos_tests extends: .pintos_tests
variables: variables:

View File

@@ -4,7 +4,7 @@ SRCDIR = ..
# To add a new test, put its name on the PROGS list # To add a new test, put its name on the PROGS list
# and then add a name_SRC line that lists its source files. # and then add a name_SRC line that lists its source files.
PROGS = cat cmp cp echo halt hex-dump mcat mcp rm \ PROGS = cat cmp cp echo halt hex-dump mcat mcp rm \
bubsort insult lineup matmult recursor args-ovf bubsort insult lineup matmult recursor
# Should work from task 2 onward. # Should work from task 2 onward.
cat_SRC = cat.c cat_SRC = cat.c
@@ -18,7 +18,6 @@ lineup_SRC = lineup.c
ls_SRC = ls.c ls_SRC = ls.c
recursor_SRC = recursor.c recursor_SRC = recursor.c
rm_SRC = rm.c rm_SRC = rm.c
args-ovf_SRC = args-ovf.c
# Should work in task 3; also in task 4 if VM is included. # Should work in task 3; also in task 4 if VM is included.
bubsort_SRC = bubsort.c bubsort_SRC = bubsort.c

File diff suppressed because one or more lines are too long

View File

@@ -119,14 +119,14 @@ sema_up (struct semaphore *sema)
old_level = intr_disable (); old_level = intr_disable ();
if (!list_empty (&sema->waiters)) if (!list_empty (&sema->waiters))
{ {
/* Enforces wake-up of the highest priority thread waiting for the /* Enforces wake-up of the highest priority thread waiting for the
semaphore. */ semaphore. */
struct list_elem *e = list_max (&sema->waiters, priority_less, NULL); struct list_elem *e = list_max (&sema->waiters, priority_less, NULL);
list_remove (e); list_remove (e);
thread_unblock (list_entry (e, struct thread, elem)); thread_unblock (list_entry (e, struct thread, elem));
thread_unblocked = true; thread_unblocked = true;
} }
sema->value++; sema->value++;
intr_set_level (old_level); intr_set_level (old_level);
@@ -134,12 +134,12 @@ sema_up (struct semaphore *sema)
priority that the current running thread, including the case when called priority that the current running thread, including the case when called
within an interrupt handler. */ within an interrupt handler. */
if (thread_unblocked) if (thread_unblocked)
{ {
if (intr_context ()) if (intr_context ())
intr_yield_on_return (); intr_yield_on_return ();
else else
thread_yield (); thread_yield ();
} }
} }
static void sema_test_helper (void *sema_); static void sema_test_helper (void *sema_);

View File

@@ -688,7 +688,6 @@ init_thread (struct thread *t, const char *name, int nice, int priority,
t->recent_cpu = recent_cpu; t->recent_cpu = recent_cpu;
t->priority = t->base_priority; t->priority = t->base_priority;
t->fd_counter = MINIMUM_USER_FD;
t->exit_status = -1; t->exit_status = -1;
list_init (&t->child_results); list_init (&t->child_results);

View File

@@ -32,9 +32,6 @@ typedef int tid_t;
#define NICE_DEFAULT 0 /* Default niceness. */ #define NICE_DEFAULT 0 /* Default niceness. */
#define NICE_MAX 20 /* Highest niceness. */ #define NICE_MAX 20 /* Highest niceness. */
/* File Descriptors. */
#define MINIMUM_USER_FD 2 /* Minimum file descriptor for user programs. */
/* A process result, synchronised between parent and child. */ /* A process result, synchronised between parent and child. */
struct process_result struct process_result
{ {
@@ -140,9 +137,7 @@ struct thread
#ifdef USERPROG #ifdef USERPROG
/* Owned by userprog/process.c. */ /* Owned by userprog/process.c. */
uint32_t *pagedir; /* Page directory. */ uint32_t *pagedir; /* Page directory. */
unsigned int fd_counter; /* File descriptor counter for thread's struct hash open_files; /* Hash Table of FD -> Struct File */
open files. */
struct hash open_files; /* Hash Table of FD -> Struct File. */
#endif #endif
/* Owned by thread.c. */ /* Owned by thread.c. */

View File

@@ -28,10 +28,6 @@
(for the purposes of alignment). */ (for the purposes of alignment). */
#define WORD_SIZE 4 #define WORD_SIZE 4
/* Defines non-negative integer division wherein the result is always rounded
up. */
#define DIV_CEIL(x, y) ((x + (y - 1)) / y)
/* Keeps track of the position of pointers to user program arguments /* Keeps track of the position of pointers to user program arguments
within a linked list. */ within a linked list. */
struct arg_elem struct arg_elem
@@ -44,6 +40,8 @@ struct arg_elem
that executes process_start for the purpose of starting a user process. */ that executes process_start for the purpose of starting a user process. */
struct process_start_data struct process_start_data
{ {
char *cmd; /* Pointer to a copy of the command used to execute the process.
Allocated a page that must be freed by process_start. */
char *cmd_saveptr; /* Value pointed to by 'saveptr' argument used by char *cmd_saveptr; /* Value pointed to by 'saveptr' argument used by
successive calls to strtok_r to split 'cmd' into successive calls to strtok_r to split 'cmd' into
tokens while maintaining state. */ tokens while maintaining state. */
@@ -51,7 +49,7 @@ struct process_start_data
be started. */ be started. */
bool success; /* Indicates whether the process was successfully loaded. */ bool success; /* Indicates whether the process was successfully loaded. */
struct semaphore loaded; /* Semaphore used to signal that the process has struct semaphore loaded; /* Semaphore used to signal that the process has
finished attempting to load. */ been loaded. */
}; };
static thread_func start_process NO_RETURN; static thread_func start_process NO_RETURN;
@@ -66,7 +64,14 @@ process_execute (const char *cmd)
{ {
char *cmd_copy; char *cmd_copy;
tid_t tid; tid_t tid;
struct process_start_data data;
struct process_start_data *data = malloc (sizeof (struct process_start_data));
if (data == NULL)
{
return TID_ERROR;
}
sema_init (&data->loaded, 0);
data->success = false;
/* 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(). */
@@ -80,34 +85,34 @@ 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 can be opened/exists. */ /* 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. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
struct file *file = filesys_open (file_name); /* Validates that the current file to be executed is a valid file */
bool valid_file = filesys_open (file_name) != NULL;
lock_release (&filesys_lock); lock_release (&filesys_lock);
if (file == NULL) 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'. */
strlcpy (data.file_name, file_name, FNAME_MAX_LEN + 1); data->cmd = cmd_copy;
sema_init (&data.loaded, 0); strlcpy (data->file_name, file_name, FNAME_MAX_LEN + 1);
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)
/* Wait until process file has finished attempting to load via the child palloc_free_page (cmd_copy);
thread before reporting success of starting execution. */ else
if (tid != TID_ERROR)
{ {
sema_down (&data.loaded); sema_down (&data->loaded);
if (!data.success) if (!data->success)
tid = TID_ERROR; tid = TID_ERROR;
} }
free (data);
palloc_free_page (cmd_copy);
return tid; return tid;
} }
@@ -119,15 +124,14 @@ static void *push_to_stack (void **esp, void *data, size_t data_size);
/* Make the current thread execute 'cmd', passing in a copy of the /* Make the current thread execute 'cmd', passing in a copy of the
command string used for processing, the saveptr used by strtok_r command string used for processing, the saveptr used by strtok_r
(in order to further tokenize the same command and retrieve its (in order to further tokenize the same command and retrieve its
arguments), the name of the file being executed, and a semaphore that arguments), as well as the name of the file being executed. This
calls sema_up to indicate that the 'success' variable passed to it involves loading the specified file and starting it running. */
has been updated to indicate whether the process file loading succeeded.
This involves loading the specified file and calling its main () function
with the specified command arguments. */
static void 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;
/* Initialize interrupt frame and load executable. */ /* Initialize interrupt frame and load executable. */
@@ -135,47 +139,42 @@ 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;
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
/* Prevent writing to the file being executed. */
struct file *exec_file = filesys_open (data->file_name); struct file *exec_file = filesys_open (data->file_name);
if (exec_file == NULL) if (exec_file == NULL)
{ {
/* If the executable file cannot be opened, free resources and quit. */
lock_release (&filesys_lock); lock_release (&filesys_lock);
sema_up (&data->loaded); goto fail;
thread_exit ();
} }
thread_current ()->exec_file = exec_file;
/* Deny write to the executable file to prevent writing to it and release the
file system lock. */
file_deny_write (exec_file); file_deny_write (exec_file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
thread_current ()->exec_file = exec_file; success = load (data->file_name, &if_.eip, &if_.esp);
/* Load the ELF executable file, and store the success of the operation in /* If load failed, quit. */
the 'success' variable in data. */ if (!success)
data->success = load (data->file_name, &if_.eip, &if_.esp);
/* If load was sucessful, initialize user process stack and free page used
to store the command that executed the process. */
if (data->success)
{ {
data->success = palloc_free_page (data->cmd);
process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name); goto fail;
} }
/* Signal that the process has finished attempting to load. */ /* Initialize user process stack and free page used to store the
bool success = data->success; command that executed the process. */
sema_up (&data->loaded); success = process_init_stack (data->cmd_saveptr, &if_.esp, data->file_name);
palloc_free_page (data->cmd);
/* If the load was unsuccessful or if it was but the stack initialization /* If stack initialization failed, free resources and quit. */
failed, exit the thread. */
if (!success) if (!success)
thread_exit (); {
goto fail;
}
data->success = true;
sema_up (&data->loaded);
/* 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
@@ -184,6 +183,12 @@ 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, exit. */
fail:
data->success = false;
sema_up (&data->loaded);
thread_exit ();
} }
/* Helper function that initializes the stack of a newly created /* Helper function that initializes the stack of a newly created
@@ -191,10 +196,6 @@ start_process (void *proc_start_data)
static bool static bool
process_init_stack (char *cmd_saveptr, void **esp, char *file_name) process_init_stack (char *cmd_saveptr, void **esp, char *file_name)
{ {
ASSERT (cmd_saveptr != NULL);
ASSERT (esp != NULL);
ASSERT (file_name != NULL);
/* Load command line argument *data* to user process stack. /* Load command line argument *data* to user process stack.
This can't cause overflow due to enforcing that the size of This can't cause overflow due to enforcing that the size of
command line input must fit in a page. Also keep track command line input must fit in a page. Also keep track
@@ -206,12 +207,8 @@ process_init_stack (char *cmd_saveptr, void **esp, char *file_name)
int arg_count = 0; int arg_count = 0;
while (arg != NULL) while (arg != NULL)
{ {
/* filename has already been validated to be a safe-to-access string,
so we can safely use strlen here. Filename has already been
split from the command line arguments. */
push_to_stack (esp, arg, (strlen (arg) + 1) * sizeof (char)); push_to_stack (esp, arg, (strlen (arg) + 1) * sizeof (char));
/* Try to allocate memory for the argument pointer. */
struct arg_elem *arg_elem = malloc (sizeof (struct arg_elem)); struct arg_elem *arg_elem = malloc (sizeof (struct arg_elem));
if (arg_elem == NULL) if (arg_elem == NULL)
{ {
@@ -220,11 +217,9 @@ process_init_stack (char *cmd_saveptr, void **esp, char *file_name)
return false; return false;
} }
/* Store the argument pointer in the linked list. */
arg_elem->arg = *esp; arg_elem->arg = *esp;
list_push_front (&arg_list, &arg_elem->elem); list_push_front (&arg_list, &arg_elem->elem);
/* Increment the argument count and get the next argument. */
arg_count++; arg_count++;
arg = strtok_r (NULL, " ", &cmd_saveptr); arg = strtok_r (NULL, " ", &cmd_saveptr);
} }
@@ -240,22 +235,13 @@ process_init_stack (char *cmd_saveptr, void **esp, char *file_name)
+ return_addr_size; + return_addr_size;
/* If pushing the rest of the data required for the stack would cause /* If pushing the rest of the data required for the stack would cause
overflow, allocate as many extra pages as needed to the user process overflow, allocate an extra page that is contiguous within the
contiguously in the virtual address space below the initial page. */ virtual address space (below the current address range). */
int overflow_bytes = (PHYS_BASE - *esp) + remaining_size - PGSIZE; if (PHYS_BASE - *esp + remaining_size > PGSIZE)
if (overflow_bytes > 0)
{ {
/* Calculate the number of pages needed to allocate. */ uint8_t *kpage = palloc_get_page (PAL_USER | PAL_ZERO);
int pages_needed = DIV_CEIL (overflow_bytes, PGSIZE); if (!install_page (((uint8_t *) PHYS_BASE) - PGSIZE * 2, kpage, true))
return false;
/* Allocate the pages and map them to the user process. */
for (int i = 1; i < pages_needed + 1; i++)
{
uint8_t *kpage = palloc_get_page (PAL_USER | PAL_ZERO);
if (!install_page (((uint8_t *) PHYS_BASE) - PGSIZE * (i + 1),
kpage, true))
return false;
}
} }
/* Align stack pointer to word size before pushing argv elements for /* Align stack pointer to word size before pushing argv elements for
@@ -313,12 +299,11 @@ push_to_stack (void **esp, void *data, size_t data_size)
* This function will be implemented in task 2. * This function will be implemented in task 2.
* For now, it does nothing. */ * For now, it does nothing. */
int int
process_wait (tid_t child_tid) process_wait (tid_t child_tid UNUSED)
{ {
struct process_result *child_result = NULL; struct process_result *child_result = NULL;
struct list_elem *e; struct list_elem *e;
struct thread *cur = thread_current (); struct thread *cur = thread_current ();
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); e = list_next (e))
{ {
@@ -326,40 +311,27 @@ process_wait (tid_t child_tid)
= list_entry (e, struct process_result, elem); = list_entry (e, struct process_result, elem);
if (result->tid == child_tid) if (result->tid == child_tid)
{ {
/* Found the child process. */
child_result = result; child_result = result;
break; break;
} }
/* List is ordered, allowing us to break early. */
/* List is ordered, allowing us to break early if the child_tid is
greater than the current result's tid. */
else if (result->tid > child_tid) else if (result->tid > child_tid)
break; break;
} }
/* If the child process was not found, return -1. */
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
wait) for it here to ensure we don't free the lock memory before it is wait) for it here to ensure we don't free the lock memory before it is
released in process_exit. */ released in process_exit. */
lock_acquire (&child_result->lock); lock_acquire (&child_result->lock);
/* To prevent waiting for child twice, remove it from the list. /* To prevent waiting for child twice, remove it from the list.
No need to use lock since this is the only thread with access to No need to use lock since this is the only thread with access to
the struct process_result now. */ the struct process_result now. */
list_remove (&child_result->elem); list_remove (&child_result->elem);
/* Get the exit status of the child */
int exit_status = child_result->exit_status; int exit_status = child_result->exit_status;
/* Release the lock */
lock_release (&child_result->lock); lock_release (&child_result->lock);
free (child_result); free (child_result);
return exit_status; return exit_status;
} }
@@ -376,10 +348,9 @@ 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);
/* Close the executable file, implicitly allowing it to be written to. */ /* Close the executable file. */
if (cur->exec_file != NULL) if (cur->exec_file != NULL)
{ {
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
file_close (cur->exec_file); file_close (cur->exec_file);
lock_release (&filesys_lock); lock_release (&filesys_lock);

View File

@@ -16,6 +16,8 @@
#define MAX_SYSCALL_ARGS 3 #define MAX_SYSCALL_ARGS 3
#define EXIT_FAILURE -1 #define EXIT_FAILURE -1
static unsigned fd_counter = MIN_USER_FD;
struct open_file struct open_file
{ {
int fd; /* File Descriptor / Identifier */ int fd; /* File Descriptor / Identifier */
@@ -140,7 +142,6 @@ syscall_exit (int status)
static pid_t static pid_t
syscall_exec (const char *cmd_line) syscall_exec (const char *cmd_line)
{ {
/* Validate the user string before executing the process. */
validate_user_string (cmd_line); validate_user_string (cmd_line);
return process_execute (cmd_line); /* Returns the PID of the new process */ return process_execute (cmd_line); /* Returns the PID of the new process */
@@ -160,15 +161,12 @@ syscall_wait (pid_t pid)
static bool static bool
syscall_create (const char *file, unsigned initial_size) syscall_create (const char *file, unsigned initial_size)
{ {
/* Validate the user string before creating the file. */
validate_user_string (file); validate_user_string (file);
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_create (file, initial_size); bool status = filesys_create (file, initial_size);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Return the status of the file creation. */
return status; return status;
} }
@@ -178,15 +176,12 @@ syscall_create (const char *file, unsigned initial_size)
static bool static bool
syscall_remove (const char *file) syscall_remove (const char *file)
{ {
/* Validate the user string before removing the file. */
validate_user_string (file); validate_user_string (file);
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
bool status = filesys_remove (file); bool status = filesys_remove (file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Return the status of the file removal. */
return status; return status;
} }
@@ -197,15 +192,11 @@ syscall_remove (const char *file)
static int static int
syscall_open (const char *file) syscall_open (const char *file)
{ {
/* Validate the user string before opening the file. */
validate_user_string (file); validate_user_string (file);
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
struct file *ptr = filesys_open (file); struct file *ptr = filesys_open (file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* If the file could not be opened, return failure. */
if (ptr == NULL) if (ptr == NULL)
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -215,14 +206,12 @@ syscall_open (const char *file)
= (struct open_file*) malloc (sizeof (struct open_file)); = (struct open_file*) malloc (sizeof (struct open_file));
if (file_info == NULL) if (file_info == NULL)
{ {
/* If we could not allocate memory for the file_info struct, close the
file and return failure. */
file_close (ptr); file_close (ptr);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* Populate the above struct, with a unique FD and the current open file */ /* Populate the above struct, with a unique FD and the current open file */
file_info->fd = thread_current ()->fd_counter++; file_info->fd = fd_counter++;
file_info->file = ptr; file_info->file = ptr;
/* Add the new FD->file mapping to the hashtable for the current thread */ /* Add the new FD->file mapping to the hashtable for the current thread */
@@ -238,17 +227,14 @@ syscall_open (const char *file)
static int static int
syscall_filesize (int fd) syscall_filesize (int fd)
{ {
/* Try to get the file from the FD. If it does not exist, return failure. */
struct open_file *file_info = fd_get_file (fd); struct open_file *file_info = fd_get_file (fd);
if (file_info == NULL) if (file_info == NULL)
return EXIT_FAILURE; return EXIT_FAILURE;
/* Acquire the file system lock to prevent any race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
int bytes = file_length (file_info->file); int bytes = file_length (file_info->file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Return the number of bytes in the file. */
return bytes; return bytes;
} }
@@ -261,10 +247,9 @@ syscall_read (int fd, void *buffer, unsigned size)
{ {
/* Only console (fd = 0) or other files, not including STDOUT, (fd > 1) are /* Only console (fd = 0) or other files, not including STDOUT, (fd > 1) are
allowed. */ allowed. */
if (fd < STDIN_FILENO || fd == STDOUT_FILENO) if (fd < 0 || fd == STDOUT_FILENO)
return EXIT_FAILURE; return EXIT_FAILURE;
/* Validate the user buffer for the provided size before reading. */
validate_user_pointer (buffer, size); validate_user_pointer (buffer, size);
if (fd == STDIN_FILENO) if (fd == STDIN_FILENO)
@@ -274,24 +259,18 @@ syscall_read (int fd, void *buffer, unsigned size)
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
write_buffer[i] = input_getc (); write_buffer[i] = input_getc ();
/* In case of console, read is always (eventually) successful. So return
the size for the number of bytes read. */
return size; return size;
} }
else else
{ {
/* Reading from a file. */ /* Reading from a file. */
/* Find the file from the FD. If it does not exist, return failure. */
struct open_file *file_info = fd_get_file (fd); struct open_file *file_info = fd_get_file (fd);
if (file_info == NULL) if (file_info == NULL)
return EXIT_FAILURE; return EXIT_FAILURE;
/* Acquire the file system lock to prevent race-conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
int bytes_written = file_read (file_info->file, buffer, size); int bytes_written = file_read (file_info->file, buffer, size);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Return the number of bytes read. */
return bytes_written; return bytes_written;
} }
} }
@@ -308,32 +287,25 @@ syscall_write (int fd, const void *buffer, unsigned size)
if (fd <= 0) if (fd <= 0)
return 0; return 0;
/* Validate the user buffer for the provided size before writing. */
validate_user_pointer (buffer, size); validate_user_pointer (buffer, size);
if (fd == STDOUT_FILENO) if (fd == STDOUT_FILENO)
{ {
/* Writing to the console. */ /* Writing to the console. */
putbuf (buffer, size); putbuf (buffer, size);
/* In case of console, write is always successful. So return the size for
the number of bytes written. */
return size; return size;
} }
else else
{ {
/* Writing to a file. */ /* Writing to a file. */
/* Find the file from the FD. If it does not exist, return failure. */
struct open_file *file_info = fd_get_file (fd); struct open_file *file_info = fd_get_file (fd);
if (file_info == NULL) if (file_info == NULL)
return 0; return 0;
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
int bytes = file_write (file_info->file, buffer, size); int bytes = file_write (file_info->file, buffer, size);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Return the number of bytes written. */
return bytes; return bytes;
} }
} }
@@ -345,11 +317,9 @@ syscall_write (int fd, const void *buffer, unsigned size)
static void static void
syscall_seek (int fd, unsigned position) syscall_seek (int fd, unsigned position)
{ {
/* Find the file from the FD. If it does not exist, do nothing. */
struct open_file *file_info = fd_get_file (fd); struct open_file *file_info = fd_get_file (fd);
if (file_info != NULL) if (file_info != NULL)
{ {
/* File exists: Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
file_seek (file_info->file, position); file_seek (file_info->file, position);
lock_release (&filesys_lock); lock_release (&filesys_lock);
@@ -362,17 +332,14 @@ syscall_seek (int fd, unsigned position)
static unsigned static unsigned
syscall_tell (int fd) syscall_tell (int fd)
{ {
/* Find the file from the FD. If it does not exist, return 0. */
struct open_file *file_info = fd_get_file (fd); struct open_file *file_info = fd_get_file (fd);
if (file_info == NULL) if (file_info == NULL)
return 0; return 0;
/* Acquire the file system lock to prevent race conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
unsigned pos = file_tell (file_info->file); unsigned pos = file_tell (file_info->file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Return the current position in the file. */
return pos; return pos;
} }
@@ -382,21 +349,14 @@ syscall_tell (int fd)
static void static void
syscall_close (int fd) syscall_close (int fd)
{ {
/* Find the file from the FD. If it does not exist, do nothing. */
struct open_file *file_info = fd_get_file (fd); struct open_file *file_info = fd_get_file (fd);
if (file_info != NULL) if (file_info != NULL)
{ {
/* File exists */
/* First, remove the file from the hash table of open files. */
hash_delete (&thread_current ()->open_files, &file_info->elem); hash_delete (&thread_current ()->open_files, &file_info->elem);
/* Then, close the file, acquiring the file system lock to prevent race
conditions. */
lock_acquire (&filesys_lock); lock_acquire (&filesys_lock);
file_close (file_info->file); file_close (file_info->file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
/* Free the memory allocated for the file_info struct. */
free (file_info); free (file_info);
} }
} }
@@ -406,12 +366,7 @@ syscall_close (int fd)
unsigned unsigned
fd_hash (const struct hash_elem *element, void *aux UNUSED) fd_hash (const struct hash_elem *element, void *aux UNUSED)
{ {
/* We use the FD as the hash value. This is because the FD is incremented return hash_int (hash_entry (element, struct open_file, elem)->fd);
sequentially and is therefore unique for each file. It positively affects
the performance of the hash table: 1. It is unique so no need to call
expensive hash functions. 2. It being sequential means that the hash table
is more likely to be weight balanced. */
return hash_entry (element, struct open_file, elem)->fd;
} }
/* Comparator function for the open_file table. Compares two entries based on /* Comparator function for the open_file table. Compares two entries based on
@@ -466,19 +421,17 @@ fd_get_file (int fd)
static void static void
validate_user_pointer (const void *start, size_t size) validate_user_pointer (const void *start, size_t size)
{ {
/* If the size is 0, we do not need to check anything. */
if (size == 0) if (size == 0)
return; return;
const void *end = start + size - 1; const void *end = start + size - 1;
/* Check if the start and end pointers are valid user virtual addresses. */
if (start == NULL || !is_user_vaddr (start) || !is_user_vaddr (end)) if (start == NULL || !is_user_vaddr (start) || !is_user_vaddr (end))
syscall_exit (EXIT_FAILURE); syscall_exit (EXIT_FAILURE);
/* We now need to check if the entire memory block is mapped to physical /* We now need to check if the entire memory block is mapped to physical
memory by the page table. */ memory by the page table. */
for (const void *ptr = pg_round_down (start); ptr <= end; ptr += PGSIZE) for (const void *ptr = start; ptr <= end; ptr += PGSIZE)
if (pagedir_get_page (thread_current ()->pagedir, ptr) == NULL) if (pagedir_get_page (thread_current ()->pagedir, ptr) == NULL)
syscall_exit (EXIT_FAILURE); syscall_exit (EXIT_FAILURE);
} }
@@ -489,11 +442,9 @@ validate_user_pointer (const void *start, size_t size)
static void static void
validate_user_string (const char *str) validate_user_string (const char *str)
{ {
/* Check if the string pointer is a valid user virtual address. */
if (str == NULL || !is_user_vaddr (str)) if (str == NULL || !is_user_vaddr (str))
syscall_exit (EXIT_FAILURE); syscall_exit (EXIT_FAILURE);
/* Calculate the offset of the string within the (first) page. */
size_t offset = (uintptr_t) str % PGSIZE; size_t offset = (uintptr_t) str % PGSIZE;
/* We move page by page, checking if the page is mapped to physical memory. */ /* We move page by page, checking if the page is mapped to physical memory. */
@@ -501,8 +452,6 @@ validate_user_string (const char *str)
{ {
void *page = pg_round_down (str); void *page = pg_round_down (str);
/* If we reach addresses that are not mapped to physical memory before the
end of the string, the thread is terminated. */
if (!is_user_vaddr(page) || if (!is_user_vaddr(page) ||
pagedir_get_page (thread_current ()->pagedir, page) == NULL) pagedir_get_page (thread_current ()->pagedir, page) == NULL)
syscall_exit (EXIT_FAILURE); syscall_exit (EXIT_FAILURE);

View File

@@ -4,6 +4,8 @@
#include <hash.h> #include <hash.h>
#include "threads/synch.h" #include "threads/synch.h"
#define MIN_USER_FD 2
typedef int pid_t; typedef int pid_t;
struct lock filesys_lock; struct lock filesys_lock;