aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES10
-rw-r--r--threadproc/unix/signals.c49
2 files changed, 56 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 7b1c23a00..42b0d6de8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,13 @@
Changes with APR b1
- *) change the apr_table_elts macro so that it provides access via
- a const pointer instead of a non-const pointer
+ *) Fix apr_setup_signal_thread() so that threads don't block
+ synchronous signals (e.g., SIGSEGV). It is a programming error
+ to do so, and some platforms (e.g., Solaris, AIX) don't call any
+ registered signal handler when such signals are blocked.
+ [Jeff Trawick]
+
+ *) Change the apr_table_elts macro so that it provides access via
+ a const pointer instead of a non-const pointer.
[Brian Pane <bpane@pacbell.net]
*) Use strerror_r() where available, since strerror() isn't always
diff --git a/threadproc/unix/signals.c b/threadproc/unix/signals.c
index 0872ecc4a..6d49cc218 100644
--- a/threadproc/unix/signals.c
+++ b/threadproc/unix/signals.c
@@ -268,6 +268,41 @@ const char *apr_signal_get_description(int signum)
#endif /* SYS_SIGLIST_DECLARED */
#if APR_HAS_THREADS && (HAVE_SIGSUSPEND || APR_HAVE_SIGWAIT) && !defined(OS2)
+
+static void remove_sync_sigs(sigset_t *sig_mask)
+{
+#ifdef SIGABRT
+ sigdelset(sig_mask, SIGABRT);
+#endif
+#ifdef SIGBUS
+ sigdelset(sig_mask, SIGBUS);
+#endif
+#ifdef SIGEMT
+ sigdelset(sig_mask, SIGEMT);
+#endif
+#ifdef SIGFPE
+ sigdelset(sig_mask, SIGFPE);
+#endif
+#ifdef SIGILL
+ sigdelset(sig_mask, SIGILL);
+#endif
+#ifdef SIGIOT
+ sigdelset(sig_mask, SIGIOT);
+#endif
+#ifdef SIGPIPE
+ sigdelset(sig_mask, SIGPIPE);
+#endif
+#ifdef SIGSEGV
+ sigdelset(sig_mask, SIGSEGV);
+#endif
+#ifdef SIGSYS
+ sigdelset(sig_mask, SIGSYS);
+#endif
+#ifdef SIGTRAP
+ sigdelset(sig_mask, SIGTRAP);
+#endif
+}
+
APR_DECLARE(apr_status_t) apr_signal_thread(int(*signal_handler)(int signum))
{
sigset_t sig_mask;
@@ -329,8 +364,20 @@ APR_DECLARE(apr_status_t) apr_setup_signal_thread(void)
sigset_t sig_mask;
int rv;
- /* All threads should mask signals out, according to sigwait(2) man page */
+ /* All threads should mask out signals to be handled by
+ * the thread doing sigwait().
+ *
+ * No thread should ever block synchronous signals.
+ * See the Solaris man page for pthread_sigmask() for
+ * some information. Solaris chooses to knock out such
+ * processes when a blocked synchronous signal is
+ * delivered, skipping any registered signal handler.
+ * AIX doesn't call a signal handler either. At least
+ * one level of linux+glibc does call the handler even
+ * when the synchronous signal is blocked.
+ */
sigfillset(&sig_mask);
+ remove_sync_sigs(&sig_mask);
#if defined(SIGPROCMASK_SETS_THREAD_MASK)
rv = sigprocmask(SIG_SETMASK, &sig_mask, NULL);