From 39de20e8a3b4aa1f59f194a97f69ae2e3efa2b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Mon, 11 Sep 2023 21:01:46 +0200 Subject: [PATCH] ensureNoDisposablesAreLeakedInTestSuite: ipc (#192570) * ensureNoDisposablesAreLeakedInTestSuite: ipc related to #190503 * debt - proxy services need to ask for disposables --------- Co-authored-by: Benjamin Pasero --- src/vs/base/common/event.ts | 13 +++- src/vs/base/parts/ipc/common/ipc.ts | 45 +++++++---- src/vs/base/parts/ipc/test/common/ipc.test.ts | 78 ++++++++++--------- src/vs/code/electron-main/app.ts | 38 ++++----- .../node/sharedProcess/sharedProcessMain.ts | 18 +++-- .../files/node/watcher/watcherMain.ts | 3 +- src/vs/platform/terminal/node/ptyHostMain.ts | 7 +- 7 files changed, 118 insertions(+), 84 deletions(-) diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 2e5f7fc27a1..b8e1da4b777 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -394,7 +394,7 @@ export namespace Event { * this.onInstallExtension = Event.buffer(service.onInstallExtension, true); * ``` */ - export function buffer(event: Event, flushAfterTimeout = false, _buffer: T[] = []): Event { + export function buffer(event: Event, flushAfterTimeout = false, _buffer: T[] = [], disposable?: DisposableStore): Event { let buffer: T[] | null = _buffer.slice(); let listener: IDisposable | null = event(e => { @@ -405,6 +405,10 @@ export namespace Event { } }); + if (disposable) { + disposable.add(listener); + } + const flush = () => { buffer?.forEach(e => emitter.fire(e)); buffer = null; @@ -414,6 +418,9 @@ export namespace Event { onWillAddFirstListener() { if (!listener) { listener = event(e => emitter.fire(e)); + if (disposable) { + disposable.add(listener); + } } }, @@ -435,6 +442,10 @@ export namespace Event { } }); + if (disposable) { + disposable.add(emitter); + } + return emitter.event; } /** diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 747e8513b1f..db61aed4ff1 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -427,7 +427,6 @@ export class ChannelServer implements IChannelServer { this.sendResponse({ id, data, type: ResponseType.PromiseSuccess }); - this.activeRequests.delete(request.id); }, err => { if (err instanceof Error) { this.sendResponse({ @@ -440,7 +439,8 @@ export class ChannelServer implements IChannelServer{ id, data: err, type: ResponseType.PromiseErrorObj }); } - + }).finally(() => { + disposable.dispose(); this.activeRequests.delete(request.id); }); @@ -639,7 +639,10 @@ export class ChannelClient implements IChannelClient, IDisposable { this.activeRequests.add(disposable); }); - return result.finally(() => { this.activeRequests.delete(disposable); }); + return result.finally(() => { + disposable.dispose(); + this.activeRequests.delete(disposable); + }); } private requestEvent(channelName: string, name: string, arg?: any): Event { @@ -795,6 +798,8 @@ export class IPCServer implements IChannelServer, I private readonly _onDidRemoveConnection = new Emitter>(); readonly onDidRemoveConnection: Event> = this._onDidRemoveConnection.event; + private disposables = new DisposableStore(); + get connections(): Connection[] { const result: Connection[] = []; this._connections.forEach(ctx => result.push(ctx)); @@ -802,10 +807,10 @@ export class IPCServer implements IChannelServer, I } constructor(onDidClientConnect: Event) { - onDidClientConnect(({ protocol, onDidClientDisconnect }) => { + this.disposables.add(onDidClientConnect(({ protocol, onDidClientDisconnect }) => { const onFirstMessage = Event.once(protocol.onMessage); - onFirstMessage(msg => { + this.disposables.add(onFirstMessage(msg => { const reader = new BufferReader(msg); const ctx = deserialize(reader) as TContext; @@ -818,14 +823,14 @@ export class IPCServer implements IChannelServer, I this._connections.add(connection); this._onDidAddConnection.fire(connection); - onDidClientDisconnect(() => { + this.disposables.add(onDidClientDisconnect(() => { channelServer.dispose(); channelClient.dispose(); this._connections.delete(connection); this._onDidRemoveConnection.fire(connection); - }); - }); - }); + })); + })); + })); } /** @@ -879,7 +884,7 @@ export class IPCServer implements IChannelServer, I private getMulticastEvent(channelName: string, clientFilter: (client: Client) => boolean, eventName: string, arg: any): Event { const that = this; - let disposables = new DisposableStore(); + let disposables: DisposableStore | undefined; // Create an emitter which hooks up to all clients // as soon as first listener is added. It also @@ -922,7 +927,8 @@ export class IPCServer implements IChannelServer, I disposables.add(eventMultiplexer); }, onDidRemoveLastListener: () => { - disposables.dispose(); + disposables?.dispose(); + disposables = undefined; } }); @@ -932,14 +938,21 @@ export class IPCServer implements IChannelServer, I registerChannel(channelName: string, channel: IServerChannel): void { this.channels.set(channelName, channel); - this._connections.forEach(connection => { + for (const connection of this._connections) { connection.channelServer.registerChannel(channelName, channel); - }); + } } dispose(): void { - this.channels.clear(); + this.disposables.dispose(); + + for (const connection of this._connections) { + connection.channelClient.dispose(); + connection.channelServer.dispose(); + } + this._connections.clear(); + this.channels.clear(); this._onDidAddConnection.dispose(); this._onDidRemoveConnection.dispose(); } @@ -1074,7 +1087,7 @@ export namespace ProxyChannel { export interface ICreateServiceChannelOptions extends IProxyOptions { } - export function fromService(service: unknown, options?: ICreateServiceChannelOptions): IServerChannel { + export function fromService(service: unknown, disposables: DisposableStore, options?: ICreateServiceChannelOptions): IServerChannel { const handler = service as { [key: string]: unknown }; const disableMarshalling = options && options.disableMarshalling; @@ -1083,7 +1096,7 @@ export namespace ProxyChannel { const mapEventNameToEvent = new Map>(); for (const key in handler) { if (propertyIsEvent(key)) { - mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event, true)); + mapEventNameToEvent.set(key, Event.buffer(handler[key] as Event, true, undefined, disposables)); } } diff --git a/src/vs/base/parts/ipc/test/common/ipc.test.ts b/src/vs/base/parts/ipc/test/common/ipc.test.ts index eaead87178e..35184c08217 100644 --- a/src/vs/base/parts/ipc/test/common/ipc.test.ts +++ b/src/vs/base/parts/ipc/test/common/ipc.test.ts @@ -9,9 +9,11 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { BufferReader, BufferWriter, ClientConnectionEvent, deserialize, IChannel, IMessagePassingProtocol, IPCClient, IPCServer, IServerChannel, ProxyChannel, serialize } from 'vs/base/parts/ipc/common/ipc'; +import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils'; class QueueProtocol implements IMessagePassingProtocol { @@ -111,6 +113,8 @@ interface ITestService { class TestService implements ITestService { + private disposables = new DisposableStore(); + private readonly _onPong = new Emitter(); readonly onPong = this._onPong.event; @@ -131,7 +135,7 @@ class TestService implements ITestService { return Promise.reject(canceled()); } - return new Promise((_, e) => cancellationToken.onCancellationRequested(() => e(canceled()))); + return new Promise((_, e) => this.disposables.add(cancellationToken.onCancellationRequested(() => e(canceled())))); } buffersLength(buffers: VSBuffer[]): Promise { @@ -149,6 +153,10 @@ class TestService implements ITestService { context(context?: unknown): Promise { return Promise.resolve(context); } + + dispose() { + this.disposables.dispose(); + } } class TestChannel implements IServerChannel { @@ -213,6 +221,8 @@ class TestChannelClient implements ITestService { suite('Base IPC', function () { + const store = ensureNoDisposablesAreLeakedInTestSuite(); + test('createProtocolPair', async function () { const [clientProtocol, serverProtocol] = createProtocolPair(); @@ -236,21 +246,16 @@ suite('Base IPC', function () { let ipcService: ITestService; setup(function () { - service = new TestService(); - const testServer = new TestIPCServer(); + service = store.add(new TestService()); + const testServer = store.add(new TestIPCServer()); server = testServer; server.registerChannel(TestChannelId, new TestChannel(service)); - client = testServer.createConnection('client1'); + client = store.add(testServer.createConnection('client1')); ipcService = new TestChannelClient(client.getChannel(TestChannelId)); }); - teardown(function () { - client.dispose(); - server.dispose(); - }); - test('call success', async function () { const r = await ipcService.marco(); return assert.strictEqual(r, 'polo'); @@ -301,7 +306,7 @@ suite('Base IPC', function () { test('listen to events', async function () { const messages: string[] = []; - ipcService.onPong(msg => messages.push(msg)); + store.add(ipcService.onPong(msg => messages.push(msg))); await timeout(0); assert.deepStrictEqual(messages, []); @@ -343,20 +348,21 @@ suite('Base IPC', function () { let service: TestService; let ipcService: ITestService; + const disposables = new DisposableStore(); + setup(function () { - service = new TestService(); - const testServer = new TestIPCServer(); + service = store.add(new TestService()); + const testServer = disposables.add(new TestIPCServer()); server = testServer; - server.registerChannel(TestChannelId, ProxyChannel.fromService(service)); + server.registerChannel(TestChannelId, ProxyChannel.fromService(service, disposables)); - client = testServer.createConnection('client1'); + client = disposables.add(testServer.createConnection('client1')); ipcService = ProxyChannel.toService(client.getChannel(TestChannelId)); }); teardown(function () { - client.dispose(); - server.dispose(); + disposables.clear(); }); test('call success', async function () { @@ -376,7 +382,7 @@ suite('Base IPC', function () { test('listen to events', async function () { const messages: string[] = []; - ipcService.onPong(msg => messages.push(msg)); + disposables.add(ipcService.onPong(msg => messages.push(msg))); await timeout(0); assert.deepStrictEqual(messages, []); @@ -409,20 +415,21 @@ suite('Base IPC', function () { let service: TestService; let ipcService: ITestService; + const disposables = new DisposableStore(); + setup(function () { - service = new TestService(); - const testServer = new TestIPCServer(); + service = store.add(new TestService()); + const testServer = disposables.add(new TestIPCServer()); server = testServer; - server.registerChannel(TestChannelId, ProxyChannel.fromService(service)); + server.registerChannel(TestChannelId, ProxyChannel.fromService(service, disposables)); - client = testServer.createConnection('client1'); + client = disposables.add(testServer.createConnection('client1')); ipcService = ProxyChannel.toService(client.getChannel(TestChannelId), { context: 'Super Context' }); }); teardown(function () { - client.dispose(); - server.dispose(); + disposables.clear(); }); test('call extra context', async function () { @@ -433,20 +440,20 @@ suite('Base IPC', function () { suite('one to many', function () { test('all clients get pinged', async function () { - const service = new TestService(); + const service = store.add(new TestService()); const channel = new TestChannel(service); - const server = new TestIPCServer(); + const server = store.add(new TestIPCServer()); server.registerChannel('channel', channel); let client1GotPinged = false; - const client1 = server.createConnection('client1'); + const client1 = store.add(server.createConnection('client1')); const ipcService1 = new TestChannelClient(client1.getChannel('channel')); - ipcService1.onPong(() => client1GotPinged = true); + store.add(ipcService1.onPong(() => client1GotPinged = true)); let client2GotPinged = false; - const client2 = server.createConnection('client2'); + const client2 = store.add(server.createConnection('client2')); const ipcService2 = new TestChannelClient(client2.getChannel('channel')); - ipcService2.onPong(() => client2GotPinged = true); + store.add(ipcService2.onPong(() => client2GotPinged = true)); await timeout(1); service.ping('hello'); @@ -454,24 +461,20 @@ suite('Base IPC', function () { await timeout(1); assert(client1GotPinged, 'client 1 got pinged'); assert(client2GotPinged, 'client 2 got pinged'); - - client1.dispose(); - client2.dispose(); - server.dispose(); }); test('server gets pings from all clients (broadcast channel)', async function () { - const server = new TestIPCServer(); + const server = store.add(new TestIPCServer()); const client1 = server.createConnection('client1'); - const clientService1 = new TestService(); + const clientService1 = store.add(new TestService()); const clientChannel1 = new TestChannel(clientService1); client1.registerChannel('channel', clientChannel1); const pings: string[] = []; const channel = server.getChannel('channel', () => true); const service = new TestChannelClient(channel); - service.onPong(msg => pings.push(msg)); + store.add(service.onPong(msg => pings.push(msg))); await timeout(1); clientService1.ping('hello 1'); @@ -480,7 +483,7 @@ suite('Base IPC', function () { assert.deepStrictEqual(pings, ['hello 1']); const client2 = server.createConnection('client2'); - const clientService2 = new TestService(); + const clientService2 = store.add(new TestService()); const clientChannel2 = new TestChannel(clientService2); client2.registerChannel('channel', clientChannel2); @@ -503,7 +506,6 @@ suite('Base IPC', function () { assert.deepStrictEqual(pings, ['hello 1', 'hello 2', 'hello again 2']); client2.dispose(); - server.dispose(); }); }); }); diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 9fcc3ce6f10..5307987e657 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -14,7 +14,7 @@ import { isEqualOrParent } from 'vs/base/common/extpath'; import { once } from 'vs/base/common/functional'; import { stripComments } from 'vs/base/common/json'; import { getPathLabel } from 'vs/base/common/labels'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { isAbsolute, join, posix } from 'vs/base/common/path'; import { IProcessEnvironment, isLinux, isLinuxSnap, isMacintosh, isWindows, OS } from 'vs/base/common/platform'; @@ -1051,10 +1051,12 @@ export class CodeApplication extends Disposable { // can talk to the first instance. Electron IPC does not work // across apps until `requestSingleInstance` APIs are adopted. - const launchChannel = ProxyChannel.fromService(accessor.get(ILaunchMainService), { disableMarshalling: true }); + const disposables = this._register(new DisposableStore()); + + const launchChannel = ProxyChannel.fromService(accessor.get(ILaunchMainService), disposables, { disableMarshalling: true }); this.mainProcessNodeIpcServer.registerChannel('launch', launchChannel); - const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsMainService), { disableMarshalling: true }); + const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsMainService), disposables, { disableMarshalling: true }); this.mainProcessNodeIpcServer.registerChannel('diagnostics', diagnosticsChannel); // Policies (main & shared process) @@ -1070,7 +1072,7 @@ export class CodeApplication extends Disposable { sharedProcessClient.then(client => client.registerChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME, fileSystemProviderChannel)); // User Data Profiles - const userDataProfilesService = ProxyChannel.fromService(accessor.get(IUserDataProfilesMainService)); + const userDataProfilesService = ProxyChannel.fromService(accessor.get(IUserDataProfilesMainService), disposables); mainProcessElectronServer.registerChannel('userDataProfiles', userDataProfilesService); sharedProcessClient.then(client => client.registerChannel('userDataProfiles', userDataProfilesService)); @@ -1083,45 +1085,45 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel('update', updateChannel); // Issues - const issueChannel = ProxyChannel.fromService(accessor.get(IIssueMainService)); + const issueChannel = ProxyChannel.fromService(accessor.get(IIssueMainService), disposables); mainProcessElectronServer.registerChannel('issue', issueChannel); // Encryption - const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService)); + const encryptionChannel = ProxyChannel.fromService(accessor.get(IEncryptionMainService), disposables); mainProcessElectronServer.registerChannel('encryption', encryptionChannel); // Signing - const signChannel = ProxyChannel.fromService(accessor.get(ISignService)); + const signChannel = ProxyChannel.fromService(accessor.get(ISignService), disposables); mainProcessElectronServer.registerChannel('sign', signChannel); // Keyboard Layout - const keyboardLayoutChannel = ProxyChannel.fromService(accessor.get(IKeyboardLayoutMainService)); + const keyboardLayoutChannel = ProxyChannel.fromService(accessor.get(IKeyboardLayoutMainService), disposables); mainProcessElectronServer.registerChannel('keyboardLayout', keyboardLayoutChannel); // Native host (main & shared process) this.nativeHostMainService = accessor.get(INativeHostMainService); - const nativeHostChannel = ProxyChannel.fromService(this.nativeHostMainService); + const nativeHostChannel = ProxyChannel.fromService(this.nativeHostMainService, disposables); mainProcessElectronServer.registerChannel('nativeHost', nativeHostChannel); sharedProcessClient.then(client => client.registerChannel('nativeHost', nativeHostChannel)); // Workspaces - const workspacesChannel = ProxyChannel.fromService(accessor.get(IWorkspacesService)); + const workspacesChannel = ProxyChannel.fromService(accessor.get(IWorkspacesService), disposables); mainProcessElectronServer.registerChannel('workspaces', workspacesChannel); // Menubar - const menubarChannel = ProxyChannel.fromService(accessor.get(IMenubarMainService)); + const menubarChannel = ProxyChannel.fromService(accessor.get(IMenubarMainService), disposables); mainProcessElectronServer.registerChannel('menubar', menubarChannel); // URL handling - const urlChannel = ProxyChannel.fromService(accessor.get(IURLService)); + const urlChannel = ProxyChannel.fromService(accessor.get(IURLService), disposables); mainProcessElectronServer.registerChannel('url', urlChannel); // Extension URL Trust - const extensionUrlTrustChannel = ProxyChannel.fromService(accessor.get(IExtensionUrlTrustService)); + const extensionUrlTrustChannel = ProxyChannel.fromService(accessor.get(IExtensionUrlTrustService), disposables); mainProcessElectronServer.registerChannel('extensionUrlTrust', extensionUrlTrustChannel); // Webview Manager - const webviewChannel = ProxyChannel.fromService(accessor.get(IWebviewManagerService)); + const webviewChannel = ProxyChannel.fromService(accessor.get(IWebviewManagerService), disposables); mainProcessElectronServer.registerChannel('webview', webviewChannel); // Storage (main & shared process) @@ -1134,11 +1136,11 @@ export class CodeApplication extends Disposable { sharedProcessClient.then(client => client.registerChannel('profileStorageListener', profileStorageListener)); // Terminal - const ptyHostChannel = ProxyChannel.fromService(accessor.get(ILocalPtyService)); + const ptyHostChannel = ProxyChannel.fromService(accessor.get(ILocalPtyService), disposables); mainProcessElectronServer.registerChannel(TerminalIpcChannels.LocalPty, ptyHostChannel); // External Terminal - const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService)); + const externalTerminalChannel = ProxyChannel.fromService(accessor.get(IExternalTerminalMainService), disposables); mainProcessElectronServer.registerChannel('externalTerminal', externalTerminalChannel); // Logger @@ -1151,11 +1153,11 @@ export class CodeApplication extends Disposable { mainProcessElectronServer.registerChannel('extensionhostdebugservice', electronExtensionHostDebugBroadcastChannel); // Extension Host Starter - const extensionHostStarterChannel = ProxyChannel.fromService(accessor.get(IExtensionHostStarter)); + const extensionHostStarterChannel = ProxyChannel.fromService(accessor.get(IExtensionHostStarter), disposables); mainProcessElectronServer.registerChannel(ipcExtensionHostStarterChannelName, extensionHostStarterChannel); // Utility Process Worker - const utilityProcessWorkerChannel = ProxyChannel.fromService(accessor.get(IUtilityProcessWorkerMainService)); + const utilityProcessWorkerChannel = ProxyChannel.fromService(accessor.get(IUtilityProcessWorkerMainService), disposables); mainProcessElectronServer.registerChannel(ipcUtilityProcessWorkerChannelName, utilityProcessWorkerChannel); } diff --git a/src/vs/code/node/sharedProcess/sharedProcessMain.ts b/src/vs/code/node/sharedProcess/sharedProcessMain.ts index a81bedb9ab4..2a46b4ddaf5 100644 --- a/src/vs/code/node/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/node/sharedProcess/sharedProcessMain.ts @@ -7,7 +7,7 @@ import { hostname, release } from 'os'; import { MessagePortMain, MessageEvent } from 'vs/base/parts/sandbox/node/electronTypes'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; -import { combinedDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { firstOrDefault } from 'vs/base/common/arrays'; @@ -367,16 +367,18 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { private initChannels(accessor: ServicesAccessor): void { + const disposables = this._register(new DisposableStore()); + // Extensions Management const channel = new ExtensionManagementChannel(accessor.get(IExtensionManagementService), () => null); this.server.registerChannel('extensions', channel); // Language Packs - const languagePacksChannel = ProxyChannel.fromService(accessor.get(ILanguagePackService)); + const languagePacksChannel = ProxyChannel.fromService(accessor.get(ILanguagePackService), disposables); this.server.registerChannel('languagePacks', languagePacksChannel); // Diagnostics - const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsService)); + const diagnosticsChannel = ProxyChannel.fromService(accessor.get(IDiagnosticsService), disposables); this.server.registerChannel('diagnostics', diagnosticsChannel); // Extension Tips @@ -384,11 +386,11 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { this.server.registerChannel('extensionTipsService', extensionTipsChannel); // Checksum - const checksumChannel = ProxyChannel.fromService(accessor.get(IChecksumService)); + const checksumChannel = ProxyChannel.fromService(accessor.get(IChecksumService), disposables); this.server.registerChannel('checksum', checksumChannel); // Profiling - const profilingChannel = ProxyChannel.fromService(accessor.get(IV8InspectProfilingService)); + const profilingChannel = ProxyChannel.fromService(accessor.get(IV8InspectProfilingService), disposables); this.server.registerChannel('v8InspectProfiling', profilingChannel); // Settings Sync @@ -396,7 +398,7 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { this.server.registerChannel('userDataSyncMachines', userDataSyncMachineChannel); // Custom Endpoint Telemetry - const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService)); + const customEndpointTelemetryChannel = ProxyChannel.fromService(accessor.get(ICustomEndpointTelemetryService), disposables); this.server.registerChannel('customEndpointTelemetry', customEndpointTelemetryChannel); const userDataSyncAccountChannel = new UserDataSyncAccountServiceChannel(accessor.get(IUserDataSyncAccountService)); @@ -413,11 +415,11 @@ class SharedProcessMain extends Disposable implements IClientConnectionFilter { this.server.registerChannel('userDataAutoSync', userDataAutoSyncChannel); // Tunnel - const sharedProcessTunnelChannel = ProxyChannel.fromService(accessor.get(ISharedProcessTunnelService)); + const sharedProcessTunnelChannel = ProxyChannel.fromService(accessor.get(ISharedProcessTunnelService), disposables); this.server.registerChannel(ipcSharedProcessTunnelChannelName, sharedProcessTunnelChannel); // Remote Tunnel - const remoteTunnelChannel = ProxyChannel.fromService(accessor.get(IRemoteTunnelService)); + const remoteTunnelChannel = ProxyChannel.fromService(accessor.get(IRemoteTunnelService), disposables); this.server.registerChannel('remoteTunnel', remoteTunnelChannel); } diff --git a/src/vs/platform/files/node/watcher/watcherMain.ts b/src/vs/platform/files/node/watcher/watcherMain.ts index e3fd4ca9cde..09f952c4f4a 100644 --- a/src/vs/platform/files/node/watcher/watcherMain.ts +++ b/src/vs/platform/files/node/watcher/watcherMain.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { DisposableStore } from 'vs/base/common/lifecycle'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { Server as ChildProcessServer } from 'vs/base/parts/ipc/node/ipc.cp'; import { Server as UtilityProcessServer } from 'vs/base/parts/ipc/node/ipc.mp'; @@ -17,4 +18,4 @@ if (isUtilityProcess(process)) { } const service = new UniversalWatcher(); -server.registerChannel('watcher', ProxyChannel.fromService(service)); +server.registerChannel('watcher', ProxyChannel.fromService(service, new DisposableStore())); diff --git a/src/vs/platform/terminal/node/ptyHostMain.ts b/src/vs/platform/terminal/node/ptyHostMain.ts index cd0faa5ff20..f3693acbda3 100644 --- a/src/vs/platform/terminal/node/ptyHostMain.ts +++ b/src/vs/platform/terminal/node/ptyHostMain.ts @@ -21,6 +21,7 @@ import { HeartbeatService } from 'vs/platform/terminal/node/heartbeatService'; import { PtyService } from 'vs/platform/terminal/node/ptyService'; import { isUtilityProcess } from 'vs/base/parts/sandbox/node/electronTypes'; import { timeout } from 'vs/base/common/async'; +import { DisposableStore } from 'vs/base/common/lifecycle'; startPtyHost(); @@ -72,13 +73,15 @@ async function startPtyHost() { logService.warn(`Pty host is simulating ${simulatedLatency}ms latency`); } + const disposables = new DisposableStore(); + // Heartbeat responsiveness tracking const heartbeatService = new HeartbeatService(); - server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService)); + server.registerChannel(TerminalIpcChannels.Heartbeat, ProxyChannel.fromService(heartbeatService, disposables)); // Init pty service const ptyService = new PtyService(logService, productService, reconnectConstants, simulatedLatency); - const ptyServiceChannel = ProxyChannel.fromService(ptyService); + const ptyServiceChannel = ProxyChannel.fromService(ptyService, disposables); server.registerChannel(TerminalIpcChannels.PtyHost, ptyServiceChannel); // Register a channel for direct communication via Message Port