0.9.5.58:
authorGabor Melis <mega@hotpop.com>
Fri, 14 Oct 2005 14:11:29 +0000 (14:11 +0000)
committerGabor Melis <mega@hotpop.com>
Fri, 14 Oct 2005 14:11:29 +0000 (14:11 +0000)
  * nasty interrupt bug:
    1) sigalrm handler is deferred
    2) later it's run via sigtrap handler
    3) handler does pa_alloc while sigtrap is blocked
    4) gc is needed and another sigtrap is triggered by 3)
    5) stupid Linux kernel sees that sigtrap is blocked and invokes the
       default handler (see http://groups.google.com/group/fa.linux.kernel/browse_frm/thread/455401a6837c72bf/865ea792a236299c)
    6) coredump
    Adding SA_NODEFER to sigaction is enough for sane systems to fix this.
    Not for buggy Linux 2.6. A compile time test was added for
    sigaction and SA_NODEFER allowing the runtime to work around this
    bug (see interrupt.c).
  * added missing sigemptysets

src/runtime/interrupt.c
tools-for-build/Makefile
tools-for-build/grovel-features.sh
tools-for-build/sigaction-sa-nodefer-works-test.c [new file with mode: 0644]
version.lisp-expr

index 9c63983..d8c818a 100644 (file)
@@ -118,7 +118,7 @@ check_blockables_blocked_or_lose()
     int i;
     sigemptyset(&empty);
     thread_sigmask(SIG_BLOCK, &empty, &current);
-    for(i=0;i<NSIG;i++) {
+    for(i = 1; i < NSIG; i++) {
         if (sigismember(&blockable_sigset, i) && !sigismember(&current, i))
             lose("blockable signal %d not blocked",i);
     }
@@ -160,9 +160,7 @@ void reset_signal_mask(void)
 
 void block_blockable_signals(void)
 {
-    sigset_t block;
-    sigcopyset(&block, &blockable_sigset);
-    thread_sigmask(SIG_BLOCK, &block, 0);
+    thread_sigmask(SIG_BLOCK, &blockable_sigset, 0);
 }
 
 \f
@@ -480,6 +478,7 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
 #ifdef LISP_FEATURE_SB_THREAD
         {
             sigset_t unblock;
+            sigemptyset(&unblock);
             sigaddset(&unblock, SIG_STOP_FOR_GC);
             thread_sigmask(SIG_UNBLOCK, &unblock, 0);
         }
@@ -1020,6 +1019,7 @@ interrupt_maybe_gc_int(int signal, siginfo_t *info, void *void_context)
 #ifdef LISP_FEATURE_SB_THREAD
     else {
         sigset_t new;
+        sigemptyset(&new);
         sigaddset(&new,SIG_STOP_FOR_GC);
         thread_sigmask(SIG_UNBLOCK,&new,0);
     }
@@ -1030,6 +1030,28 @@ interrupt_maybe_gc_int(int signal, siginfo_t *info, void *void_context)
     return 1;
 }
 
+#ifndef LISP_FEATURE_SIGACTION_NODEFER_WORKS
+
+/* In Linux 2.4 synchronous signals (sigtrap & co) can be delivered if
+ * they are blocked, in Linux 2.6 the default handler is invoked
+ * instead that usually coredumps. One might hastily think that adding
+ * SA_NODEFER helps, but until ~2.6.13 if SA_NODEFER is specified then
+ * the whole sa_mask is ignored and instead of not adding the signal
+ * in question to the mask. That means if it's not blockable the
+ * signal must be unblocked at the beginning of signal handlers.
+ */
+void
+unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
+{
+    sigset_t unblock;
+    sigemptyset(&unblock);
+    sigaddset(&unblock, signal);
+    thread_sigmask(SIG_UNBLOCK, &unblock, 0);
+    (*interrupt_low_level_handlers[signal])(signal, info, void_context);
+}
+
+#endif
+
 \f
 /*
  * noise to install handlers
@@ -1049,11 +1071,19 @@ undoably_install_low_level_interrupt_handler (int signal,
 
     if (sigismember(&deferrable_sigset,signal))
         sa.sa_sigaction = low_level_maybe_now_maybe_later;
+#ifndef LISP_FEATURE_SIGACTION_NODEFER_WORKS
+    else if (!sigismember(&blockable_sigset, signal))
+        sa.sa_sigaction = unblock_me_trampoline;
+#endif
     else
         sa.sa_sigaction = handler;
 
     sigcopyset(&sa.sa_mask, &blockable_sigset);
-    sa.sa_flags = SA_SIGINFO | SA_RESTART;
+    sa.sa_flags = SA_SIGINFO | SA_RESTART
+#ifdef LISP_FEATURE_SIGACTION_NODEFER_WORKS
+            | SA_NODEFER
+#endif
+        ;
 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
     if((signal==SIG_MEMORY_FAULT)
 #ifdef SIG_INTERRUPT_THREAD
@@ -1095,7 +1125,11 @@ install_handler(int signal, void handler(int, siginfo_t*, void*))
         }
 
         sigcopyset(&sa.sa_mask, &blockable_sigset);
-        sa.sa_flags = SA_SIGINFO | SA_RESTART;
+        sa.sa_flags = SA_SIGINFO | SA_RESTART
+#ifdef LISP_FEATURE_SIGACTION_NODEFER_WORKS
+            | SA_NODEFER
+#endif
+            ;
         sigaction(signal, &sa, NULL);
     }
 
index 0d2760d..cbc8201 100644 (file)
@@ -12,7 +12,9 @@
 CPPFLAGS:=-I../src/runtime
 LDFLAGS:=$(LDFLAGS) $(OS_LIBS)
 
-all: grovel-headers determine-endianness where-is-mcontext modify-ldt-struct-name 
+all: grovel-headers determine-endianness where-is-mcontext \
+        modify-ldt-struct-name sigaction-sa-nodefer-works-test
 
-clean: 
-       rm -f *.o grovel-headers determine-endianness where-is-mcontext modify-ldt-structure-name
+clean:
+       rm -f *.o grovel-headers determine-endianness where-is-mcontext \
+                modify-ldt-structure-name sigaction-sa-nodefer-works-test
index 4111fae..db7974f 100644 (file)
@@ -1,4 +1,4 @@
-# Automated platform feature testing 
+# Automated platform feature testing
 cd ./tools-for-build > /dev/null
 
 # FIXME: Use this to test for dlopen presence and hence
@@ -24,3 +24,5 @@ featurep os-provides-dlopen
 featurep os-provides-dladdr
 
 featurep os-provides-putwc
+
+featurep sigaction-sa-nodefer-works
diff --git a/tools-for-build/sigaction-sa-nodefer-works-test.c b/tools-for-build/sigaction-sa-nodefer-works-test.c
new file mode 100644 (file)
index 0000000..5208f48
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * See if SA_NODEFER makes sigaction ignore sa_mask
+ * altogether. According to POSIX SA_NODEFER means: 'don't add the
+ * handler's signal to the mask'.
+ */
+
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * While most of SBCL is derived from the CMU CL system, many
+ * utilities for the build process (like this one) were written from
+ * scratch after the fork from CMU CL.
+ *
+ * This software is in the public domain and is provided with
+ * absolutely no warranty. See the COPYING and CREDITS files for
+ * more information.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+void
+handler(int signal, siginfo_t *info, void *void_context)
+{
+    sigset_t empty, current;
+    int i;
+    sigemptyset(&empty);
+    sigprocmask(SIG_BLOCK, &empty, &current);
+    for(i = 1; i < NSIG; i++)
+        if (sigismember(&current, i) != ((i == SIGABRT) ? 1 : 0))
+            exit(128 + i);
+    exit(104);
+}
+
+int
+main (int argc, char *argv[])
+{
+    struct sigaction sa;
+
+    sa.sa_flags = SA_SIGINFO | SA_NODEFER;
+    sa.sa_sigaction = handler;
+    sigemptyset(&sa.sa_mask);
+    sigaddset(&sa.sa_mask, SIGABRT);
+    sigaction(SIGTRAP, &sa, NULL);
+    kill(getpid(), SIGTRAP);
+    while (1) sleep(1);
+}
index 4a505c3..2b1b4e0 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.9.5.57"
+"0.9.5.58"