diff --git a/cpu/native/irq_cpu.c b/cpu/native/irq_cpu.c index b0b0c7f950..1a8ea8ca93 100644 --- a/cpu/native/irq_cpu.c +++ b/cpu/native/irq_cpu.c @@ -356,6 +356,55 @@ void native_isr_entry(int sig, siginfo_t *info, void *context) #endif } +/** + * Add or remove handler for signal + * + * To be called with interrupts disabled + * + */ +void set_signal_handler(int sig, bool add) +{ + struct sigaction sa; + int ret; + + /* update the signal mask so enableIRQ()/disableIRQ() will be aware */ + if (add) { + _native_syscall_enter(); + ret = sigdelset(&_native_sig_set, sig); + _native_syscall_leave(); + } else { + _native_syscall_enter(); + ret = sigaddset(&_native_sig_set, sig); + _native_syscall_leave(); + } + + if (ret == -1) { + err(EXIT_FAILURE, "set_signal_handler: sigdelset"); + } + + memset(&sa, 0, sizeof(sa)); + + /* Disable other signal during execution of the handler for this signal. */ + memcpy(&sa.sa_mask, &_native_sig_set_dint, sizeof(sa.sa_mask)); + + /* restart interrupted systems call and custom signal stack */ + sa.sa_flags = SA_RESTART | SA_ONSTACK; + + if (add) { + sa.sa_flags |= SA_SIGINFO; /* sa.sa_sigaction is used */ + sa.sa_sigaction = native_isr_entry; + } else + { + sa.sa_handler = SIG_IGN; + } + + _native_syscall_enter(); + if (sigaction(sig, &sa, NULL)) { + err(EXIT_FAILURE, "set_signal_handler: sigaction"); + } + _native_syscall_leave(); +} + /** * register signal/interrupt handler for signal sig * @@ -366,26 +415,12 @@ int register_interrupt(int sig, _native_callback_t handler) { DEBUG("register_interrupt\n"); - _native_syscall_enter(); - if (sigdelset(&_native_sig_set, sig)) { - err(EXIT_FAILURE, "register_interrupt: sigdelset"); - } + unsigned state = disableIRQ(); native_irq_handlers[sig] = handler; + set_signal_handler(sig, true); - /* set current dINT sigmask for all signals */ - struct sigaction sa; - sa.sa_sigaction = native_isr_entry; - sa.sa_mask = _native_sig_set_dint; - sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - for (int i = 0; i < 255; i++) { - if (native_irq_handlers[i] != NULL) { - if (sigaction(sig, &sa, NULL)) { - err(EXIT_FAILURE, "register_interrupt: sigaction"); - } - } - } - _native_syscall_leave(); + restoreIRQ(state); return 0; } @@ -397,31 +432,12 @@ int unregister_interrupt(int sig) { DEBUG("unregister_interrupt\n"); - _native_syscall_enter(); - if (sigaddset(&_native_sig_set, sig) == -1) { - err(EXIT_FAILURE, "unregister_interrupt: sigaddset"); - } + unsigned state = disableIRQ(); + set_signal_handler(sig, false); native_irq_handlers[sig] = NULL; - /* reset signal handler for sig */ - struct sigaction sa; - sa.sa_handler = SIG_IGN; /* there may be late signals, so we need to ignore those */ - sa.sa_mask = _native_sig_set_dint; - sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - if (sigaction(sig, &sa, NULL)) { - err(EXIT_FAILURE, "unregister_interrupt: sigaction"); - } - /* change sigmask for remaining signal handlers */ - sa.sa_sigaction = native_isr_entry; - for (int i = 0; i < 255; i++) { - if (native_irq_handlers[i] != NULL) { - if (sigaction(sig, &sa, NULL)) { - err(EXIT_FAILURE, "unregister_interrupt: sigaction"); - } - } - } - _native_syscall_leave(); + restoreIRQ(state); return 0; }