diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2013-12-20 06:57:13 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2013-12-20 06:57:13 -0800 |
commit | 6e8aaedc1f3be2c9c7c3031499ad2b4bce05dfbc (patch) | |
tree | a972a7ce0467da3e666c4f841b9970971c5c211e /signal.c | |
parent | 0231fc1659ea0a75e058b38c3085d7631162f1b1 (diff) | |
download | txr-6e8aaedc1f3be2c9c7c3031499ad2b4bce05dfbc.tar.gz txr-6e8aaedc1f3be2c9c7c3031499ad2b4bce05dfbc.tar.bz2 txr-6e8aaedc1f3be2c9c7c3031499ad2b4bce05dfbc.zip |
Fixing a bug and performance issue.
Problem: we are using sigsetjmp but with a jmp_buf structure;
it requires sigjmp_buf!
Performance issue: sigsetjmp is a dog which makes system calls.
Solution: let's roll our own cached version of sigprocmask which
only calls the real sigprocmask when the mask changes. Then
our extended_setjmp will just use regular setjmp, plus our own
custom signal saving and restoring based on the cached version.
* signal.c (sig_blocked_cache): New variable.
(set_sig_handler): Use our sig_mask instead of sigprocmask.
(mem_set_bits, mem_clr_bits): New static functions.
(sig_mask): New function.
* signal.h (extended_jmp_buf): New member, blocked.
(extended_setjmp): save blocked signals by peeking into
sig_blocked_cache, and restore using sig_mask.
(sig_blocked_cache, sig_mask): Declared.
Diffstat (limited to 'signal.c')
-rw-r--r-- | signal.c | 53 |
1 files changed, 51 insertions, 2 deletions
@@ -26,8 +26,10 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <stdarg.h> #include <setjmp.h> +#include <errno.h> #include <wchar.h> #include <dirent.h> #include <signal.h> @@ -42,6 +44,7 @@ #define MAX_SIG 32 volatile sig_atomic_t async_sig_enabled = 0; +sigset_t sig_blocked_cache; static val sig_lambda[MAX_SIG]; volatile unsigned long sig_deferred; @@ -134,7 +137,7 @@ val set_sig_handler(val signo, val lambda) sigset_t block, saved; sigfillset(&block); - sigprocmask(SIG_BLOCK, &block, &saved); + sig_mask(SIG_BLOCK, &block, &saved); if (sig < 0 || sig >= MAX_SIG) uw_throwf(error_s, lit("set-sig-handler: signal ~s out of range\n"), sig, nao); @@ -164,7 +167,7 @@ val set_sig_handler(val signo, val lambda) sig_lambda[sig] = lambda; } - sigprocmask(SIG_SETMASK, &saved, 0); + sig_mask(SIG_SETMASK, &saved, 0); return old_lambda; } @@ -198,3 +201,49 @@ val sig_check(void) return t; } + +static void mem_set_bits(mem_t *target, const mem_t *bits, size_t size) +{ + while (size--) + *target++ |= *bits++; +} + +static void mem_clr_bits(mem_t *target, const mem_t *bits, size_t size) +{ + while (size--) + *target++ &= ~*bits++; +} + +int sig_mask(int how, const sigset_t *set, sigset_t *oldset) +{ + sigset_t new; + const sigset_t *pnew; + + switch (how) { + case SIG_SETMASK: + pnew = set; + break; + case SIG_BLOCK: + pnew = &new; + new = sig_blocked_cache; + mem_set_bits((mem_t *) &new, (mem_t *) set, sizeof new); + break; + case SIG_UNBLOCK: + pnew = &new; + new = sig_blocked_cache; + mem_clr_bits((mem_t *) &new, (mem_t *) set, sizeof new); + break; + default: + errno = EINVAL; + return -1; + } + + if (memcmp(&sig_blocked_cache, pnew, sizeof *pnew) != 0) { + sig_blocked_cache = *pnew; + return sig_mask(SIG_BLOCK, pnew, oldset); + } + + if (oldset != 0) + *oldset = sig_blocked_cache; + return 0; +} |