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

Track debugging sessions until csdevkit is initialized #6480

Merged
merged 3 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
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
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