From 29dc4b6927186a756606a019a76aabf89befe726 Mon Sep 17 00:00:00 2001 From: Chemi Atlow Date: Sat, 24 Jun 2023 18:52:38 +0300 Subject: [PATCH] fs: use kResistStopPropagation PR-URL: https://github.com/nodejs/node/pull/48521 Backport-PR-URL: https://github.com/nodejs/node/pull/49618 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Moshe Atlow --- lib/fs.js | 4 +++- lib/internal/fs/recursive_watch.js | 4 +++- lib/internal/fs/watchers.js | 7 ++++++- lib/internal/test_runner/mock/mock_timers.js | 22 +++++++++++++------- lib/internal/test_runner/runner.js | 11 +++++++++- lib/internal/test_runner/test.js | 11 +++++++++- lib/timers/promises.js | 10 ++++++--- 7 files changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index fd99fef03c5243..db3c202bfa6d75 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -160,6 +160,7 @@ let ReadStream; let WriteStream; let rimraf; let rimrafSync; +let kResistStopPropagation; // These have to be separate because of how graceful-fs happens to do it's // monkeypatching. @@ -2435,7 +2436,8 @@ function watch(filename, options, listener) { process.nextTick(() => watcher.close()); } else { const listener = () => watcher.close(); - options.signal.addEventListener('abort', listener); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + options.signal.addEventListener('abort', listener, { __proto__: null, [kResistStopPropagation]: true }); watcher.once('close', () => { options.signal.removeEventListener('abort', listener); }); diff --git a/lib/internal/fs/recursive_watch.js b/lib/internal/fs/recursive_watch.js index ed146fa28bed8d..1cd99ffb41f7e2 100644 --- a/lib/internal/fs/recursive_watch.js +++ b/lib/internal/fs/recursive_watch.js @@ -42,6 +42,7 @@ function lazyLoadFsSync() { internalSync ??= require('fs'); return internalSync; } +let kResistStopPropagation; async function traverse(dir, files = new SafeMap(), symbolicLinks = new SafeSet()) { const { opendir } = lazyLoadFsPromises(); @@ -265,7 +266,8 @@ class FSWatcher extends EventEmitter { } : (resolve, reject) => { const onAbort = () => reject(new AbortError(undefined, { cause: signal.reason })); if (signal.aborted) return onAbort(); - signal.addEventListener('abort', onAbort, { __proto__: null, once: true }); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', onAbort, { __proto__: null, once: true, [kResistStopPropagation]: true }); this.once('change', (eventType, filename) => { signal.removeEventListener('abort', onAbort); resolve({ __proto__: null, value: { eventType, filename } }); diff --git a/lib/internal/fs/watchers.js b/lib/internal/fs/watchers.js index ce885c154c81c5..99212fa713bf3f 100644 --- a/lib/internal/fs/watchers.js +++ b/lib/internal/fs/watchers.js @@ -299,6 +299,8 @@ ObjectDefineProperty(FSEvent.prototype, 'owner', { set(v) { return this[owner_symbol] = v; }, }); +let kResistStopPropagation; + async function* watch(filename, options = kEmptyObject) { const path = toNamespacedPath(getValidatedPath(filename)); validateObject(options, 'options'); @@ -330,7 +332,10 @@ async function* watch(filename, options = kEmptyObject) { }; try { - signal?.addEventListener('abort', oncancel, { once: true }); + if (signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', oncancel, { __proto__: null, once: true, [kResistStopPropagation]: true }); + } handle.onchange = (status, eventType, filename) => { if (status < 0) { const error = uvException({ diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index 7eea0c592f7408..32ee71d8bb2ff0 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -32,6 +32,8 @@ const nodeTimers = require('timers'); const nodeTimersPromises = require('timers/promises'); const EventEmitter = require('events'); +let kResistStopPropagation; + function compareTimersLists(a, b) { return (a.runAt - b.runAt) || (a.id - b.id); } @@ -100,7 +102,7 @@ class MockTimers { if (options?.signal) { validateAbortSignal(options.signal, 'options.signal'); - if (options.signal?.aborted) { + if (options.signal.aborted) { throw abortIt(options.signal); } @@ -108,9 +110,11 @@ class MockTimers { emitter.emit('data', { __proto__: null, aborted: true, reason }); }; - options.signal?.addEventListener('abort', onAbort, { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + options.signal.addEventListener('abort', onAbort, { __proto__: null, once: true, + [kResistStopPropagation]: true, }); } @@ -161,7 +165,7 @@ class MockTimers { return reject(err); } - if (options.signal?.aborted) { + if (options.signal.aborted) { return reject(abortIt(options.signal)); } } @@ -175,10 +179,14 @@ class MockTimers { return resolve(result || id); }, ms); - options?.signal?.addEventListener('abort', onabort, { - __proto__: null, - once: true, - }); + if (options?.signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + options.signal.addEventListener('abort', onabort, { + __proto__: null, + once: true, + [kResistStopPropagation]: true, + }); + } }); } diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 88b648d9a19cbf..09dde95fb0522c 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -76,6 +76,8 @@ const kDiagnosticsFilterArgs = ['tests', 'suites', 'pass', 'fail', 'cancelled', const kCanceledTests = new SafeSet() .add(kCancelledByParent).add(kAborted).add(kTestTimeoutFailure); +let kResistStopPropagation; + // TODO(cjihrig): Replace this with recursive readdir once it lands. function processPath(path, testFiles, options) { const stats = statSync(path); @@ -441,7 +443,14 @@ function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) { triggerUncaughtException(error, true /* fromPromise */); })); }); - signal?.addEventListener('abort', () => root.postRun(), { __proto__: null, once: true }); + if (signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener( + 'abort', + () => root.postRun(), + { __proto__: null, once: true, [kResistStopPropagation]: true }, + ); + } return filesWatcher; } diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 74c20a31278050..cc8a7ff2ac0acd 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -72,6 +72,7 @@ const kUnwrapErrors = new SafeSet() .add(kTestCodeFailure).add(kHookFailure) .add('uncaughtException').add('unhandledRejection'); const { testNamePatterns, testOnlyFlag } = parseCommandLine(); +let kResistStopPropagation; function stopTest(timeout, signal) { if (timeout === kDefaultTimeout) { @@ -266,7 +267,15 @@ class Test extends AsyncResource { this.signal = this.#abortController.signal; validateAbortSignal(signal, 'options.signal'); - this.#outerSignal?.addEventListener('abort', this.#abortHandler); + if (signal) { + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + } + + this.#outerSignal?.addEventListener( + 'abort', + this.#abortHandler, + { __proto__: null, [kResistStopPropagation]: true }, + ); this.fn = fn; this.harness = null; // Configured on the root test by the test harness. diff --git a/lib/timers/promises.js b/lib/timers/promises.js index d224520f10694d..2bf36d6cc51700 100644 --- a/lib/timers/promises.js +++ b/lib/timers/promises.js @@ -40,6 +40,7 @@ const { } = require('internal/util'); const kScheduler = Symbol('kScheduler'); +let kResistStopPropagation; function cancelListenerHandler(clear, reject, signal) { if (!this._destroyed) { @@ -81,7 +82,8 @@ function setTimeout(after, value, options = kEmptyObject) { if (signal) { oncancel = FunctionPrototypeBind(cancelListenerHandler, timeout, clearTimeout, reject, signal); - signal.addEventListener('abort', oncancel); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', oncancel, { __proto__: null, [kResistStopPropagation]: true }); } }); return oncancel !== undefined ? @@ -123,7 +125,8 @@ function setImmediate(value, options = kEmptyObject) { oncancel = FunctionPrototypeBind(cancelListenerHandler, immediate, clearImmediate, reject, signal); - signal.addEventListener('abort', oncancel); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', oncancel, { __proto__: null, [kResistStopPropagation]: true }); } }); return oncancel !== undefined ? @@ -164,7 +167,8 @@ async function* setInterval(after, value, options = kEmptyObject) { callback = undefined; } }; - signal.addEventListener('abort', onCancel, { once: true }); + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; + signal.addEventListener('abort', onCancel, { __proto__: null, once: true, [kResistStopPropagation]: true }); } while (!signal?.aborted) {