diff --git a/src/coreclrDebug/activate.ts b/src/coreclrDebug/activate.ts index 01becfc7b..1bffd2924 100644 --- a/src/coreclrDebug/activate.ts +++ b/src/coreclrDebug/activate.ts @@ -310,21 +310,3 @@ export class DebugAdapterExecutableFactory implements vscode.DebugAdapterDescrip return executable; } } - -let _brokeredServicePipeName: string | undefined; - -/** - * Initialize brokered service pipe name from C# dev kit, if available. - * - * @param csDevKitPipeName Activated brokered service pipe name activated by {@link CSharpDevKitExports}. - */ -export function initializeBrokeredServicePipeName(csDevKitPipeName: string) { - _brokeredServicePipeName = csDevKitPipeName; -} - -/** - * Fetch the brokered service pipe name from C# dev kit, if available. - */ -export function getBrokeredServicePipeName(): string | undefined { - return _brokeredServicePipeName; -} diff --git a/src/coreclrDebug/provisionalDebugSessionTracker.ts b/src/coreclrDebug/provisionalDebugSessionTracker.ts new file mode 100644 index 000000000..28bf067bd --- /dev/null +++ b/src/coreclrDebug/provisionalDebugSessionTracker.ts @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +/** + * This tracks a debug session until C# dev kit is loaded (if present) and STOPS tracking any existing + * debug session after C# dev kit is loaded. + * The idea is to avoid a race condition if a debugging session starts before C# dev kit is initialized, + * since the brokered service pipe name will be sent with a 'launch' command. + * If the extension loads during an existing session, rather than not initializing any C# dev kit services (such as hot reload), + * this sends a custom request to the engine with the brokered service pipe name in order to initialize it. + */ +export class ProvisionalDebugSessionTracker { + private _sessions: Set | undefined = new Set(); + + private _onDidStartDebugSession: vscode.Disposable | undefined; + private _onDidTerminateDebugSession: vscode.Disposable | undefined; + + private _brokeredServicePipeName: string | undefined; + + /** + * Initializes the debug session handlers. + */ + initializeDebugSessionHandlers(context: vscode.ExtensionContext): void { + this._onDidStartDebugSession = vscode.debug.onDidStartDebugSession(this.onDidStartDebugSession.bind(this)); + + this._onDidTerminateDebugSession = vscode.debug.onDidTerminateDebugSession((session: vscode.DebugSession) => { + this.onDidTerminateDebugSession(session); + }); + + context.subscriptions.push(this._onDidStartDebugSession); + context.subscriptions.push(this._onDidTerminateDebugSession); + } + + /** + * Tracks a debug session until it is terminated. + * @param session Debug session. + */ + onDidStartDebugSession(session: vscode.DebugSession): void { + if (session.type !== 'coreclr') { + return; + } + + this._sessions?.add(session); + } + + /** + * Notifies that a debug session has been terminated. + */ + onDidTerminateDebugSession(session: vscode.DebugSession): void { + this._sessions?.delete(session); + } + + /** + * If there is any active debug session, this notifies the engine that csdevkit was loaded. + * @param csDevKitPipeName Brokered service pipe name activated by {@link CSharpDevKitExports}. + */ + async onCsDevKitInitialized(csDevKitPipeName: string): Promise { + this._brokeredServicePipeName = csDevKitPipeName; + + const sessions = this._sessions; + if (sessions != undefined) { + // Debugging session already started, send a custom DAP request to the engine. + sessions.forEach((s) => s.customRequest('initializeBrokeredServicePipeName', csDevKitPipeName)); + } + + // Since C# dev kit was initialized, we no longer need to track debugging sessions. + this.cleanup(); + } + + /** + * Fetches the brokered service pipe name from C# dev kit, if available. + */ + getBrokeredServicePipeName(): string | undefined { + return this._brokeredServicePipeName; + } + + /** + * No longer tracks any debugging session going forward. + */ + cleanup(): void { + this._sessions?.clear(); + this._sessions = undefined; + + this._onDidStartDebugSession?.dispose(); + this._onDidTerminateDebugSession?.dispose(); + } +} + +export const debugSessionTracker = new ProvisionalDebugSessionTracker(); diff --git a/src/main.ts b/src/main.ts index ec66c1673..e5f046716 100644 --- a/src/main.ts +++ b/src/main.ts @@ -57,6 +57,7 @@ import { ServerStateChange } from './lsptoolshost/serverStateChange'; import { SolutionSnapshotProvider } from './lsptoolshost/services/solutionSnapshotProvider'; import { RazorTelemetryDownloader } from './razor/razorTelemetryDownloader'; import { commonOptions, omnisharpOptions, razorOptions } from './shared/options'; +import { debugSessionTracker } from './coreclrDebug/provisionalDebugSessionTracker'; export async function activate( context: vscode.ExtensionContext @@ -335,6 +336,8 @@ export async function activate( reporter.sendTelemetryEvent('CSharpActivated', activationProperties); if (!useOmnisharpServer) { + debugSessionTracker.initializeDebugSessionHandlers(context); + tryGetCSharpDevKitExtensionExports(csharpLogObserver); // If we got here, the server should definitely have been created. @@ -401,9 +404,9 @@ function tryGetCSharpDevKitExtensionExports(csharpLogObserver: CsharpLoggerObser ]); // Notify the vsdbg configuration provider that C# dev kit has been loaded. - exports.serverProcessLoaded(async () => - coreclrdebug.initializeBrokeredServicePipeName(await exports.getBrokeredServiceServerPipeName()) - ); + exports.serverProcessLoaded(async () => { + debugSessionTracker.onCsDevKitInitialized(await exports.getBrokeredServiceServerPipeName()); + }); vscode.commands.executeCommand('setContext', 'dotnet.debug.serviceBrokerAvailable', true); } else { diff --git a/src/shared/configurationProvider.ts b/src/shared/configurationProvider.ts index e1ba91747..12b98581e 100644 --- a/src/shared/configurationProvider.ts +++ b/src/shared/configurationProvider.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import { ParsedEnvironmentFile } from '../coreclrDebug/parsedEnvironmentFile'; -import { getBrokeredServicePipeName } from '../coreclrDebug/activate'; +import { debugSessionTracker } from '../coreclrDebug/provisionalDebugSessionTracker'; import { MessageItem } from '../vscodeAdapter'; import { CertToolStatusCodes, createSelfSignedCert, hasDotnetDevCertsHttps } from '../utils/dotnetDevCertsHttps'; @@ -66,7 +66,7 @@ export class BaseVsDbgConfigurationProvider implements vscode.DebugConfiguration return null; } - const brokeredServicePipeName = getBrokeredServicePipeName(); + const brokeredServicePipeName = debugSessionTracker.getBrokeredServicePipeName(); if (brokeredServicePipeName !== undefined) { debugConfiguration.brokeredServicePipeName = brokeredServicePipeName; }