Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix leak in File System Watcher #12144

Merged
merged 2 commits into from
Feb 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down Expand Up @@ -196,22 +196,34 @@ 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<void> {
while (await this.orCancel(fsp.stat(this.fsPath).then(() => false, () => true))) {
await this.orCancel(new Promise(resolve => setTimeout(resolve, 500)));
while (await fsp.stat(this.fsPath).then(() => false, () => true)) {
await timeout(500);
this.assertNotDisposed();
}
this.assertNotDisposed();
const watcher = await this.createNsfw();
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);
throw WatcherDisposal;
}
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;
}

Expand Down Expand Up @@ -299,13 +311,6 @@ export class NsfwWatcher {
});
}

/**
* Wrap a promise to reject as soon as this handle gets disposed.
*/
protected async orCancel<T>(promise: Promise<T>): Promise<T> {
return Promise.race<T>([this.deferredDisposalDeferred.promise, promise]);
}

/**
* When references hit zero, we'll schedule disposal for a bit later.
*
Expand Down