linux/arch/um/os-Linux/signal.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004 PathScale, Inc
   3 * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   4 * Licensed under the GPL
   5 */
   6
   7#include <stdlib.h>
   8#include <stdarg.h>
   9#include <errno.h>
  10#include <signal.h>
  11#include <strings.h>
  12#include "as-layout.h"
  13#include "kern_util.h"
  14#include "os.h"
  15#include "sysdep/mcontext.h"
  16
  17void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
  18        [SIGTRAP]       = relay_signal,
  19        [SIGFPE]        = relay_signal,
  20        [SIGILL]        = relay_signal,
  21        [SIGWINCH]      = winch,
  22        [SIGBUS]        = bus_handler,
  23        [SIGSEGV]       = segv_handler,
  24        [SIGIO]         = sigio_handler,
  25        [SIGVTALRM]     = timer_handler };
  26
  27static void sig_handler_common(int sig, mcontext_t *mc)
  28{
  29        struct uml_pt_regs r;
  30        int save_errno = errno;
  31
  32        r.is_user = 0;
  33        if (sig == SIGSEGV) {
  34                /* For segfaults, we want the data from the sigcontext. */
  35                get_regs_from_mc(&r, mc);
  36                GET_FAULTINFO_FROM_MC(r.faultinfo, mc);
  37        }
  38
  39        /* enable signals if sig isn't IRQ signal */
  40        if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
  41                unblock_signals();
  42
  43        (*sig_info[sig])(sig, &r);
  44
  45        errno = save_errno;
  46}
  47
  48/*
  49 * These are the asynchronous signals.  SIGPROF is excluded because we want to
  50 * be able to profile all of UML, not just the non-critical sections.  If
  51 * profiling is not thread-safe, then that is not my problem.  We can disable
  52 * profiling when SMP is enabled in that case.
  53 */
  54#define SIGIO_BIT 0
  55#define SIGIO_MASK (1 << SIGIO_BIT)
  56
  57#define SIGVTALRM_BIT 1
  58#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
  59
  60static int signals_enabled;
  61static unsigned int signals_pending;
  62
  63void sig_handler(int sig, mcontext_t *mc)
  64{
  65        int enabled;
  66
  67        enabled = signals_enabled;
  68        if (!enabled && (sig == SIGIO)) {
  69                signals_pending |= SIGIO_MASK;
  70                return;
  71        }
  72
  73        block_signals();
  74
  75        sig_handler_common(sig, mc);
  76
  77        set_signals(enabled);
  78}
  79
  80static void real_alarm_handler(mcontext_t *mc)
  81{
  82        struct uml_pt_regs regs;
  83
  84        if (mc != NULL)
  85                get_regs_from_mc(&regs, mc);
  86        regs.is_user = 0;
  87        unblock_signals();
  88        timer_handler(SIGVTALRM, &regs);
  89}
  90
  91void alarm_handler(int sig, mcontext_t *mc)
  92{
  93        int enabled;
  94
  95        enabled = signals_enabled;
  96        if (!signals_enabled) {
  97                signals_pending |= SIGVTALRM_MASK;
  98                return;
  99        }
 100
 101        block_signals();
 102
 103        real_alarm_handler(mc);
 104        set_signals(enabled);
 105}
 106
 107void timer_init(void)
 108{
 109        set_handler(SIGVTALRM);
 110}
 111
 112void set_sigstack(void *sig_stack, int size)
 113{
 114        stack_t stack = ((stack_t) { .ss_flags  = 0,
 115                                     .ss_sp     = (__ptr_t) sig_stack,
 116                                     .ss_size   = size - sizeof(void *) });
 117
 118        if (sigaltstack(&stack, NULL) != 0)
 119                panic("enabling signal stack failed, errno = %d\n", errno);
 120}
 121
 122static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = {
 123        [SIGSEGV] = sig_handler,
 124        [SIGBUS] = sig_handler,
 125        [SIGILL] = sig_handler,
 126        [SIGFPE] = sig_handler,
 127        [SIGTRAP] = sig_handler,
 128
 129        [SIGIO] = sig_handler,
 130        [SIGWINCH] = sig_handler,
 131        [SIGVTALRM] = alarm_handler
 132};
 133
 134
 135static void hard_handler(int sig, siginfo_t *info, void *p)
 136{
 137        struct ucontext *uc = p;
 138        mcontext_t *mc = &uc->uc_mcontext;
 139        unsigned long pending = 1UL << sig;
 140
 141        do {
 142                int nested, bail;
 143
 144                /*
 145                 * pending comes back with one bit set for each
 146                 * interrupt that arrived while setting up the stack,
 147                 * plus a bit for this interrupt, plus the zero bit is
 148                 * set if this is a nested interrupt.
 149                 * If bail is true, then we interrupted another
 150                 * handler setting up the stack.  In this case, we
 151                 * have to return, and the upper handler will deal
 152                 * with this interrupt.
 153                 */
 154                bail = to_irq_stack(&pending);
 155                if (bail)
 156                        return;
 157
 158                nested = pending & 1;
 159                pending &= ~1;
 160
 161                while ((sig = ffs(pending)) != 0){
 162                        sig--;
 163                        pending &= ~(1 << sig);
 164                        (*handlers[sig])(sig, mc);
 165                }
 166
 167                /*
 168                 * Again, pending comes back with a mask of signals
 169                 * that arrived while tearing down the stack.  If this
 170                 * is non-zero, we just go back, set up the stack
 171                 * again, and handle the new interrupts.
 172                 */
 173                if (!nested)
 174                        pending = from_irq_stack(nested);
 175        } while (pending);
 176}
 177
 178void set_handler(int sig)
 179{
 180        struct sigaction action;
 181        int flags = SA_SIGINFO | SA_ONSTACK;
 182        sigset_t sig_mask;
 183
 184        action.sa_sigaction = hard_handler;
 185
 186        /* block irq ones */
 187        sigemptyset(&action.sa_mask);
 188        sigaddset(&action.sa_mask, SIGVTALRM);
 189        sigaddset(&action.sa_mask, SIGIO);
 190        sigaddset(&action.sa_mask, SIGWINCH);
 191
 192        if (sig == SIGSEGV)
 193                flags |= SA_NODEFER;
 194
 195        if (sigismember(&action.sa_mask, sig))
 196                flags |= SA_RESTART; /* if it's an irq signal */
 197
 198        action.sa_flags = flags;
 199        action.sa_restorer = NULL;
 200        if (sigaction(sig, &action, NULL) < 0)
 201                panic("sigaction failed - errno = %d\n", errno);
 202
 203        sigemptyset(&sig_mask);
 204        sigaddset(&sig_mask, sig);
 205        if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
 206                panic("sigprocmask failed - errno = %d\n", errno);
 207}
 208
 209int change_sig(int signal, int on)
 210{
 211        sigset_t sigset;
 212
 213        sigemptyset(&sigset);
 214        sigaddset(&sigset, signal);
 215        if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0)
 216                return -errno;
 217
 218        return 0;
 219}
 220
 221void block_signals(void)
 222{
 223        signals_enabled = 0;
 224        /*
 225         * This must return with signals disabled, so this barrier
 226         * ensures that writes are flushed out before the return.
 227         * This might matter if gcc figures out how to inline this and
 228         * decides to shuffle this code into the caller.
 229         */
 230        barrier();
 231}
 232
 233void unblock_signals(void)
 234{
 235        int save_pending;
 236
 237        if (signals_enabled == 1)
 238                return;
 239
 240        /*
 241         * We loop because the IRQ handler returns with interrupts off.  So,
 242         * interrupts may have arrived and we need to re-enable them and
 243         * recheck signals_pending.
 244         */
 245        while (1) {
 246                /*
 247                 * Save and reset save_pending after enabling signals.  This
 248                 * way, signals_pending won't be changed while we're reading it.
 249                 */
 250                signals_enabled = 1;
 251
 252                /*
 253                 * Setting signals_enabled and reading signals_pending must
 254                 * happen in this order.
 255                 */
 256                barrier();
 257
 258                save_pending = signals_pending;
 259                if (save_pending == 0)
 260                        return;
 261
 262                signals_pending = 0;
 263
 264                /*
 265                 * We have pending interrupts, so disable signals, as the
 266                 * handlers expect them off when they are called.  They will
 267                 * be enabled again above.
 268                 */
 269
 270                signals_enabled = 0;
 271
 272                /*
 273                 * Deal with SIGIO first because the alarm handler might
 274                 * schedule, leaving the pending SIGIO stranded until we come
 275                 * back here.
 276                 */
 277                if (save_pending & SIGIO_MASK)
 278                        sig_handler_common(SIGIO, NULL);
 279
 280                if (save_pending & SIGVTALRM_MASK)
 281                        real_alarm_handler(NULL);
 282        }
 283}
 284
 285int get_signals(void)
 286{
 287        return signals_enabled;
 288}
 289
 290int set_signals(int enable)
 291{
 292        int ret;
 293        if (signals_enabled == enable)
 294                return enable;
 295
 296        ret = signals_enabled;
 297        if (enable)
 298                unblock_signals();
 299        else block_signals();
 300
 301        return ret;
 302}
 303
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.