Skip to content

Commit

Permalink
Track debugging sessions until csdevkit is initialized (#6480)
Browse files Browse the repository at this point in the history
* Track debugging sessions until csdevkit is initialized.

* Address code review suggestions.

* Use the session parameter to untrack a session.

---------

Co-authored-by: Isadora Rodopoulos <[email protected]>
  • Loading branch information
isadorasophia and Isadora Rodopoulos authored Oct 11, 2023
1 parent 9f97603 commit e91e3f0
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 23 deletions.
18 changes: 0 additions & 18 deletions src/coreclrDebug/activate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
93 changes: 93 additions & 0 deletions src/coreclrDebug/provisionalDebugSessionTracker.ts
Original file line number Diff line number Diff line change
@@ -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<vscode.DebugSession> | undefined = new Set<vscode.DebugSession>();

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<void> {
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();
9 changes: 6 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/shared/configurationProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit e91e3f0

Please sign in to comment.