/* * Copyright 2021 The Emscripten Authors. All rights reserved. * Emscripten is available under two separate licenses, the MIT license and the * University of Illinois/NCSA Open Source License. Both these licenses can be * found in the LICENSE file. */ #define _GNU_SOURCE // for sigorset/sigandset #include #include #include #include #include "libc.h" #define SST_SIZE (_NSIG/8/sizeof(long)) static thread_local sigset_t __sig_mask; thread_local sigset_t __sig_pending; static int siginvertset(sigset_t *dest, const sigset_t *src) { unsigned long i = 0, *d = (void*) dest, *s = (void*) src; for(; i < SST_SIZE; i++) d[i] = ~s[i]; return 0; } bool __sig_is_blocked(int sig) { return sigismember(&__sig_mask, sig); } static void raise_pending_signals() { for (int sig = 0; sig < _NSIG; sig++) { if (sigismember(&__sig_pending, sig) && !sigismember(&__sig_mask, sig)) { sigdelset(&__sig_pending, sig); raise(sig); } } } int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict old) { if (old) { *old = __sig_mask; } switch (how) { case SIG_SETMASK: __sig_mask = *set; break; case SIG_BLOCK: sigorset(&__sig_mask, &__sig_mask, set); break; case SIG_UNBLOCK: { sigset_t tmp; siginvertset(&tmp, set); sigandset(&__sig_mask, &__sig_mask, &tmp); break; } default: return EINVAL; } // These two signals can never be blocked. sigdelset(&__sig_mask, SIGKILL); sigdelset(&__sig_mask, SIGSTOP); // Now that current mask has changed, raise any pending signals that // might now be unblocked. raise_pending_signals(); return 0; } int sigpending(sigset_t *set) { *set = __sig_pending; return 0; }