(defun sub-gc (&key (gen 0))
(unless (eql (sb!thread:current-thread-id)
(sb!thread::mutex-value *already-in-gc*))
+ ;; With gencgc, unless *NEED-TO-COLLECT-GARBAGE* every allocation
+ ;; in this function triggers another gc, potentially exceeding
+ ;; maximum interrupt nesting.
(setf *need-to-collect-garbage* t)
(when (zerop *gc-inhibit*)
(sb!thread:with-mutex (*already-in-gc*)
(when (plusp freed)
(incf *n-bytes-freed-or-purified* freed)))
(sb!thread::reap-dead-threads)))
- ;; Outside the mutex, these may cause another GC.
+ ;; Outside the mutex, these may cause another GC. FIXME: it can
+ ;; potentially exceed maximum interrupt nesting by triggering
+ ;; GCs.
(run-pending-finalizers)
(dolist (hook *after-gc-hooks*)
(handler-case
* we should GC in the near future
*/
if (auto_gc_trigger && bytes_allocated > auto_gc_trigger) {
- /* 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
- */
- sigset_t new_mask,old_mask;
- sigemptyset(&new_mask);
- sigaddset_blockable(&new_mask);
- sigprocmask(SIG_BLOCK,&new_mask,&old_mask);
-
- struct interrupt_data *data=th->interrupt_data;
- 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);
- } else {
- sigprocmask(SIG_SETMASK,&old_mask,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
+ */
+ sigset_t new_mask,old_mask;
+ sigemptyset(&new_mask);
+ sigaddset_blockable(&new_mask);
+ sigprocmask(SIG_BLOCK,&new_mask,&old_mask);
+
+ struct interrupt_data *data=th->interrupt_data;
+ 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 {
+ sigprocmask(SIG_SETMASK,&old_mask,0);
+ }
}
}
new_obj = gc_alloc_with_region(nbytes,0,region,0);