|  | /* 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 | 
|  | * will get this mixed in.  Mostly just registration of signal handlers. | 
|  | * | 
|  | * POSIX signal handling caveats: | 
|  | * - We don't copy signal handling tables or anything across forks or execs | 
|  | * - We don't send meaningful info in the siginfos, nor do we pass pid/uids on | 
|  | * signals coming from a kill.  This is especially pertinent for sigqueue, | 
|  | * which needs a payload (value) and sending PID | 
|  | * - We run handlers in vcore context, so any blocking syscall will spin. | 
|  | * Regular signals have restrictions on their syscalls too, though not this | 
|  | * great.  We could spawn off a uthread to run the handler, given that we have | 
|  | * a 2LS (which we don't for SCPs). | 
|  | * - We don't do anything with signal blocking/masking.  When in a signal | 
|  | * handler, you won't get interrupted with another signal handler (so long as | 
|  | * you run it in vcore context!).  With uthreads, you could get interrupted. | 
|  | * There is also no process wide signal blocking yet (sigprocmask()).  If this | 
|  | * is desired, we can abort certain signals when we h_p_signal(), | 
|  | * - Likewise, we don't do waiting for particular signals yet.  Just about the | 
|  | * only thing we do is allow the registration of signal handlers. | 
|  | * - Check each function for further notes.  */ | 
|  |  | 
|  | // Needed for sigmask functions... | 
|  | #define _GNU_SOURCE | 
|  |  | 
|  | #include <parlib/parlib.h> | 
|  | #include <parlib/signal.h> | 
|  | #include <parlib/uthread.h> | 
|  | #include <parlib/event.h> | 
|  | #include <parlib/ros_debug.h> | 
|  | #include <errno.h> | 
|  | #include <stdlib.h> | 
|  | #include <parlib/assert.h> | 
|  | #include <ros/procinfo.h> | 
|  | #include <ros/syscall.h> | 
|  | #include <sys/mman.h> | 
|  | #include <parlib/stdio.h> | 
|  |  | 
|  | /* Forward declare our signal_ops functions. */ | 
|  | static int __sigaltstack(__const struct sigaltstack *__restrict __ss, | 
|  | struct sigaltstack *__restrict __oss); | 
|  | static int __siginterrupt(int __sig, int __interrupt); | 
|  | static int __sigpending(sigset_t *__set); | 
|  | static int __sigprocmask(int __how, __const sigset_t *__restrict __set, | 
|  | sigset_t *__restrict __oset); | 
|  | static int __sigqueue(__pid_t __pid, int __sig, __const union sigval __val); | 
|  | static int __sigreturn(struct sigcontext *__scp); | 
|  | static int __sigstack(struct sigstack *__ss, struct sigstack *__oss); | 
|  | static int __sigsuspend(__const sigset_t *__set); | 
|  | static int __sigtimedwait(__const sigset_t *__restrict __set, | 
|  | siginfo_t *__restrict __info, | 
|  | __const struct timespec *__restrict __timeout); | 
|  | 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 = { | 
|  | .sigaltstack = __sigaltstack, | 
|  | .siginterrupt = __siginterrupt, | 
|  | .sigpending = __sigpending, | 
|  | .sigprocmask = __sigprocmask, | 
|  | .sigqueue = __sigqueue, | 
|  | .sigreturn = __sigreturn, | 
|  | .sigstack = __sigstack, | 
|  | .sigsuspend = __sigsuspend, | 
|  | .sigtimedwait = __sigtimedwait, | 
|  | .sigwait = __sigwait, | 
|  | .sigwaitinfo = __sigwaitinfo, | 
|  | .sigself = __sigself | 
|  | }; | 
|  |  | 
|  | /* 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; | 
|  | /* These POSIX signals are process-wide, but legacy applications and | 
|  | * their signal handlers often expect the signals to be routed to | 
|  | * particular threads.  This manifests in a couple ways: the signal | 
|  | * handlers expect a user context, and the program expects syscalls to | 
|  | * be interrupted.  Which context?  Which syscall? | 
|  | * | 
|  | * On Akaros, signals only go to the process, since there is no kernel | 
|  | * notion of a thread/task within a process.  All knowledge of | 
|  | * threads and how to resolve this mismatch between process-wide signals | 
|  | * and threads is held in the 2LS.  If we wanted to abort a syscall, | 
|  | * we'd need to know which one - after all, on Akaros syscalls are | 
|  | * asynchronous and it is only in the 2LS that they are coupled to | 
|  | * uthreads.  When it comes to routing the signal, the 2LS could do | 
|  | * something like pthread_kill, or just execute the handler. */ | 
|  | sched_ops->got_posix_signal(sig_nr, &info); | 
|  | } | 
|  |  | 
|  | /* Called from uthread_slim_init() */ | 
|  | void init_posix_signals(void) | 
|  | { | 
|  | struct event_queue *posix_sig_ev_q; | 
|  |  | 
|  | signal_ops = &default_signal_ops; | 
|  | register_ev_handler(EV_POSIX_SIGNAL, handle_event, 0); | 
|  | posix_sig_ev_q = get_eventq(EV_MBOX_UCQ); | 
|  | assert(posix_sig_ev_q); | 
|  | posix_sig_ev_q->ev_flags = EVENT_IPI | EVENT_INDIR | EVENT_SPAM_INDIR | | 
|  | EVENT_WAKEUP; | 
|  | register_kevent_q(posix_sig_ev_q, EV_POSIX_SIGNAL); | 
|  | } | 
|  |  | 
|  | /* Swap the contents of two user contexts (not just their pointers). */ | 
|  | static void swap_user_contexts(struct user_context *c1, struct user_context *c2) | 
|  | { | 
|  | struct user_context temp_ctx; | 
|  |  | 
|  | temp_ctx = *c1; | 
|  | *c1 = *c2; | 
|  | *c2 = temp_ctx; | 
|  | } | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | uintptr_t stack; | 
|  | struct user_context *ctx; | 
|  |  | 
|  | if (uthread->flags & UTHREAD_SAVED) { | 
|  | ctx = &uthread->u_ctx; | 
|  | } else { | 
|  | assert(current_uthread == uthread); | 
|  | ctx = &vcpd_of(vcore_id())->uthread_ctx; | 
|  | } | 
|  | stack = get_user_ctx_sp(ctx) - sizeof(struct sigdata); | 
|  | stack = ROUNDDOWN(stack, __alignof__(struct sigdata)); | 
|  | assert(stack_ptr_is_sane(stack)); | 
|  | uthread->sigstate.data = (struct sigdata*)stack; | 
|  | /* Parlib aggressively saves the FP state for HW and VM ctxs.  SW ctxs | 
|  | * should not have FP state saved. */ | 
|  | switch (ctx->type) { | 
|  | case ROS_HW_CTX: | 
|  | case ROS_VM_CTX: | 
|  | assert(uthread->flags & UTHREAD_FPSAVED); | 
|  | /* We need to save the already-saved FP state into the sigstate | 
|  | * space.  The sig handler is taking over the uthread and its GP | 
|  | * and FP spaces. | 
|  | * | 
|  | * If we ever go back to not aggressively saving the FP state, | 
|  | * then for HW and VM ctxs, the state is in hardware. | 
|  | * Regardless, we still need to save it in ->as, with something | 
|  | * like: save_fp_state(&uthread->sigstate.data->as); | 
|  | * | 
|  | * Either way, when we're done with this entire function, the | 
|  | * *uthread* will have ~UTHREAD_FPSAVED, since we will be | 
|  | * talking about the SW context that is running the signal | 
|  | * handler. */ | 
|  | uthread->sigstate.data->as = uthread->as; | 
|  | uthread->flags &= ~UTHREAD_FPSAVED; | 
|  | break; | 
|  | case ROS_SW_CTX: | 
|  | assert(!(uthread->flags & UTHREAD_FPSAVED)); | 
|  | break; | 
|  | }; | 
|  | if (info != NULL) | 
|  | uthread->sigstate.data->info = *info; | 
|  |  | 
|  | if (uthread->sigstate.sigalt_stacktop != 0) | 
|  | stack = uthread->sigstate.sigalt_stacktop; | 
|  |  | 
|  | init_user_ctx(&uthread->sigstate.data->u_ctx, (uintptr_t)entry, stack); | 
|  | /* The uthread may or may not be UTHREAD_SAVED.  That depends on whether | 
|  | * the uthread was in that state initially.  We're swapping into the | 
|  | * location of 'ctx', which is either in VCPD or the uth itself. */ | 
|  | swap_user_contexts(ctx, &uthread->sigstate.data->u_ctx); | 
|  | } | 
|  |  | 
|  | /* Restore the context saved as the result of running a signal handler on a | 
|  | * uthread. This context will execute the next time the uthread is run. */ | 
|  | static void __restore_after_sighandler(struct uthread *uthread) | 
|  | { | 
|  | uthread->u_ctx = uthread->sigstate.data->u_ctx; | 
|  | uthread->flags |= UTHREAD_SAVED; | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /* Callback when yielding a pthread after upon completion of a sighandler.  We | 
|  | * didn't save the current context on yeild, but that's ok because here we | 
|  | * restore the original saved context of the pthread and then treat this like a | 
|  | * normal voluntary yield. */ | 
|  | static void __exit_sighandler_cb(struct uthread *uthread, void *junk) | 
|  | { | 
|  | __restore_after_sighandler(uthread); | 
|  | uthread_paused(uthread); | 
|  | } | 
|  |  | 
|  | /* Run a specific sighandler from the top of the sigstate stack. The 'info' | 
|  | * struct is prepopulated before the call is triggered as the result of a | 
|  | * reflected fault. */ | 
|  | static void __run_sighandler(void) | 
|  | { | 
|  | struct uthread *uthread = current_uthread; | 
|  | int signo = uthread->sigstate.data->info.si_signo; | 
|  |  | 
|  | __sigdelset(&uthread->sigstate.pending, signo); | 
|  | trigger_posix_signal(signo, &uthread->sigstate.data->info, | 
|  | &uthread->sigstate.data->u_ctx); | 
|  | uthread_yield(FALSE, __exit_sighandler_cb, 0); | 
|  | } | 
|  |  | 
|  | /* Run through all pending sighandlers and trigger them with a NULL info | 
|  | * field. These handlers are triggered as the result of thread directed | 
|  | * signals (i.e. not interprocess signals), and thus don't require individual | 
|  | * 'info' structs. */ | 
|  | static void __run_all_sighandlers(void) | 
|  | { | 
|  | struct uthread *uthread = current_uthread; | 
|  | sigset_t andset = uthread->sigstate.pending & (~uthread->sigstate.mask); | 
|  |  | 
|  | for (int i = 1; i < _NSIG; i++) { | 
|  | if (__sigismember(&andset, i)) { | 
|  | __sigdelset(&uthread->sigstate.pending, i); | 
|  | trigger_posix_signal(i, NULL, | 
|  | &uthread->sigstate.data->u_ctx); | 
|  | } | 
|  | } | 
|  | uthread_yield(FALSE, __exit_sighandler_cb, 0); | 
|  | } | 
|  |  | 
|  | int uthread_signal(struct uthread *uthread, int signo) | 
|  | { | 
|  | // Slightly racy with clearing of mask when triggering the signal, but | 
|  | // that's OK, as signals are inherently racy since they don't queue up. | 
|  | return sigaddset(&uthread->sigstate.pending, signo); | 
|  | } | 
|  |  | 
|  | /* If there are any pending signals, prep the uthread to run it's signal | 
|  | * handler. The next time the uthread is run, it will pop into it's signal | 
|  | * handler context instead of its original saved context. Once the signal | 
|  | * handler is complete, the original context will be restored and restarted. */ | 
|  | void uthread_prep_pending_signals(struct uthread *uthread) | 
|  | { | 
|  | if (!uth_is_handling_sigs(uthread) && uthread->sigstate.pending) { | 
|  | sigset_t andset = uthread->sigstate.pending & (~uthread->sigstate.mask); | 
|  |  | 
|  | if (!__sigisemptyset(&andset)) | 
|  | __prep_sighandler(uthread, __run_all_sighandlers, NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* If the given signal is unmasked, prep the uthread to run it's signal | 
|  | * handler, but don't run it yet. In either case, make the uthread runnable | 
|  | * again. Once the signal handler is complete, the original context will be | 
|  | * restored and restarted. */ | 
|  | void uthread_prep_signal_from_fault(struct uthread *uthread, | 
|  | int signo, int code, void *addr) | 
|  | { | 
|  | if (!__sigismember(&uthread->sigstate.mask, signo)) { | 
|  | struct siginfo info = {0}; | 
|  |  | 
|  | 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); | 
|  | exit(-1); | 
|  | } | 
|  | info.si_signo = signo; | 
|  | info.si_code = code; | 
|  | info.si_addr = addr; | 
|  | __prep_sighandler(uthread, __run_sighandler, &info); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This is managed by vcore / 2LS code */ | 
|  | static int __sigaltstack(__const struct sigaltstack *__restrict __ss, | 
|  | struct sigaltstack *__restrict __oss) | 
|  | { | 
|  | if (__ss->ss_flags != 0) { | 
|  | errno = EINVAL; | 
|  | return -1; | 
|  | } | 
|  | if (__oss != NULL) { | 
|  | errno = EINVAL; | 
|  | return -1; | 
|  | } | 
|  | if (__ss->ss_size < MINSIGSTKSZ) { | 
|  | errno = ENOMEM; | 
|  | return -1; | 
|  | } | 
|  | uintptr_t stack_top = (uintptr_t) __ss->ss_sp + __ss->ss_size; | 
|  |  | 
|  | current_uthread->sigstate.sigalt_stacktop = stack_top; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Akaros can't have signals interrupt syscalls to need a restart, though we can | 
|  | * re-wake-up the process while it is waiting for its syscall. */ | 
|  | static int __siginterrupt(int __sig, int __interrupt) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Not really possible or relevant - you'd need to walk/examine the event UCQ */ | 
|  | static int __sigpending(sigset_t *__set) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int __sigprocmask(int __how, __const sigset_t *__restrict __set, | 
|  | sigset_t *__restrict __oset) | 
|  | { | 
|  | 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 = ¤t_uthread->sigstate.mask; | 
|  |  | 
|  | if (__set && (__how != SIG_BLOCK) && | 
|  | (__how != SIG_SETMASK) && | 
|  | (__how != SIG_UNBLOCK)) { | 
|  | errno = EINVAL; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (__oset) | 
|  | *__oset = *sigmask; | 
|  | if (__set) { | 
|  | switch (__how) { | 
|  | case SIG_BLOCK: | 
|  | *sigmask = *sigmask | *__set; | 
|  | break; | 
|  | case SIG_SETMASK: | 
|  | *sigmask = *__set; | 
|  | break; | 
|  | case SIG_UNBLOCK: | 
|  | *sigmask = *sigmask & ~(*__set); | 
|  | break; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Needs support with trigger_posix_signal to deal with passing values with | 
|  | * POSIX signals. */ | 
|  | static int __sigqueue(__pid_t __pid, int __sig, __const union sigval __val) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Linux specific, and not really needed for us */ | 
|  | static int __sigreturn(struct sigcontext *__scp) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* This is managed by vcore / 2LS code */ | 
|  | static int __sigstack(struct sigstack *__ss, struct sigstack *__oss) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Could do this with a loop on delivery of the signal, sleeping and getting | 
|  | * woken up by the kernel on any event, like we do with async syscalls. */ | 
|  | static int __sigsuspend(__const sigset_t *__set) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Can be done similar to sigsuspend, with an extra alarm syscall */ | 
|  | static int __sigtimedwait(__const sigset_t *__restrict __set, | 
|  | siginfo_t *__restrict __info, | 
|  | __const struct timespec *__restrict __timeout) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Can be done similar to sigsuspend */ | 
|  | static int __sigwait(__const sigset_t *__restrict __set, int *__restrict __sig) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Can be done similar to sigsuspend */ | 
|  | static int __sigwaitinfo(__const sigset_t *__restrict __set, | 
|  | siginfo_t *__restrict __info) | 
|  | { | 
|  | 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; | 
|  | } |