+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)) \
+ {
+
+#define RESTORE_ERRNO \
+ } \
+ errno = _saved_errno; \
+ }
+
+static void run_deferred_handler(struct interrupt_data *data,
+ os_context_t *context);
+#ifndef LISP_FEATURE_WIN32
+static void store_signal_data_for_later (struct interrupt_data *data,
+ void *handler, int signal,
+ siginfo_t *info,
+ os_context_t *context);
+\f
+
+/* Generic signal related utilities. */
+
+void
+get_current_sigmask(sigset_t *sigset)
+{
+ /* Get the current sigmask, by blocking the empty set. */
+ thread_sigmask(SIG_BLOCK, 0, sigset);
+}
+
+void
+block_signals(sigset_t *what, sigset_t *where, sigset_t *old)
+{
+ if (where) {
+ int i;
+ if (old)
+ sigcopyset(old, where);
+ for(i = 1; i < NSIG; i++) {
+ if (sigismember(what, i))
+ sigaddset(where, i);
+ }
+ } else {
+ thread_sigmask(SIG_BLOCK, what, old);
+ }
+}
+
+void
+unblock_signals(sigset_t *what, sigset_t *where, sigset_t *old)
+{
+ if (where) {
+ int i;
+ if (old)
+ sigcopyset(old, where);
+ for(i = 1; i < NSIG; i++) {
+ if (sigismember(what, i))
+ sigdelset(where, i);
+ }
+ } else {
+ thread_sigmask(SIG_UNBLOCK, what, old);
+ }
+}
+
+static void
+print_sigset(sigset_t *sigset)
+{
+ int i;
+ for(i = 1; i < NSIG; i++) {
+ if (sigismember(sigset, i))
+ fprintf(stderr, "Signal %d masked\n", i);
+ }
+}
+
+/* Return 1 is all signals is sigset2 are masked in sigset, return 0
+ * if all re unmasked else die. Passing NULL for sigset is a shorthand
+ * for the current sigmask. */
+boolean
+all_signals_blocked_p(sigset_t *sigset, sigset_t *sigset2,
+ const char *name)
+{
+#if !defined(LISP_FEATURE_WIN32)
+ int i;
+ boolean has_blocked = 0, has_unblocked = 0;
+ sigset_t current;
+ if (sigset == 0) {
+ get_current_sigmask(¤t);
+ sigset = ¤t;
+ }
+ for(i = 1; i < NSIG; i++) {
+ if (sigismember(sigset2, i)) {
+ if (sigismember(sigset, i))
+ has_blocked = 1;
+ else
+ has_unblocked = 1;
+ }
+ }
+ if (has_blocked && has_unblocked) {
+ print_sigset(sigset);
+ lose("some %s signals blocked, some unblocked\n", name);
+ }
+ if (has_blocked)
+ return 1;
+ else
+ return 0;
+#endif
+}
+\f