0.9.1.7: "fix" SB-SPROF on non-gencgc platforms
[sbcl.git] / src / runtime / interrupt.c
index 2377308..c2ef993 100644 (file)
@@ -199,7 +199,7 @@ fake_foreign_function_call(os_context_t *context)
 #ifdef reg_ALLOC
     dynamic_space_free_pointer =
        (lispobj *)(*os_context_register_addr(context, reg_ALLOC));
-#ifdef alpha
+#if defined(LISP_FEATURE_ALPHA)
     if ((long)dynamic_space_free_pointer & 1) {
        lose("dead in fake_foreign_function_call, context = %x", context);
     }
@@ -305,8 +305,9 @@ interrupt_handle_pending(os_context_t *context)
 
     thread=arch_os_get_current_thread();
     data=thread->interrupt_data;
-    /* FIXME I'm not altogether sure this is appropriate if we're
-     * here as the result of a pseudo-atomic */
+
+    /* FIXME: This is almost certainly wrong if we're here as the
+     * result of a pseudo-atomic as opposed to WITHOUT-INTERRUPTS. */
     SetSymbolValue(INTERRUPT_PENDING, NIL,thread);
 
     /* restore the saved signal mask from the original signal (the
@@ -517,7 +518,7 @@ maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
     interrupt_handle_now(signal, info, context);
 #ifdef LISP_FEATURE_DARWIN
     /* Work around G5 bug */
-    sigreturn(void_context);
+    DARWIN_FIX_CONTEXT(context);
 #endif
 }
 
@@ -547,11 +548,19 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, void *void_context)
      * awful state, to stop them from being waited for indefinitely.
      * Userland reaping is done later when GC is finished  */
     mark_dead_threads();
-
+    if(thread->state!=STATE_STOPPING) {
+      lose("sig_stop_for_gc_handler: wrong thread state: %ld\n",
+           fixnum_value(thread->state));
+    }
     thread->state=STATE_STOPPED;
 
     sigemptyset(&ss); sigaddset(&ss,SIG_STOP_FOR_GC);
     sigwaitinfo(&ss,0);
+    if(thread->state!=STATE_STOPPED) {
+      lose("sig_stop_for_gc_handler: wrong thread state on wakeup: %ld\n",
+           fixnum_value(thread->state));
+    }
+    thread->state=STATE_RUNNING;
 
     undo_fake_foreign_function_call(context);
 }
@@ -563,7 +572,7 @@ interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context)
     os_context_t *context = arch_os_get_context(&void_context);
     interrupt_handle_now(signal, info, context);
 #ifdef LISP_FEATURE_DARWIN
-    sigreturn(void_context);
+    DARWIN_FIX_CONTEXT(context);
 #endif
 }
 
@@ -808,6 +817,53 @@ interrupt_maybe_gc(int signal, siginfo_t *info, void *void_context)
 
 #endif
 
+void
+kludge_sigset_for_gc(sigset_t * set)
+{
+#ifndef LISP_FEATURE_GENCGC
+    /* FIXME: It is not sure if GENCGC is really right here: maybe this
+     * really affects eg. only Sparc and PPC. And the following KLUDGE
+     * could really use real fixing as well.
+     *
+     * KLUDGE: block some async signals that seem to have the ability
+     * to hang us in an uninterruptible state during GC -- at least
+     * part of the time. The main beneficiary of this is SB-SPROF, as
+     * SIGPROF was almost certain to be eventually triggered at a bad
+     * moment, rendering it virtually useless. SIGINT and SIGIO from
+     * user or eg. Slime also seemed to occasionally do this.
+     *
+     * The problem this papers over appears to be something going awry
+     * in SB-UNIX:RECEIVE-PENDING-SIGNALS at the end of the
+     * WITHOUT-INTERRUPTS in SUB-GC: adding debugging output shows us
+     * leaving the body of W-I, but never entering sigtrap_handler.
+     *
+     * Empirically, it seems that the problem is only triggered if the
+     * GC was triggered/deferred during a PA section, but this is not
+     * a sufficient condition: some collections triggered in such a
+     * manner seem to be able to receive and defer a signal during the
+     * GC without issues. Likewise empirically, it seems that the
+     * problem arises more often with floating point code then not. Eg
+     * (LOOP (* (RANDOM 1.0) (RANDOM 1.0))) will eventually hang if
+     * run with SB-SPROF on, but (LOOP (FOO (MAKE-LIST 24))) will not.
+     * All this makes some badnesss in the interaction between PA and
+     * W-I seem likely, possibly in the form of one or more bad VOPs.
+     * 
+     * For additional entertainment on the affected platforms we
+     * currently use an actual illegal instruction to receive pending
+     * interrupts instead of a trap: whether this has any bearing on
+     * the matter is unknown.
+     * 
+     * Apparently CMUCL blocks everything but SIGILL for GC on Sparc,
+     * possibly for this very reason.
+     *
+     * -- NS 2005-05-20
+     */
+    sigdelset(set, SIGPROF);
+    sigdelset(set, SIGIO);
+    sigdelset(set, SIGINT);
+#endif
+}
+
 /* this is also used by gencgc, in alloc() */
 boolean
 interrupt_maybe_gc_int(int signal, siginfo_t *info, void *void_context)
@@ -815,16 +871,24 @@ interrupt_maybe_gc_int(int signal, siginfo_t *info, void *void_context)
     sigset_t new;
     os_context_t *context=(os_context_t *) void_context;
     fake_foreign_function_call(context);
+
     /* SUB-GC may return without GCing if *GC-INHIBIT* is set, in
      * which case we will be running with no gc trigger barrier
      * thing for a while.  But it shouldn't be long until the end
-     * of WITHOUT-GCING. */
+     * of WITHOUT-GCING. 
+     *
+     * FIXME: It would be good to protect the end of dynamic space
+     * and signal a storage condition from there.
+     */
 
+    /* enable some signals before calling into Lisp */
     sigemptyset(&new);
     sigaddset_blockable(&new);
-    /* enable signals before calling into Lisp */
+    kludge_sigset_for_gc(&new);
     sigprocmask(SIG_UNBLOCK,&new,0);
+
     funcall0(SymbolFunction(SUB_GC));
+
     undo_fake_foreign_function_call(context);
     return 1;
 }