1.0.25.38: fix maybe_gc
authorGabor Melis <mega@hotpop.com>
Mon, 16 Feb 2009 22:01:45 +0000 (22:01 +0000)
committerGabor Melis <mega@hotpop.com>
Mon, 16 Feb 2009 22:01:45 +0000 (22:01 +0000)
src/runtime/gc-common.c
src/runtime/interrupt.c
src/runtime/interrupt.h
version.lisp-expr

index 0da8a1f..d01a4fc 100644 (file)
@@ -2440,10 +2440,8 @@ maybe_gc(os_context_t *context)
     FSHOW((stderr, "/maybe_gc: calling SUB_GC\n"));
     /* FIXME: Nothing must go wrong during GC else we end up running
      * the debugger, error handlers, and user code in general in a
-     * potentially unsafe place. With deferrables blocked due to
-     * fake_foreign_function_call + unblock_gc_signals(), we'll not
-     * have a pleasant time either. Running out of the control stack
-     * or the heap in SUB-GC are ways to lose. Of course, deferrables
+     * potentially unsafe place. Running out of the control stack or
+     * the heap in SUB-GC are ways to lose. Of course, deferrables
      * cannot be unblocked because there may be a pending handler, or
      * we may even be in a WITHOUT-INTERRUPTS. */
     gc_happened = funcall0(StaticSymbolFunction(SUB_GC));
@@ -2452,16 +2450,19 @@ maybe_gc(os_context_t *context)
     if ((gc_happened != NIL) &&
         /* See if interrupts are enabled or it's possible to enable
          * them. POST-GC has a similar check, but we don't want to
-         * unlock deferrables in that case, because if there is a
-         * pending interrupt we'd lose, but more to point the POST-GC
-         * runs user code in a pretty much arbitrary place so it
-         * better not be in WITHOUT-INTERRUPTS. */
+         * unlock deferrables in that case and get a pending interrupt
+         * here. */
         ((SymbolValue(INTERRUPTS_ENABLED,thread) != NIL) ||
          (SymbolValue(ALLOW_WITH_INTERRUPTS,thread) != NIL))) {
-        FSHOW((stderr, "/maybe_gc: calling POST_GC\n"));
-        if (!interrupt_handler_pending_p())
-            unblock_deferrable_signals();
-        funcall0(StaticSymbolFunction(POST_GC));
+        sigset_t *context_sigmask = os_context_sigmask_addr(context);
+        if (!deferrables_blocked_in_sigset_p(context_sigmask)) {
+            FSHOW((stderr, "/maybe_gc: calling POST_GC\n"));
+            thread_sigmask(SIG_SETMASK, context_sigmask, 0);
+            check_gc_signals_unblocked_or_lose();
+            funcall0(StaticSymbolFunction(POST_GC));
+        } else {
+            FSHOW((stderr, "/maybe_gc: punting on POST_GC due to blockage\n"));
+        }
     }
     undo_fake_foreign_function_call(context);
     FSHOW((stderr, "/maybe_gc: returning\n"));
index 78f34fb..22ea827 100644 (file)
@@ -164,6 +164,19 @@ sigset_t blockable_sigset;
 sigset_t gc_sigset;
 #endif
 
+boolean
+deferrables_blocked_in_sigset_p(sigset_t *sigset)
+{
+#if !defined(LISP_FEATURE_WIN32)
+    int i;
+    for(i = 1; i < NSIG; i++) {
+        if (sigismember(&deferrable_sigset, i) && sigismember(sigset, i))
+            return 1;
+    }
+#endif
+    return 0;
+}
+
 void
 check_deferrables_unblocked_in_sigset_or_lose(sigset_t *sigset)
 {
@@ -669,24 +682,24 @@ interrupt_handle_pending(os_context_t *context)
 
     check_blockables_blocked_or_lose();
 
-    /* If GC/SIG_STOP_FOR_GC stroke during PA and there was no pending
+    /* If GC/SIG_STOP_FOR_GC struck during PA and there was no pending
      * handler, then the pending mask was saved and
      * gc_blocked_deferrables set. Hence, there can be no pending
      * handler and it's safe to restore the pending mask.
      *
      * Note, that if gc_blocked_deferrables is false we may still have
-     * to GC. In this case, we are coming out of a WITHOUT-GCING. */
+     * to GC. In this case, we are coming out of a WITHOUT-GCING or a
+     * pseudo atomic was interrupt be a deferrable first. */
     if (data->gc_blocked_deferrables) {
         if (data->pending_handler)
             lose("GC blocked deferrables but still got a pending handler.");
         if (SymbolValue(GC_INHIBIT,thread)!=NIL)
             lose("GC blocked deferrables while GC is inhibited.");
-        /* restore the saved signal mask from the original signal
-         * (the one that interrupted us during the critical
-         * section) into the os_context for the signal we're
-         * currently in the handler for. This should ensure that
-         * when we return from the handler the blocked signals are
-         * unblocked */
+        /* Restore the saved signal mask from the original signal (the
+         * one that interrupted us during the critical section) into
+         * the os_context for the signal we're currently in the
+         * handler for. This should ensure that when we return from
+         * the handler the blocked signals are unblocked. */
         sigcopyset(os_context_sigmask_addr(context), &data->pending_mask);
         data->gc_blocked_deferrables = 0;
     }
@@ -706,6 +719,7 @@ interrupt_handle_pending(os_context_t *context)
           * is used in SUB-GC as part of the mechanism to supress
           * recursive gcs.*/
         if (SymbolValue(GC_PENDING,thread) == T) {
+
             /* Two reasons for doing this. First, if there is a
              * pending handler we don't want to run. Second, we are
              * going to clear pseudo atomic interrupted to avoid
@@ -722,7 +736,11 @@ interrupt_handle_pending(os_context_t *context)
 
             /* GC_PENDING is cleared in SUB-GC, or if another thread
              * is doing a gc already we will get a SIG_STOP_FOR_GC and
-             * that will clear it. */
+             * that will clear it.
+             *
+             * If there is a pending handler or gc was triggerred in a
+             * signal handler then maybe_gc won't run POST_GC and will
+             * return normally. */
             if (!maybe_gc(context))
                 lose("GC not inhibited but maybe_gc did not GC.");
 
index 1a4c2af..325723f 100644 (file)
@@ -43,6 +43,7 @@ extern void unblock_deferrable_signals(void);
 extern void unblock_gc_signals(void);
 extern void unblock_signals_in_context_and_maybe_warn(os_context_t *context);
 
+extern boolean deferrables_blocked_in_sigset_p(sigset_t *sigset);
 extern void check_deferrables_blocked_or_lose(void);
 extern void check_blockables_blocked_or_lose(void);
 extern void check_gc_signals_unblocked_or_lose(void);
index 76c2dbc..4ece006 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.25.37"
+"1.0.25.38"