- /* set things up so that GC happens when we finish the PA
- * section. We only do this if there wasn't a pending handler
- * already, in case it was a gc. If it wasn't a GC, the next
- * allocation will get us back to this point anyway, so no harm done
- */
- struct interrupt_data *data=th->interrupt_data;
- if(!data->pending_handler)
- maybe_defer_handler(interrupt_maybe_gc_int,data,0,0,0);
+ struct thread *thread=arch_os_get_current_thread();
+ /* Don't flood the system with interrupts if the need to gc is
+ * already noted. This can happen for example when SUB-GC
+ * allocates or after a gc triggered in a WITHOUT-GCING. */
+ if (SymbolValue(NEED_TO_COLLECT_GARBAGE,thread) == NIL) {
+ /* set things up so that GC happens when we finish the PA
+ * section. We only do this if there wasn't a pending
+ * handler already, in case it was a gc. If it wasn't a
+ * GC, the next allocation will get us back to this point
+ * anyway, so no harm done
+ */
+ struct interrupt_data *data=th->interrupt_data;
+ sigset_t new_mask,old_mask;
+ sigemptyset(&new_mask);
+ sigaddset_blockable(&new_mask);
+ thread_sigmask(SIG_BLOCK,&new_mask,&old_mask);
+
+ if((!data->pending_handler) &&
+ maybe_defer_handler(interrupt_maybe_gc_int,data,0,0,0)) {
+ /* Leave the signals blocked just as if it was
+ * deferred the normal way and set the
+ * pending_mask. */
+ sigcopyset(&(data->pending_mask),&old_mask);
+ SetSymbolValue(NEED_TO_COLLECT_GARBAGE,T,thread);
+ } else {
+ thread_sigmask(SIG_SETMASK,&old_mask,0);
+ }
+ }