1.0.5.49: interrupt & GC & PA handling
[sbcl.git] / src / runtime / gc-common.c
index 4182448..4f95952 100644 (file)
@@ -2468,12 +2468,30 @@ maybe_gc(os_context_t *context)
      */
 #ifndef LISP_FEATURE_WIN32
     if(SymbolValue(INTERRUPTS_ENABLED,thread)!=NIL) {
-        thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
-        check_gc_signals_unblocked_or_lose();
+        sigset_t *context_sigmask = os_context_sigmask_addr(context);
+#ifdef LISP_FEATURE_SB_THREAD
+        /* What if the context we'd like to restore has GC signals
+         * blocked? Just skip the GC: we can't set GC_PENDING, because
+         * that would block the next attempt, and we don't know when
+         * we'd next check for it -- and it's hard to be sure that
+         * unblocking would be safe.
+         *
+         * FIXME: This is not actually much better: we may already have
+         * GC_PENDING set, and presumably our caller assumes that we will
+         * clear it. Perhaps we should, even though we don't actually GC? */
+        if (sigismember(context_sigmask,SIG_STOP_FOR_GC)) {
+            undo_fake_foreign_function_call(context);
+            return 1;
+        }
+#endif
+        thread_sigmask(SIG_SETMASK, context_sigmask, 0);
     }
     else
         unblock_gc_signals();
 #endif
+    /* SIG_STOP_FOR_GC needs to be enabled before we can call lisp:
+     * otherwise two threads racing here may deadlock: the other will
+     * wait on the GC lock, and the other cannot stop the first one... */
     funcall0(SymbolFunction(SUB_GC));
     undo_fake_foreign_function_call(context);
     return 1;