From 38aa43b66fc47723393a9ab065733ce808813047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=A4der?= Date: Fri, 3 Feb 2023 15:14:28 +0100 Subject: [PATCH 1/2] Don't repeatedly call Promise.race(). Fixes #12001 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code was calling Promise.race() repeatedly while waiting for a file to come into existence. This added a `PromiseReaction` object each time, which never was collected Contributed on behalf of STMicroelectronics Signed-off-by: Thomas Mäder --- .../nsfw-watcher/nsfw-filesystem-service.ts | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts b/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts index e60b103f4e740..79cc13f49c27b 100644 --- a/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts +++ b/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts @@ -23,7 +23,7 @@ import { FileChangeType, FileSystemWatcherService, FileSystemWatcherServiceClient, WatchOptions } from '../../common/filesystem-watcher-protocol'; import { FileChangeCollection } from '../file-change-collection'; -import { Deferred } from '@theia/core/lib/common/promise-util'; +import { Deferred, timeout } from '@theia/core/lib/common/promise-util'; export interface NsfwWatcherOptions { ignored: IMinimatch[] @@ -201,17 +201,21 @@ export class NsfwWatcher { * before running an NSFW watcher. */ protected async start(): Promise { - while (await this.orCancel(fsp.stat(this.fsPath).then(() => false, () => true))) { - await this.orCancel(new Promise(resolve => setTimeout(resolve, 500))); + while (!this.disposed && await fsp.stat(this.fsPath).then(() => false, () => true)) { + await timeout(500); + } + const watcher = await this.createNsfw(); + if (this.disposed) { + return; + } + + await watcher.start(); + this.debug('STARTED', `disposed=${this.disposed}`); + // The watcher could be disposed while it was starting, make sure to check for this: + if (this.disposed) { + await this.stopNsfw(watcher); + return; } - const watcher = await this.orCancel(this.createNsfw()); - await this.orCancel(watcher.start().then(() => { - this.debug('STARTED', `disposed=${this.disposed}`); - // The watcher could be disposed while it was starting, make sure to check for this: - if (this.disposed) { - this.stopNsfw(watcher); - } - })); this.nsfw = watcher; } @@ -299,13 +303,6 @@ export class NsfwWatcher { }); } - /** - * Wrap a promise to reject as soon as this handle gets disposed. - */ - protected async orCancel(promise: Promise): Promise { - return Promise.race([this.deferredDisposalDeferred.promise, promise]); - } - /** * When references hit zero, we'll schedule disposal for a bit later. * From 9a8231d3f07ab56738da504e1e02f869cc8f4f74 Mon Sep 17 00:00:00 2001 From: Paul Marechal Date: Fri, 3 Feb 2023 17:06:53 -0500 Subject: [PATCH 2/2] throw upon cancellation --- .../nsfw-watcher/nsfw-filesystem-service.ts | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts b/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts index 79cc13f49c27b..e5d5812e79ebc 100644 --- a/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts +++ b/packages/filesystem/src/node/nsfw-watcher/nsfw-filesystem-service.ts @@ -196,25 +196,33 @@ export class NsfwWatcher { return this.refsPerClient.size > 0; } + /** + * @throws with {@link WatcherDisposal} if this instance is disposed. + */ + protected assertNotDisposed(): void { + if (this.disposed) { + throw WatcherDisposal; + } + } + /** * When starting a watcher, we'll first check and wait for the path to exists * before running an NSFW watcher. */ protected async start(): Promise { - while (!this.disposed && await fsp.stat(this.fsPath).then(() => false, () => true)) { + while (await fsp.stat(this.fsPath).then(() => false, () => true)) { await timeout(500); + this.assertNotDisposed(); } + this.assertNotDisposed(); const watcher = await this.createNsfw(); - if (this.disposed) { - return; - } - + this.assertNotDisposed(); await watcher.start(); this.debug('STARTED', `disposed=${this.disposed}`); // The watcher could be disposed while it was starting, make sure to check for this: if (this.disposed) { await this.stopNsfw(watcher); - return; + throw WatcherDisposal; } this.nsfw = watcher; }