+#ifdef LISP_FEATURE_SB_THRUPTION
+static inline int
+thread_may_thrupt(os_context_t *ctx)
+{
+ struct thread * self = arch_os_get_current_thread();
+ /* Thread may be interrupted if all of these are true:
+ * 1) Deferrables are unblocked in the context of the signal that
+ * went into the safepoint. -- Otherwise the surrounding code
+ * didn't want to be interrupted by a signal, so presumably it didn't
+ * want to be INTERRUPT-THREADed either.
+ * (See interrupt_handle_pending for an exception.)
+ * 2) On POSIX: There is no pending signal. This is important even
+ * after checking the sigmask, since we could be in the
+ * handle_pending trap following re-enabling of interrupts.
+ * Signals are unblocked in that case, but the signal is still
+ * pending; we want to run GC before handling the signal and
+ * therefore entered this safepoint. But the thruption would call
+ * ALLOW-WITH-INTERRUPTS, and could re-enter the handle_pending
+ * trap, leading to recursion.
+ * 3) INTERRUPTS_ENABLED is non-nil.
+ * 4) No GC pending; it takes precedence.
+ * Note that we are in a safepoint here, which is always outside of PA. */
+
+ if (SymbolValue(INTERRUPTS_ENABLED, self) == NIL)
+ return 0;
+
+ if (SymbolValue(GC_PENDING, self) != NIL)
+ return 0;
+
+ if (SymbolValue(STOP_FOR_GC_PENDING, self) != NIL)
+ return 0;
+
+#ifdef LISP_FEATURE_WIN32
+ if (deferrables_blocked_p(&self->os_thread->blocked_signal_set))
+ return 0;
+#else
+ /* ctx is NULL if the caller wants to ignore the sigmask. */
+ if (ctx && deferrables_blocked_p(os_context_sigmask_addr(ctx)))
+ return 0;
+ if (SymbolValue(INTERRUPT_PENDING, self) != NIL)
+ return 0;
+#endif
+
+ if (SymbolValue(RESTART_CLUSTERS, self) == NIL)
+ /* This special case prevents TERMINATE-THREAD from hitting
+ * during INITIAL-THREAD-FUNCTION before it's ready. Curiously,
+ * deferrables are already unblocked there. Further
+ * investigation may be in order. */
+ return 0;
+
+ return 1;
+}
+
+// returns 0 if skipped, 1 otherwise
+int
+check_pending_thruptions(os_context_t *ctx)
+{
+ struct thread *p = arch_os_get_current_thread();
+
+ gc_assert(!os_get_csp(p));
+
+ if (!thread_may_thrupt(ctx))
+ return 0;
+ if (SymbolValue(THRUPTION_PENDING, p) == NIL)
+ return 0;
+ SetSymbolValue(THRUPTION_PENDING, NIL, p);
+
+ sigset_t oldset;
+ block_deferrable_signals(0, &oldset);
+
+ funcall0(StaticSymbolFunction(RUN_INTERRUPTION));
+
+ pthread_sigmask(SIG_SETMASK, &oldset, 0);
+ return 1;
+}
+#endif
+