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));
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"));
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)
{
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;
}
* 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
/* 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.");
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);
;;; 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"