diff --git a/libc/calls/getcontext.S b/libc/calls/getcontext.S index cbd7ff9f6..3ffd34b41 100644 --- a/libc/calls/getcontext.S +++ b/libc/calls/getcontext.S @@ -20,12 +20,6 @@ // Gets machine state. // -// This function goes 14x slower if sigaction() has ever been used to -// install a signal handling function. If you don't care about signal -// safety and just want fast fibers, then you may override the global -// variable `__interruptible` to disable the sigprocmask() calls, for -// pure userspace context switching. -// // @return 0 on success, or -1 w/ errno // @see makecontext() // @see swapcontext() diff --git a/libc/calls/raise.c b/libc/calls/raise.c index 063637881..1796d2df7 100644 --- a/libc/calls/raise.c +++ b/libc/calls/raise.c @@ -23,6 +23,7 @@ #include "libc/intrin/strace.internal.h" #include "libc/runtime/syslib.internal.h" #include "libc/sysv/consts/sicode.h" +#include "libc/sysv/errfuns.h" /** * Sends signal to self. @@ -35,6 +36,7 @@ * * @param sig can be SIGALRM, SIGINT, SIGTERM, SIGKILL, etc. * @return 0 on success, or nonzero on failure + * @raise EINVAL if `sig` is invalid * @asyncsignalsafe */ int raise(int sig) { @@ -42,8 +44,12 @@ int raise(int sig) { if (IsXnuSilicon()) { rc = __syslib->__raise(sig); } else if (IsWindows()) { - __sig_raise(sig, SI_TKILL); - rc = 0; + if (0 <= sig && sig <= 64) { + __sig_raise(sig, SI_TKILL); + rc = 0; + } else { + rc = einval(); + } } else { rc = sys_tkill(gettid(), sig, 0); } diff --git a/libc/calls/sig.c b/libc/calls/sig.c index 00a2cc10a..467c19939 100644 --- a/libc/calls/sig.c +++ b/libc/calls/sig.c @@ -34,6 +34,7 @@ #include "libc/intrin/atomic.h" #include "libc/intrin/bsf.h" #include "libc/intrin/describebacktrace.internal.h" +#include "libc/intrin/kprintf.h" #include "libc/intrin/popcnt.h" #include "libc/intrin/strace.internal.h" #include "libc/intrin/weaken.h" @@ -169,53 +170,59 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig, } static textwindows sigaction_f __sig_handler(unsigned rva) { + atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed); return (sigaction_f)(__executable_start + rva); } -textwindows int __sig_raise(int sig, int sic) { +textwindows int __sig_raise(volatile int sig, int sic) { - // create machine context object - struct PosixThread *pt = _pthread_self(); - ucontext_t ctx = {.uc_sigmask = pt->tib->tib_sigmask}; - struct NtContext nc; - nc.ContextFlags = kNtContextFull; - GetThreadContext(GetCurrentThread(), &nc); - _ntcontext2linux(&ctx, &nc); + // bitset of kinds of handlers called + volatile int handler_was_called = 0; + + // loop over pending signals + ucontext_t ctx; + getcontext(&ctx); + if (!sig) { + if ((sig = __sig_get(ctx.uc_sigmask))) { + sic = SI_KERNEL; + } else { + return handler_was_called; + } + } // process signal(s) - int handler_was_called = 0; - do { - // start the signal - unsigned rva, flags; - if (__sig_start(pt, sig, &rva, &flags)) { - if (flags & SA_RESETHAND) { - STRACE("resetting %G handler", sig); - __sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL; - } - - // update the signal mask in preparation for signal handller - sigset_t blocksigs = __sighandmask[sig]; - if (!(flags & SA_NODEFER)) blocksigs |= 1ull << (sig - 1); - ctx.uc_sigmask = atomic_fetch_or_explicit( - &pt->tib->tib_sigmask, blocksigs, memory_order_acquire); - - // call the user's signal handler - char ssbuf[2][128]; - siginfo_t si = {.si_signo = sig, .si_code = sic}; - STRACE("__sig_raise(%G, %t) mask %s → %s", sig, __sig_handler(rva), - (DescribeSigset)(ssbuf[0], 0, &ctx.uc_sigmask), - (DescribeSigset)(ssbuf[1], 0, (sigset_t *)&pt->tib->tib_sigmask)); - __sig_handler(rva)(sig, &si, &ctx); - (void)ssbuf; - - // restore the original signal mask - atomic_store_explicit(&pt->tib->tib_sigmask, ctx.uc_sigmask, - memory_order_release); - handler_was_called |= (flags & SA_RESTART) ? 2 : 1; + unsigned rva, flags; + struct PosixThread *pt = _pthread_self(); + if (__sig_start(pt, sig, &rva, &flags)) { + if (flags & SA_RESETHAND) { + STRACE("resetting %G handler", sig); + __sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL; } - sic = SI_KERNEL; - } while ((sig = __sig_get(ctx.uc_sigmask))); - return handler_was_called; + + // update the signal mask in preparation for signal handller + sigset_t blocksigs = __sighandmask[sig]; + if (!(flags & SA_NODEFER)) blocksigs |= 1ull << (sig - 1); + ctx.uc_sigmask = atomic_fetch_or_explicit(&pt->tib->tib_sigmask, blocksigs, + memory_order_acquire); + + // call the user's signal handler + char ssbuf[2][128]; + siginfo_t si = {.si_signo = sig, .si_code = sic}; + STRACE("__sig_raise(%G, %t) mask %s → %s", sig, __sig_handler(rva), + (DescribeSigset)(ssbuf[0], 0, &ctx.uc_sigmask), + (DescribeSigset)(ssbuf[1], 0, (sigset_t *)&pt->tib->tib_sigmask)); + __sig_handler(rva)(sig, &si, &ctx); + (void)ssbuf; + + // record this handler + handler_was_called |= (flags & SA_RESTART) ? 2 : 1; + } + + // restore sigmask + // loop back to top + // jump where handler says + sig = 0; + return setcontext(&ctx); } textwindows int __sig_relay(int sig, int sic, sigset_t waitmask) { @@ -258,7 +265,6 @@ static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) { struct CosmoTib *tib = __get_tls(); struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread; for (;;) { - atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed); // update the signal mask in preparation for signal handller sigset_t blocksigs = __sighandmask[sig]; @@ -513,9 +519,6 @@ static int __sig_crash_sig(struct NtExceptionPointers *ep, int *code) { static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig, struct CosmoTib *tib) { - // increment the signal count for getrusage() - atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed); - // log vital crash information reliably for --strace before doing much // we don't print this without the flag since raw numbers scare people // this needs at least one page of stack memory in order to get logged diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 10d4df1c2..9f19be843 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -479,13 +479,6 @@ static int __sigaction(int sig, const struct sigaction *act, * spawned your process, happened to call `setrlimit()`. Doing this is * a wonderful idea. * - * Using signals might make your C runtime slower. Upon successfully - * installing its first signal handling function, sigaction() will set - * the global variable `__interruptible` to true, to let everything else - * know that signals are in play. That way code which would otherwise be - * frequently calling sigprocmask() out of an abundance of caution, will - * no longer need to pay its outrageous cost. - * * Signal handlers should avoid clobbering global variables like `errno` * because most signals are asynchronous, i.e. the signal handler might * be called at any assembly instruction. If something like a `SIGCHLD` @@ -506,13 +499,6 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) { rc = einval(); } else { rc = __sigaction(sig, act, oldact); - if (!rc && act && (uintptr_t)act->sa_handler >= kSigactionMinRva) { - static bool once; - if (!once) { - __interruptible = true; - once = true; - } - } } STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(0, act), DescribeSigaction(rc, oldact), rc); diff --git a/libc/calls/swapcontext.S b/libc/calls/swapcontext.S index 8853c2e95..1becf475f 100644 --- a/libc/calls/swapcontext.S +++ b/libc/calls/swapcontext.S @@ -27,12 +27,6 @@ // // swapcontext(x, y); // -// This function goes 14x slower if sigaction() has ever been used to -// install a signal handling function. If you don't care about signal -// safety and just want fast fibers, then you may override the global -// variable `__interruptible` to disable the sigprocmask() calls, for -// pure userspace context switching. -// // @return 0 on success, or -1 w/ errno // @returnstwice .ftrace1 diff --git a/libc/calls/ucontext.c b/libc/calls/ucontext.c index 5ff2ceeac..cb99bb669 100644 --- a/libc/calls/ucontext.c +++ b/libc/calls/ucontext.c @@ -24,8 +24,6 @@ int __tailcontext(const ucontext_t *); static int __contextmask(const sigset_t *opt_set, sigset_t *opt_out_oldset) { - if (!__interruptible) return 0; - // signal handling functions might exist // now context switching needs to go 14x slower return sigprocmask(SIG_SETMASK, opt_set, opt_out_oldset); } @@ -33,12 +31,6 @@ static int __contextmask(const sigset_t *opt_set, sigset_t *opt_out_oldset) { /** * Sets machine context. * - * This function goes 14x slower if sigaction() has ever been used to - * install a signal handling function. If you don't care about signal - * safety and just want fast fibers, then you may override the global - * variable `__interruptible` to disable the sigprocmask() calls, for - * pure userspace context switching. - * * @return -1 on error w/ errno, otherwise won't return unless sent back * @see swapcontext() * @see makecontext() diff --git a/libc/nexgen32e/threaded.c b/libc/nexgen32e/threaded.c index dc9921998..4230175e5 100644 --- a/libc/nexgen32e/threaded.c +++ b/libc/nexgen32e/threaded.c @@ -23,11 +23,6 @@ */ int __threaded; -/** - * Set to true if sigaction() has installed signal handlers. - */ -bool __interruptible; - #ifdef __x86_64__ bool __tls_enabled; #endif diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index b2a3e7c4d..9417c9f48 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -72,7 +72,6 @@ extern int __argc; extern char **__argv; extern char **__envp; extern unsigned long *__auxv; -extern bool __interruptible; extern intptr_t __oldstack; extern uint64_t __nosync; extern int __strace; diff --git a/test/libc/calls/getcontext_test.c b/test/libc/calls/getcontext_test.c index 66b0b7563..c6137a830 100644 --- a/test/libc/calls/getcontext_test.c +++ b/test/libc/calls/getcontext_test.c @@ -54,7 +54,6 @@ TEST(getcontext, test) { TEST(getcontext, canReadAndWriteSignalMask) { sigset_t ss, old; volatile int n = 0; - __interruptible = true; sigemptyset(&ss); sigaddset(&ss, SIGUSR1); sigprocmask(SIG_SETMASK, &ss, &old); @@ -72,8 +71,7 @@ TEST(getcontext, canReadAndWriteSignalMask) { } void SetGetContext(void) { - static int a; - a = 0; + int a = 0; getcontext(&context); if (!a) { a = 1; @@ -82,9 +80,6 @@ void SetGetContext(void) { } BENCH(getcontext, bench) { - __interruptible = false; - EZBENCH2("getsetcontext nosig", donothing, SetGetContext()); - __interruptible = true; EZBENCH2("getsetcontext", donothing, SetGetContext()); } @@ -99,10 +94,6 @@ BENCH(swapcontext, bench) { } } else { ready = true; - __interruptible = false; - EZBENCH2("swapcontextx2 nosig", donothing, swapcontext(&loop, &main)); - // kprintf("dollar\n"); - __interruptible = true; EZBENCH2("swapcontextx2", donothing, swapcontext(&loop, &main)); // kprintf("dollar\n"); } diff --git a/test/libc/calls/raise_test.c b/test/libc/calls/raise_test.c index 8d6b88096..a57fc1470 100644 --- a/test/libc/calls/raise_test.c +++ b/test/libc/calls/raise_test.c @@ -20,10 +20,12 @@ #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/siginfo.h" #include "libc/dce.h" +#include "libc/intrin/kprintf.h" #include "libc/runtime/runtime.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sig.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/subprocess.h" #include "libc/testlib/testlib.h" #include "libc/thread/thread.h" @@ -67,9 +69,19 @@ void *Worker(void *arg) { } TEST(raise, threaded) { + SPAWN(fork); signal(SIGILL, SIG_DFL); pthread_t worker; ASSERT_EQ(0, pthread_create(&worker, 0, Worker, 0)); ASSERT_EQ(0, pthread_join(worker, 0)); pthread_exit(0); + EXITS(0); +} + +void OnRaise(int sig) { +} + +BENCH(raise, bench) { + signal(SIGUSR1, OnRaise); + EZBENCH2("raise", donothing, raise(SIGUSR1)); } diff --git a/test/libc/calls/sig_test.c b/test/libc/calls/sig_test.c index 8fe87fb5c..901e85c23 100644 --- a/test/libc/calls/sig_test.c +++ b/test/libc/calls/sig_test.c @@ -116,3 +116,8 @@ TEST(poll, interrupt) { ASSERT_TRUE(gotsig); ASSERT_TRUE(didit); } + +TEST(raise, zero) { + ASSERT_SYS(0, 0, raise(0)); + ASSERT_SYS(EINVAL, -1, raise(-1)); +} diff --git a/test/libc/thread/makecontext_test.c b/test/libc/thread/makecontext_test.c index 81f641baf..d04f3eb24 100644 --- a/test/libc/thread/makecontext_test.c +++ b/test/libc/thread/makecontext_test.c @@ -64,7 +64,6 @@ void check_args(long x0, long x1, long x2, long x3, long x4, long x5, double f0, TEST(makecontext, args) { char stack[1024]; - __interruptible = false; getcontext(&uc); uc.uc_link = &goback; uc.uc_stack.ss_sp = stack;