Merge branch 'system-calls' into 'user-programs'

# Conflicts:
#   src/userprog/process.c

Fix conflict in differing placeholder process_wait implementations
This commit is contained in:
Dias Alberto, Ethan
2024-11-06 16:56:43 +00:00
6 changed files with 240 additions and 16 deletions

View File

@@ -113,28 +113,33 @@ void
sema_up (struct semaphore *sema) sema_up (struct semaphore *sema)
{ {
enum intr_level old_level; enum intr_level old_level;
bool thread_unblocked = false; /* Flag to track if any thread was woken up. */
ASSERT (sema != NULL); ASSERT (sema != NULL);
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;
}
sema->value++; sema->value++;
intr_set_level (old_level); intr_set_level (old_level);
/* Yields the CPU in case the thread that has been woken up has a higher /* Yields the CPU in case the thread that has been woken up has a higher
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 (intr_context ()) if (thread_unblocked)
intr_yield_on_return (); {
else if (intr_context ())
thread_yield (); intr_yield_on_return ();
else
thread_yield ();
}
} }
static void sema_test_helper (void *sema_); static void sema_test_helper (void *sema_);
@@ -347,7 +352,6 @@ lock_release (struct lock *lock)
lock->holder = NULL; lock->holder = NULL;
sema_up (&lock->semaphore); sema_up (&lock->semaphore);
thread_yield ();
} }
/* Returns true if the current thread holds LOCK, false /* Returns true if the current thread holds LOCK, false

View File

@@ -659,6 +659,8 @@ 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->exit_status = -1;
old_level = intr_disable (); old_level = intr_disable ();
list_push_back (&all_list, &t->allelem); list_push_back (&all_list, &t->allelem);
intr_set_level (old_level); intr_set_level (old_level);

View File

@@ -111,6 +111,7 @@ struct thread
/* Shared between thread.c and synch.c. */ /* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */ struct list_elem elem; /* List element. */
int exit_status; /* Exit Status: 0 = successful exit. */
#ifdef USERPROG #ifdef USERPROG
/* Owned by userprog/process.c. */ /* Owned by userprog/process.c. */

View File

@@ -14,6 +14,7 @@
#include "threads/flags.h" #include "threads/flags.h"
#include "threads/init.h" #include "threads/init.h"
#include "threads/interrupt.h" #include "threads/interrupt.h"
#include "threads/synch.h"
#include "threads/palloc.h" #include "threads/palloc.h"
#include "threads/thread.h" #include "threads/thread.h"
#include "threads/vaddr.h" #include "threads/vaddr.h"

View File

@@ -1,11 +1,68 @@
#include "userprog/syscall.h" #include "userprog/syscall.h"
#include <stdio.h> #include "devices/shutdown.h"
#include <syscall-nr.h> #include "devices/input.h"
#include "threads/vaddr.h"
#include "threads/interrupt.h" #include "threads/interrupt.h"
#include "threads/thread.h" #include "threads/thread.h"
#include "userprog/process.h"
#include <stdio.h>
#include <syscall-nr.h>
static void syscall_handler (struct intr_frame *); static void syscall_handler (struct intr_frame *);
/* A syscall_function is a function that receives up to 3 arguments, the
arguments to the functions are either ints or pointers taking up to 32 bits
in size. */
typedef uintptr_t (*syscall_function) (uintptr_t, uintptr_t, uintptr_t);
/* System call function prototypes */
static void syscall_halt (void);
static void syscall_exit (int status);
static pid_t syscall_exec (const char *cmd_line);
static int syscall_wait (pid_t pid);
static bool syscall_create (const char *file, unsigned initial_size);
static bool syscall_remove (const char *file);
static int syscall_open (const char *file);
static int syscall_filesize (int fd);
static int syscall_read (int fd, void *buffer, unsigned size);
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 void *validate_user_pointer (const void *ptr, size_t size);
/* A struct defining a syscall_function pointer along with its arity. */
typedef struct
{
syscall_function function; /* Function pointer. */
int arity; /* Number of arguments of the function. */
} syscall_arguments;
/* A look-up table mapping numbers to system call functions with their number of
arguments. */
static const syscall_arguments syscall_lookup[] =
{
[SYS_HALT] = {(syscall_function) syscall_halt, 0},
[SYS_EXIT] = {(syscall_function) syscall_exit, 1},
[SYS_EXEC] = {(syscall_function) syscall_exec, 1},
[SYS_WAIT] = {(syscall_function) syscall_wait, 1},
[SYS_CREATE] = {(syscall_function) syscall_create, 2},
[SYS_REMOVE] = {(syscall_function) syscall_remove, 1},
[SYS_OPEN] = {(syscall_function) syscall_open, 1},
[SYS_FILESIZE] = {(syscall_function) syscall_filesize, 1},
[SYS_READ] = {(syscall_function) syscall_read, 3},
[SYS_WRITE] = {(syscall_function) syscall_write, 3},
[SYS_SEEK] = {(syscall_function) syscall_seek, 2},
[SYS_TELL] = {(syscall_function) syscall_tell, 1},
[SYS_CLOSE] = {(syscall_function) syscall_close, 1},
};
/* The number of syscall functions (i.e, number of elements) within the
syscall_lookup table. */
static const int LOOKUP_SIZE
= sizeof (syscall_lookup) / sizeof (syscall_arguments);
void void
syscall_init (void) syscall_init (void)
{ {
@@ -13,8 +70,165 @@ syscall_init (void)
} }
static void static void
syscall_handler (struct intr_frame *f UNUSED) syscall_handler (struct intr_frame *f)
{ {
printf ("system call!\n"); /* First, read the system call number from the stack. */
validate_user_pointer (f->esp, 1);
unsigned syscall_number = *(int *) f->esp;
/* Ensures the number corresponds to a system call that can be handled. */
if (syscall_number >= LOOKUP_SIZE)
thread_exit ();
syscall_arguments syscall = syscall_lookup[syscall_number];
/* Next, read and copy the arguments from the stack pointer. */
validate_user_pointer (f->esp + sizeof (uintptr_t),
syscall.arity * sizeof (uintptr_t));
uintptr_t args[3] = {0};
for (int i=0; i < syscall.arity; i++)
args[i] = *(uintptr_t *) (f->esp + sizeof (uintptr_t) * (i + 1));
/* Call the function that handles this system call with the arguments. When
there is a return value it is stored in f->eax. */
f->eax = syscall.function (args[0], args[1], args[2]);
}
static void
syscall_halt (void)
{
shutdown_power_off ();
}
static void
syscall_exit (int status)
{
/* Sets exit_status of the thread to status. thread_exit () will call
process_exit () if user programs are allowed. */
thread_current ()->exit_status = status;
thread_exit (); thread_exit ();
} }
static pid_t
syscall_exec (const char *cmd_line UNUSED)
{
//TODO
return 0;
}
static int
syscall_wait (pid_t pid)
{
return process_wait (pid);
}
static bool
syscall_create (const char *file UNUSED, unsigned initial_size UNUSED)
{
//TODO
return 0;
}
static bool
syscall_remove (const char *file UNUSED)
{
//TODO
return 0;
}
static int
syscall_open (const char *file UNUSED)
{
//TODO
return 0;
}
static int
syscall_filesize (int fd UNUSED)
{
//TODO
return 0;
}
static int
syscall_read (int fd, void *buffer, unsigned size)
{
/* Only console (fd = 0) or other files, not including STDOUT, (fd > 1) are
allowed. */
if (fd < 0 && fd != STDOUT_FILENO)
return -1;
validate_user_pointer (buffer, size);
if (fd == STDIN_FILENO)
{
/* Reading from the console. */
char *write_buffer = buffer;
for (int i = 0; i < size; i++)
write_buffer[i] = input_getc ();
return size;
}
else
{
/* Reading from a file. */
return 0; // TODO: Implement Write to Files
}
}
static int
syscall_write (int fd, const void *buffer, unsigned size)
{
/* Only console (fd = 1) or other files, not including STDIN, (fd > 1) are
allowed. */
if (fd <= 0)
return 0;
validate_user_pointer (buffer, size);
if (fd == STDOUT_FILENO)
{
/* Writing to the console. */
putbuf (buffer, size);
return size;
}
else
{
/* Writing to a file. */
return 0; // TODO: Implement Write to Files
}
}
static void
syscall_seek (int fd UNUSED, unsigned position UNUSED)
{
//TODO
}
static unsigned
syscall_tell (int fd UNUSED)
{
//TODO
return 0;
}
static void
syscall_close (int fd UNUSED)
{
//TODO
}
/* Validates if a block of memory starting at PTR and of size SIZE bytes is
fully contained within user virtual memory. Kills the thread (by calling
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.*/
static void *
validate_user_pointer (const void *ptr, size_t size)
{
if (size > 0 && (ptr == NULL ||
!is_user_vaddr (ptr) ||
!is_user_vaddr (ptr + size - 1)))
thread_exit ();
return ptr;
}

View File

@@ -1,6 +1,8 @@
#ifndef USERPROG_SYSCALL_H #ifndef USERPROG_SYSCALL_H
#define USERPROG_SYSCALL_H #define USERPROG_SYSCALL_H
typedef int pid_t;
void syscall_init (void); void syscall_init (void);
#endif /* userprog/syscall.h */ #endif /* userprog/syscall.h */