From 643efe16723422502c97b7ce9a0b56920d581814 Mon Sep 17 00:00:00 2001 From: Edy Silva Date: Tue, 26 Nov 2024 13:57:18 -0300 Subject: [PATCH] test: test clean up settled signals --- lib/internal/abort_controller.js | 9 ++-- .../test-abortsignal-drop-settled-signals.mjs | 46 +++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/lib/internal/abort_controller.js b/lib/internal/abort_controller.js index 4da7ecc7b2fe11..2514a8d0932aa2 100644 --- a/lib/internal/abort_controller.js +++ b/lib/internal/abort_controller.js @@ -99,15 +99,16 @@ const dependantSignalsCleanupRegistry = new SafeFinalizationRegistry((signalWeak const gcPersistentSignals = new SafeSet(); const finalizer = new SafeFinalizationRegistry(({ sourceSignalRef, composedSignalRef }) => { - // TODO: remove ref from source signal - // TODO: remove composed signal from gcPersistentSignals const composedSignal = composedSignalRef.deref(); if (composedSignal !== undefined) { composedSignal[kSourceSignals].delete(sourceSignalRef); - gcPersistentSignals.delete(composedSignal); + + if (composedSignal[kSourceSignals].size === 0) { + // This signal will no longer abort. There's no need to keep it in the gcPersistentSignals set. + gcPersistentSignals.delete(composedSignal); + } } - // TODO: remove ref from dependant signal const sourceSignal = sourceSignalRef.deref(); if (sourceSignal !== undefined) { sourceSignal[kDependantSignals].delete(composedSignalRef); diff --git a/test/parallel/test-abortsignal-drop-settled-signals.mjs b/test/parallel/test-abortsignal-drop-settled-signals.mjs index 728002b51d30d5..c4d8fedaa503ad 100644 --- a/test/parallel/test-abortsignal-drop-settled-signals.mjs +++ b/test/parallel/test-abortsignal-drop-settled-signals.mjs @@ -64,6 +64,38 @@ function runShortLivedSourceSignal(limit, done) { run(1); }; +function runWithOrphanListeners(limit, done) { + let composedSignalRef; + const composedSignalRefs = []; + const handler = () => { }; + + function run(iteration) { + const ac = new AbortController(); + if (iteration > limit) { + setImmediate(() => { + global.gc(); + setImmediate(() => { + global.gc(); + + done(composedSignalRefs); + }); + }); + return; + } + + composedSignalRef = new WeakRef(AbortSignal.any([ac.signal])); + composedSignalRef.deref().addEventListener('abort', handler); + + composedSignalRefs.push(composedSignalRef); + + setImmediate(() => { + run(iteration + 1); + }); + } + + run(1); +} + const limit = 10_000; describe('when there is a long-lived signal', () => { @@ -120,3 +152,17 @@ it('drops settled dependant signals when signal is composite', (t, done) => { }); }); }); + +it('drops settled signals even when there are listeners', (t, done) => { + runWithOrphanListeners(limit, (signalRefs) => { + setImmediate(() => { + global.gc(); + + const unGCedSignals = [...signalRefs].filter((ref) => ref.deref()); + + t.assert.strictEqual(unGCedSignals.length, 0); + + done(); + }); + }); +});