From 6e8aaedc1f3be2c9c7c3031499ad2b4bce05dfbc Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 20 Dec 2013 06:57:13 -0800 Subject: 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. --- ChangeLog | 23 +++++++++++++++++++++++ signal.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-- signal.h | 13 ++++++++++--- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6949e0dc..b63120b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2013-12-20 Kaz Kylheku + + 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. + 2013-12-17 Kaz Kylheku Version 72 diff --git a/signal.c b/signal.c index 82f84149..29dcab88 100644 --- a/signal.c +++ b/signal.c @@ -26,8 +26,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -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; +} diff --git a/signal.h b/signal.h index e2b794c1..8882c259 100644 --- a/signal.h +++ b/signal.h @@ -60,17 +60,23 @@ typedef struct { jmp_buf jb; sig_atomic_t se; + sigset_t blocked; int rv; } extended_jmp_buf; #define extended_setjmp(EJB) \ - (sigsetjmp((EJB).jb, 1) \ - ? (async_sig_enabled = (EJB).se, (EJB).rv) \ - : ((EJB).se = async_sig_enabled, 0)) + (setjmp((EJB).jb) \ + ? (async_sig_enabled = (EJB).se, \ + sig_mask(SIG_SETMASK, &(EJB).blocked, 0), \ + (EJB).rv) \ + : ((EJB).se = async_sig_enabled, \ + (EJB).blocked = sig_blocked_cache, 0)) #define extended_longjmp(EJB, ARG) \ ((EJB).rv = (ARG), longjmp((EJB).jb, 1)) +extern sigset_t sig_blocked_cache; + #else #define sig_save_enable do { @@ -98,3 +104,4 @@ void sig_init(void); val set_sig_handler(val signo, val lambda); val get_sig_handler(val signo); val sig_check(void); +int sig_mask(int how, const sigset_t *set, sigset_t *oldset); -- cgit v1.2.3