Fix virtio net handling of the header.
[akaros.git] / user / parlib / signal.c
index b1103a5..12b1d49 100644 (file)
@@ -56,6 +56,7 @@ static int __sigtimedwait(__const sigset_t *__restrict __set,
 static int __sigwait(__const sigset_t *__restrict __set, int *__restrict __sig);
 static int __sigwaitinfo(__const sigset_t *__restrict __set,
                          siginfo_t *__restrict __info);
+static int __sigself(int signo);
 
 /* The default definition of signal_ops (similar to sched_ops in uthread.c) */
 struct signal_ops default_signal_ops = {
@@ -69,7 +70,8 @@ struct signal_ops default_signal_ops = {
        .sigsuspend = __sigsuspend,
        .sigtimedwait = __sigtimedwait,
        .sigwait = __sigwait,
-       .sigwaitinfo = __sigwaitinfo
+       .sigwaitinfo = __sigwaitinfo,
+       .sigself = __sigself
 };
 
 /* This is the catch all akaros event->posix signal handler.  All posix signals
@@ -81,10 +83,21 @@ static void handle_event(struct event_msg *ev_msg, unsigned int ev_type,
        int sig_nr;
        struct siginfo info = {0};
        info.si_code = SI_USER;
+       struct user_context fake_uctx;
 
        assert(ev_msg);
        sig_nr = ev_msg->ev_arg1;
-       trigger_posix_signal(sig_nr, &info, 0);
+       /* We're handling a process-wide signal, but signal handlers will want a
+        * user context.  They operate on the model that some thread got the signal,
+        * but that didn't happen on Akaros.  If we happen to have a current
+        * uthread, we can use that - perhaps that's what the user wants.  If not,
+        * we'll build a fake one representing our current call stack. */
+       if (current_uthread) {
+               trigger_posix_signal(sig_nr, &info, get_cur_uth_ctx());
+       } else {
+               init_user_ctx(&fake_uctx, (uintptr_t)handle_event, get_stack_pointer());
+               trigger_posix_signal(sig_nr, &info, &fake_uctx);
+       }
 }
 
 /* Called from uthread_slim_init() */
@@ -111,9 +124,24 @@ static void swap_user_contexts(struct user_context *c1, struct user_context *c2)
        *c2 = temp_ctx;
 }
 
-/* Prep a to run a signal handler.  The original context of the uthread
- * is saved on its stack, and a new context is set up to run the signal
- * handler the next time the uthread is run. */
+/* Helper for checking a stack pointer.  It's possible the context we're
+ * injecting signals into is complete garbage, so using the SP is a little
+ * dangerous. */
+static bool stack_ptr_is_sane(uintptr_t sp)
+{
+       if ((sp < PGSIZE) || (sp > ULIM))
+               return FALSE;
+       return TRUE;
+}
+
+static bool uth_is_handling_sigs(struct uthread *uth)
+{
+       return uth->sigstate.data ? TRUE : FALSE;
+}
+
+/* Prep a uthread to run a signal handler.  The original context of the uthread
+ * is saved on its stack, and a new context is set up to run the signal handler
+ * the next time the uthread is run. */
 static void __prep_sighandler(struct uthread *uthread,
                               void (*entry)(void),
                               struct siginfo *info)
@@ -124,6 +152,7 @@ static void __prep_sighandler(struct uthread *uthread,
        if (uthread->flags & UTHREAD_SAVED) {
                ctx = &uthread->u_ctx;
                stack = get_user_ctx_stack(ctx) - sizeof(struct sigdata);
+               assert(stack_ptr_is_sane(stack));
                uthread->sigstate.data = (struct sigdata*)stack;
                if (uthread->flags & UTHREAD_FPSAVED) {
                        uthread->sigstate.data->as = uthread->as;
@@ -133,6 +162,7 @@ static void __prep_sighandler(struct uthread *uthread,
                assert(current_uthread == uthread);
                ctx = &vcpd_of(vcore_id())->uthread_ctx;
                stack = get_user_ctx_stack(ctx) - sizeof(struct sigdata);
+               assert(stack_ptr_is_sane(stack));
                uthread->sigstate.data = (struct sigdata*)stack;
                save_fp_state(&uthread->sigstate.data->as);
        }
@@ -149,9 +179,12 @@ static void __restore_after_sighandler(struct uthread *uthread)
 {
        uthread->u_ctx = uthread->sigstate.data->u_ctx;
        uthread->flags |= UTHREAD_SAVED;
-       if (uthread->u_ctx.type == ROS_HW_CTX) {
+       switch (uthread->u_ctx.type) {
+       case ROS_HW_CTX:
+       case ROS_VM_CTX:
                uthread->as = uthread->sigstate.data->as;
                uthread->flags |= UTHREAD_FPSAVED;
+               break;
        }
        uthread->sigstate.data = NULL;
 }
@@ -211,7 +244,7 @@ int uthread_signal(struct uthread *uthread, int signo)
  * handler is complete, the original context will be restored and restarted. */
 void uthread_prep_pending_signals(struct uthread *uthread)
 {
-       if (!uthread->sigstate.data && uthread->sigstate.pending) {
+       if (!uth_is_handling_sigs(uthread) && uthread->sigstate.pending) {
                sigset_t andset = uthread->sigstate.pending & (~uthread->sigstate.mask);
 
                if (!__sigisemptyset(&andset))
@@ -229,7 +262,7 @@ void uthread_prep_signal_from_fault(struct uthread *uthread,
        if (!__sigismember(&uthread->sigstate.mask, signo)) {
                struct siginfo info = {0};
 
-               if (uthread->sigstate.data) {
+               if (uth_is_handling_sigs(uthread)) {
                        printf("Uthread sighandler faulted, signal: %d\n", signo);
                        /* uthread.c already copied out the faulting ctx into the uth */
                        print_user_context(&uthread->u_ctx);
@@ -265,7 +298,20 @@ static int __sigpending(sigset_t *__set)
 static int __sigprocmask(int __how, __const sigset_t *__restrict __set,
                          sigset_t *__restrict __oset)
 {
-       sigset_t *sigmask = &current_uthread->sigstate.mask;
+       sigset_t *sigmask;
+
+       /* Signal handlers might call sigprocmask, with the intent of affecting the
+        * uthread's sigmask.  Process-wide signal handlers run on behalf of the
+        * entire process and aren't bound to a uthread, which means sigprocmask
+        * won't work.  We can tell we're running one of these handlers since we are
+        * in vcore context.  Uthread signals (e.g. pthread_kill()) run from uthread
+        * context. */
+       if (in_vcore_context()) {
+               errno = ENOENT;
+               return -1;
+       }
+
+       sigmask = &current_uthread->sigstate.mask;
 
        if (__set && (__how != SIG_BLOCK) &&
                     (__how != SIG_SETMASK) &&
@@ -339,3 +385,20 @@ static int __sigwaitinfo(__const sigset_t *__restrict __set,
        return 0;
 }
 
+static int __sigself(int signo)
+{
+       int ret;
+
+       if (in_vcore_context())
+               return kill(getpid(), signo);
+
+       ret = uthread_signal(current_uthread, signo);
+
+       void cb(struct uthread *uthread, void *arg)
+       {
+               uthread_paused(uthread);
+       }
+       if (ret == 0)
+               uthread_yield(TRUE, cb, 0);
+       return ret;
+}