+/* When we catch an internal error, should we pass it back to Lisp to
+ * be handled in a high-level way? (Early in cold init, the answer is
+ * 'no', because Lisp is still too brain-dead to handle anything.
+ * After sufficient initialization has been completed, the answer
+ * becomes 'yes'.) */
+boolean internal_errors_enabled = 0;
+
+#ifndef LISP_FEATURE_WIN32
+static
+void (*interrupt_low_level_handlers[NSIG]) (int, siginfo_t*, os_context_t*);
+#endif
+union interrupt_handler interrupt_handlers[NSIG];
+
+/* Under Linux on some architectures, we appear to have to restore the
+ * FPU control word from the context, as after the signal is delivered
+ * we appear to have a null FPU control word. */
+#if defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
+#define RESTORE_FP_CONTROL_WORD(context,void_context) \
+ os_context_t *context = arch_os_get_context(&void_context); \
+ os_restore_fp_control(context);
+#else
+#define RESTORE_FP_CONTROL_WORD(context,void_context) \
+ os_context_t *context = arch_os_get_context(&void_context);
+#endif
+
+/* Foreign code may want to start some threads on its own.
+ * Non-targetted, truly asynchronous signals can be delivered to
+ * basically any thread, but invoking Lisp handlers in such foregign
+ * threads is really bad, so let's resignal it.
+ *
+ * This should at least bring attention to the problem, but it cannot
+ * work for SIGSEGV and similar. It is good enough for timers, and
+ * maybe all deferrables. */
+
+#ifdef LISP_FEATURE_SB_THREAD
+static void
+add_handled_signals(sigset_t *sigset)
+{
+ int i;
+ for(i = 1; i < NSIG; i++) {
+ if (!(ARE_SAME_HANDLER(interrupt_low_level_handlers[i], SIG_DFL)) ||
+ !(ARE_SAME_HANDLER(interrupt_handlers[i].c, SIG_DFL))) {
+ sigaddset(sigset, i);
+ }
+ }
+}
+
+void block_signals(sigset_t *what, sigset_t *where, sigset_t *old);
+#endif
+
+static boolean
+maybe_resignal_to_lisp_thread(int signal, os_context_t *context)
+{
+#ifdef LISP_FEATURE_SB_THREAD
+ if (!pthread_getspecific(lisp_thread)) {
+ if (!(sigismember(&deferrable_sigset,signal))) {
+ corruption_warning_and_maybe_lose
+ ("Received signal %d in non-lisp thread %lu, resignalling to a lisp thread.",
+ signal,
+ pthread_self());
+ }
+ {
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ add_handled_signals(&sigset);
+ block_signals(&sigset, 0, 0);
+ block_signals(&sigset, os_context_sigmask_addr(context), 0);
+ kill(getpid(), signal);
+ }
+ return 1;
+ } else
+#endif
+ return 0;
+}
+
+/* These are to be used in signal handlers. Currently all handlers are
+ * called from one of:
+ *
+ * interrupt_handle_now_handler
+ * maybe_now_maybe_later
+ * unblock_me_trampoline
+ * low_level_handle_now_handler
+ * low_level_maybe_now_maybe_later
+ * low_level_unblock_me_trampoline
+ *
+ * This gives us a single point of control (or six) over errno, fp
+ * control word, and fixing up signal context on sparc.
+ *
+ * The SPARC/Linux platform doesn't quite do signals the way we want
+ * them done. The third argument in the handler isn't filled in by the
+ * kernel properly, so we fix it up ourselves in the
+ * arch_os_get_context(..) function. -- CSR, 2002-07-23
+ */
+#define SAVE_ERRNO(signal,context,void_context) \
+ { \
+ int _saved_errno = errno; \
+ RESTORE_FP_CONTROL_WORD(context,void_context); \
+ if (!maybe_resignal_to_lisp_thread(signal, context)) \
+ {