summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2013-12-20 06:57:13 -0800
committerKaz Kylheku <kaz@kylheku.com>2013-12-20 06:57:13 -0800
commit6e8aaedc1f3be2c9c7c3031499ad2b4bce05dfbc (patch)
treea972a7ce0467da3e666c4f841b9970971c5c211e
parent0231fc1659ea0a75e058b38c3085d7631162f1b1 (diff)
downloadtxr-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.
-rw-r--r--ChangeLog23
-rw-r--r--signal.c53
-rw-r--r--signal.h13
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 <kaz@kylheku.com>
+
+ 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 <kaz@kylheku.com>
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 <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;
+}
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);