Fixes bug in cpu_relax_vc()
[akaros.git] / user / parlib / signal.c
index df3c7b8..dacc1c3 100644 (file)
@@ -1,5 +1,6 @@
 /* Copyright (c) 2013 The Regents of the University of California
  * Barret Rhoden <brho@cs.berkeley.edu>
+ * Kevin Klues <klueska@cs.berkeley.edu>
  * See LICENSE for details.
  *
  * POSIX signal handling glue.  All glibc programs link against parlib, so they
 #include <signal.h>
 #include <stdio.h>
 
+#include <parlib.h>
 #include <event.h>
+#include <errno.h>
 #include <assert.h>
+#include <ros/procinfo.h>
+#include <ros/syscall.h>
+#include <sys/mman.h>
+#include <vcore.h> /* for print_user_context() */
+#include <waitfreelist.h>
 
-struct sigaction sigactions[_NSIG - 1];
+/* This is list of sigactions associated with each posix signal. */
+static struct sigaction sigactions[_NSIG - 1];
 
-void handle_posix_signal(struct event_msg *ev_msg, unsigned int ev_type)
+/* This is a wait-free-list used to hold the data necessary to execute signal
+ * handlers inside a 2LS. We are able to store them in a wfl because all
+ * sigdata structs are created equal, and reuse is encouraged as uthreads
+ * ask for them on demand. */
+static struct wfl sigdata_list;
+#define SIGNAL_STACK_SIZE (2*PGSIZE + sizeof(struct sigdata))
+
+/* These are the default handlers for each posix signal.  They are listed in
+ * SIGNAL(7) of the Linux Programmer's Manual.  We run them as default
+ * sigactions, instead of the older handlers, so that we have access to the
+ * faulting context.
+ *
+ * Exit codes are set as suggested in the following link.  I wish I could find
+ * the definitive source, but this will have to do for now.
+ * http://unix.stackexchange.com/questions/99112/default-exit-code-when-process-is-terminated
+ * */
+static void default_term_handler(int signr, siginfo_t *info, void *ctx)
+{
+       ros_syscall(SYS_proc_destroy, __procinfo.pid, signr, 0, 0, 0, 0);
+}
+
+static void default_core_handler(int signr, siginfo_t *info, void *ctx)
+{
+       fprintf(stderr, "Segmentation Fault (sorry, no core dump yet)\n");
+       print_user_context((struct user_context*)ctx);
+       if (info) {
+               /* ghetto, we don't have access to the PF err, since we only have a few
+                * fields available in siginfo (e.g. there's no si_trapno). */
+               fprintf(stderr, "Fault type %d at addr %p\n", info->si_errno,
+                       info->si_addr);
+       } else {
+               fprintf(stderr, "No fault info\n");
+       }
+       default_term_handler((1 << 7) + signr, info, ctx);
+}
+
+static void default_stop_handler(int signr, siginfo_t *info, void *ctx)
+{
+       fprintf(stderr, "Stop signal received!  No support to stop yet though!\n");
+}
+
+static void default_cont_handler(int signr, siginfo_t *info, void *ctx)
+{
+       fprintf(stderr, "Cont signal received!  No support to cont yet though!\n");
+}
+
+typedef void (*__sigacthandler_t)(int, siginfo_t *, void *);
+#define SIGACT_ERR     ((__sigacthandler_t) -1)        /* Error return.  */
+#define SIGACT_DFL     ((__sigacthandler_t) 0)         /* Default action.  */
+#define SIGACT_IGN     ((__sigacthandler_t) 1)         /* Ignore signal.  */
+
+static __sigacthandler_t default_handlers[] = {
+       [SIGHUP]    = default_term_handler, 
+       [SIGINT]    = default_term_handler, 
+       [SIGQUIT]   = default_core_handler, 
+       [SIGILL]    = default_core_handler, 
+       [SIGTRAP]   = default_core_handler, 
+       [SIGABRT]   = default_core_handler, 
+       [SIGIOT]    = default_core_handler, 
+       [SIGBUS]    = default_core_handler, 
+       [SIGFPE]    = default_core_handler, 
+       [SIGKILL]   = default_term_handler, 
+       [SIGUSR1]   = default_term_handler, 
+       [SIGSEGV]   = default_core_handler, 
+       [SIGUSR2]   = default_term_handler, 
+       [SIGPIPE]   = default_term_handler, 
+       [SIGALRM]   = default_term_handler, 
+       [SIGTERM]   = default_term_handler, 
+       [SIGSTKFLT] = default_term_handler, 
+       [SIGCHLD]   = SIGACT_IGN,
+       [SIGCONT]   = default_cont_handler, 
+       [SIGSTOP]   = default_stop_handler, 
+       [SIGTSTP]   = default_stop_handler, 
+       [SIGTTIN]   = default_stop_handler, 
+       [SIGTTOU]   = default_stop_handler, 
+       [SIGURG]    = default_term_handler, 
+       [SIGXCPU]   = SIGACT_IGN,
+       [SIGXFSZ]   = default_core_handler, 
+       [SIGVTALRM] = default_term_handler, 
+       [SIGPROF]   = default_term_handler, 
+       [SIGWINCH]  = SIGACT_IGN,
+       [SIGIO]     = default_term_handler, 
+       [SIGPWR]    = SIGACT_IGN,
+       [SIGSYS]    = default_core_handler
+};
+
+/* This function allocates a sigdata struct for use when running signal
+ * handlers inside a 2LS. The sigdata struct returned is pre-initialized with
+ * the 'stack' field pointing to a valid stack.  Space is allocated for both
+ * the sigdata struct and the stack in a single mmap call.  The sigdata struct
+ * just sits at the bottom of the stack, and its 'stack' field points just
+ * above it.  */
+struct sigdata *alloc_sigdata()
+{
+       struct sigdata *data = wfl_remove(&sigdata_list);
+       if (data == NULL) {
+               void *stack = mmap(0, SIGNAL_STACK_SIZE,
+                                  PROT_READ|PROT_WRITE|PROT_EXEC,
+                                  MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
+               assert(stack != MAP_FAILED);
+               data = stack + SIGNAL_STACK_SIZE - sizeof(struct sigdata);
+               data->stack = data;
+       }
+       return data;
+}
+
+/* This function frees a previously allocated sigdata struct. */
+void free_sigdata(struct sigdata *sigdata)
+{
+       wfl_insert(&sigdata_list, sigdata);
+}
+
+/* This is the akaros posix signal trigger.  Signals are dispatched from
+ * this function to their proper posix signal handler */
+void trigger_posix_signal(int sig_nr, struct siginfo *info, void *aux)
 {
-       int sig_nr;
        struct sigaction *action;
-       struct siginfo info = {0};
-       assert(ev_msg);
-       sig_nr = ev_msg->ev_arg1;
        if (sig_nr > _NSIG - 1 || sig_nr < 0)
                return;
        action = &sigactions[sig_nr];
@@ -49,41 +168,86 @@ void handle_posix_signal(struct event_msg *ev_msg, unsigned int ev_type)
                return;
        if (action->sa_handler == SIG_IGN)
                return;
-       if (action->sa_handler == SIG_DFL)      /* aka, 0 */
+       if (action->sa_handler == SIG_DFL) {
+               if (default_handlers[sig_nr] != SIGACT_IGN)
+                       default_handlers[sig_nr](sig_nr, info, aux);
                return;
+       }
+
        if (action->sa_flags & SA_SIGINFO) {
-               info.si_signo = sig_nr;
-               /* TODO: consider pid and whatnot */
-               action->sa_sigaction(sig_nr, &info, 0);
+               /* If NULL info struct passed in, construct our own */
+               struct siginfo s = {0};
+               if (info == NULL)
+                       info = &s;
+               /* Make sure the caller either already set singo in the info struct, or
+                * if they didn't, make sure it has been zeroed out (i.e. not just some
+                * garbage on the stack. */
+               assert(info->si_signo == sig_nr || info->si_signo == 0);
+               info->si_signo = sig_nr;
+               /* TODO: consider info->pid and whatnot */
+               /* We assume that this function follows the proper calling convention
+                * (i.e. it wasn't written in some crazy assembly function that
+                * trashes all its registers, i.e GO's default runtime handler) */
+               action->sa_sigaction(sig_nr, info, aux);
        } else {
                action->sa_handler(sig_nr);
        }
 }
 
+/* This is the catch all akaros event->posix signal handler.  All posix signals
+ * are received in a single akaros event type.  They are then dispatched from
+ * this function to their proper posix signal handler */
+static void handle_event(struct event_msg *ev_msg, unsigned int ev_type,
+                         void *data)
+{
+       int sig_nr;
+       struct siginfo info = {0};
+       info.si_code = SI_USER;
+
+       assert(ev_msg);
+       sig_nr = ev_msg->ev_arg1;
+       trigger_posix_signal(sig_nr, &info, 0);
+}
+
 /* Called from uthread_slim_init() */
 void init_posix_signals(void)
 {
        struct event_queue *posix_sig_ev_q;
-       ev_handlers[EV_POSIX_SIGNAL] = handle_posix_signal;
+       register_ev_handler(EV_POSIX_SIGNAL, handle_event, 0);
        posix_sig_ev_q = get_big_event_q();
        assert(posix_sig_ev_q);
        posix_sig_ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_FALLBACK;
        register_kevent_q(posix_sig_ev_q, EV_POSIX_SIGNAL);
+       wfl_init(&sigdata_list);
 }
 
-/* Will need to do these if we have signal masks (sigprocmask style) */
 int sigaddset(sigset_t *__set, int __signo)
 {
+       if (__signo == 0 || __signo > _NSIG) {
+               errno = EINVAL;
+               return -1;
+       }
+       __sigaddset(__set, __signo);
        return 0;
 }
 
 int sigdelset(sigset_t *__set, int __signo)
 {
+       if (__signo == 0 || __signo > _NSIG) {
+               errno = EINVAL;
+               return -1;
+       }
+       __sigdelset(__set, __signo);
        return 0;
 }
 
 int sigismember(__const sigset_t *__set, int __signo)
 {
+       if (__signo == 0 || __signo > _NSIG) {
+               errno = EINVAL;
+               return -1;
+       }
+       __sigismember(__set, __signo);
        return 0;
 }
 
@@ -93,6 +257,8 @@ int sigismember(__const sigset_t *__set, int __signo)
 int sigprocmask(int __how, __const sigset_t *__restrict __set,
                 sigset_t *__restrict __oset)
 {
+       printf("Function not supported generically! "
+           "Use 2LS specific function e.g. pthread_sigmask\n");
        return 0;
 }
 
@@ -144,7 +310,7 @@ int sigtimedwait(__const sigset_t *__restrict __set,
        return 0;
 }
 
-/* Needs support with handle_posix_signal to deal with passing values with POSIX
+/* Needs support with trigger_posix_signal to deal with passing values with POSIX
  * signals. */
 int sigqueue(__pid_t __pid, int __sig, __const union sigval __val)
 {
@@ -182,3 +348,17 @@ int sigaltstack(__const struct sigaltstack *__restrict __ss,
 {
        return 0;
 }
+
+__sighandler_t signal(int sig, __sighandler_t handler)
+{
+       int ret;
+       struct sigaction newsa = {0};
+       struct sigaction oldsa = {0};
+       newsa.sa_handler = handler;
+       ret = sigaction(sig, &newsa, &oldsa);
+       if (ret < 0) {
+               errno = EINVAL;
+               return SIG_ERR;
+       }
+       return oldsa.sa_handler;
+}