Skip to content

Commit b7eec61

Browse files
committed
Initialisation state and token should not be shared across sessions
microsoft#91969
1 parent 6931839 commit b7eec61

5 files changed

Lines changed: 47 additions & 30 deletions

File tree

src/vs/workbench/contrib/debug/browser/debugService.ts

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
4646
import { TaskRunResult, DebugTaskRunner } from 'vs/workbench/contrib/debug/browser/debugTaskRunner';
4747
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
4848
import { IViewsService } from 'vs/workbench/common/views';
49+
import { generateUuid } from 'vs/base/common/uuid';
4950

5051
const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
5152
const DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint';
@@ -73,7 +74,7 @@ export class DebugService implements IDebugService {
7374
private breakpointsToSendOnResourceSaved: Set<string>;
7475
private initializing = false;
7576
private previousState: State | undefined;
76-
private initCancellationToken: CancellationTokenSource | undefined;
77+
private sessionCancellationTokens = new Map<string, CancellationTokenSource>();
7778
private activity: IDisposable | undefined;
7879

7980
constructor(
@@ -206,24 +207,33 @@ export class DebugService implements IDebugService {
206207
return this.initializing ? State.Initializing : State.Inactive;
207208
}
208209

209-
private startInitializingState() {
210+
private startInitializingState(): void {
210211
if (!this.initializing) {
211212
this.initializing = true;
212213
this.onStateChange();
213214
}
214215
}
215216

216-
private endInitializingState() {
217-
if (this.initCancellationToken) {
218-
this.initCancellationToken.cancel();
219-
this.initCancellationToken = undefined;
220-
}
217+
private endInitializingState(): void {
221218
if (this.initializing) {
222219
this.initializing = false;
223220
this.onStateChange();
224221
}
225222
}
226223

224+
private cancelTokens(id: string | undefined): void {
225+
if (id) {
226+
const token = this.sessionCancellationTokens.get(id);
227+
if (token) {
228+
token.cancel();
229+
this.sessionCancellationTokens.delete(id);
230+
}
231+
} else {
232+
this.sessionCancellationTokens.forEach(t => t.cancel());
233+
this.sessionCancellationTokens.clear();
234+
}
235+
}
236+
227237
private onStateChange(): void {
228238
const state = this.state;
229239
if (this.previousState !== state) {
@@ -380,8 +390,11 @@ export class DebugService implements IDebugService {
380390
}
381391
}
382392

383-
this.initCancellationToken = new CancellationTokenSource();
384-
const configByProviders = await this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, this.initCancellationToken.token);
393+
const initCancellationToken = new CancellationTokenSource();
394+
const sessionId = generateUuid();
395+
this.sessionCancellationTokens.set(sessionId, initCancellationToken);
396+
397+
const configByProviders = await this.configurationManager.resolveConfigurationByProviders(launch && launch.workspace ? launch.workspace.uri : undefined, type, config!, initCancellationToken.token);
385398
// a falsy config indicates an aborted launch
386399
if (configByProviders && configByProviders.type) {
387400
try {
@@ -391,15 +404,15 @@ export class DebugService implements IDebugService {
391404
return false;
392405
}
393406

394-
if (!this.initCancellationToken) {
407+
if (initCancellationToken.token.isCancellationRequested) {
395408
// User cancelled, silently return
396409
return false;
397410
}
398411

399-
const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, type, resolvedConfig, this.initCancellationToken.token);
412+
const cfg = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, type, resolvedConfig, initCancellationToken.token);
400413
if (!cfg) {
401-
if (launch && type && cfg === null && this.initCancellationToken) { // show launch.json only for "config" being "null".
402-
await launch.openConfigFile(false, true, type, this.initCancellationToken.token);
414+
if (launch && type && cfg === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null".
415+
await launch.openConfigFile(false, true, type, initCancellationToken.token);
403416
}
404417
return false;
405418
}
@@ -423,7 +436,7 @@ export class DebugService implements IDebugService {
423436
const workspace = launch?.workspace || this.contextService.getWorkspace();
424437
const taskResult = await this.taskRunner.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask, (msg, actions) => this.showError(msg, actions));
425438
if (taskResult === TaskRunResult.Success) {
426-
return this.doCreateSession(launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options);
439+
return this.doCreateSession(sessionId, launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options);
427440
}
428441
return false;
429442
} catch (err) {
@@ -432,16 +445,16 @@ export class DebugService implements IDebugService {
432445
} else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
433446
await this.showError(nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved and that you have a debug extension installed for that file type."));
434447
}
435-
if (launch && this.initCancellationToken) {
436-
await launch.openConfigFile(false, true, undefined, this.initCancellationToken.token);
448+
if (launch && !initCancellationToken.token.isCancellationRequested) {
449+
await launch.openConfigFile(false, true, undefined, initCancellationToken.token);
437450
}
438451

439452
return false;
440453
}
441454
}
442455

443-
if (launch && type && configByProviders === null && this.initCancellationToken) { // show launch.json only for "config" being "null".
444-
await launch.openConfigFile(false, true, type, this.initCancellationToken.token);
456+
if (launch && type && configByProviders === null && !initCancellationToken.token.isCancellationRequested) { // show launch.json only for "config" being "null".
457+
await launch.openConfigFile(false, true, type, initCancellationToken.token);
445458
}
446459

447460
return false;
@@ -450,9 +463,9 @@ export class DebugService implements IDebugService {
450463
/**
451464
* instantiates the new session, initializes the session, registers session listeners and reports telemetry
452465
*/
453-
private async doCreateSession(root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, options?: IDebugSessionOptions): Promise<boolean> {
466+
private async doCreateSession(sessionId: string, root: IWorkspaceFolder | undefined, configuration: { resolved: IConfig, unresolved: IConfig | undefined }, options?: IDebugSessionOptions): Promise<boolean> {
454467

455-
const session = this.instantiationService.createInstance(DebugSession, configuration, root, this.model, options);
468+
const session = this.instantiationService.createInstance(DebugSession, sessionId, configuration, root, this.model, options);
456469
this.model.addSession(session);
457470
// register listeners as the very first thing!
458471
this.registerSessionListeners(session);
@@ -566,6 +579,7 @@ export class DebugService implements IDebugService {
566579
}
567580
}
568581
this.endInitializingState();
582+
this.cancelTokens(session.getId());
569583
this._onDidEndSession.fire(session);
570584

571585
const focusedSession = this.viewModel.focusedSession;
@@ -656,12 +670,13 @@ export class DebugService implements IDebugService {
656670

657671
let resolved: IConfig | undefined | null = session.configuration;
658672
if (launch && needsToSubstitute && unresolved) {
659-
this.initCancellationToken = new CancellationTokenSource();
660-
const resolvedByProviders = await this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, this.initCancellationToken.token);
673+
const initCancellationToken = new CancellationTokenSource();
674+
this.sessionCancellationTokens.set(session.getId(), initCancellationToken);
675+
const resolvedByProviders = await this.configurationManager.resolveConfigurationByProviders(launch.workspace ? launch.workspace.uri : undefined, unresolved.type, unresolved, initCancellationToken.token);
661676
if (resolvedByProviders) {
662677
resolved = await this.substituteVariables(launch, resolvedByProviders);
663-
if (resolved && this.initCancellationToken) {
664-
resolved = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, unresolved.type, resolved, this.initCancellationToken.token);
678+
if (resolved && !initCancellationToken.token.isCancellationRequested) {
679+
resolved = await this.configurationManager.resolveDebugConfigurationWithSubstitutedVariables(launch && launch.workspace ? launch.workspace.uri : undefined, unresolved.type, resolved, initCancellationToken.token);
665680
}
666681
} else {
667682
resolved = resolvedByProviders;
@@ -695,6 +710,7 @@ export class DebugService implements IDebugService {
695710
if (sessions.length === 0) {
696711
this.taskRunner.cancel();
697712
this.endInitializingState();
713+
this.cancelTokens(undefined);
698714
}
699715

700716
return Promise.all(sessions.map(s => s.terminate()));

src/vs/workbench/contrib/debug/browser/debugSession.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
3737

3838
export class DebugSession implements IDebugSession {
3939

40-
private id: string;
4140
private _subId: string | undefined;
4241
private raw: RawDebugSession | undefined;
4342
private initialized = false;
@@ -62,6 +61,7 @@ export class DebugSession implements IDebugSession {
6261
private readonly _onDidChangeName = new Emitter<string>();
6362

6463
constructor(
64+
private id: string,
6565
private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
6666
public root: IWorkspaceFolder | undefined,
6767
private model: DebugModel,
@@ -78,7 +78,6 @@ export class DebugSession implements IDebugSession {
7878
@INotificationService private readonly notificationService: INotificationService,
7979
@ILifecycleService lifecycleService: ILifecycleService
8080
) {
81-
this.id = generateUuid();
8281
this._options = options || {};
8382
if (this.hasSeparateRepl()) {
8483
this.repl = new ReplModel();

src/vs/workbench/contrib/debug/test/browser/breakpoints.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ import { createBreakpointDecorations } from 'vs/workbench/contrib/debug/browser/
1818
import { OverviewRulerLane } from 'vs/editor/common/model';
1919
import { MarkdownString } from 'vs/base/common/htmlContent';
2020
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
21+
import { generateUuid } from 'vs/base/common/uuid';
2122

2223
function createMockSession(model: DebugModel, name = 'mockSession', options?: IDebugSessionOptions): DebugSession {
23-
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
24+
return new DebugSession(generateUuid(), { resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
2425
}
2526

2627
function addBreakpointsAndCheckEvents(model: DebugModel, uri: uri, data: IBreakpointData[]): void {

src/vs/workbench/contrib/debug/test/browser/callStack.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import { createDecorationsForStackFrame } from 'vs/workbench/contrib/debug/brows
1616
import { Constants } from 'vs/base/common/uint';
1717
import { getContext, getContextForContributedActions } from 'vs/workbench/contrib/debug/browser/callStackView';
1818
import { getStackFrameThreadAndSessionToFocus } from 'vs/workbench/contrib/debug/browser/debugService';
19+
import { generateUuid } from 'vs/base/common/uuid';
1920

2021
export function createMockSession(model: DebugModel, name = 'mockSession', options?: IDebugSessionOptions): DebugSession {
21-
return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
22+
return new DebugSession(generateUuid(), { resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, options, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
2223
}
2324

2425
function createTwoStackFrames(session: DebugSession): { firstStackFrame: StackFrame, secondStackFrame: StackFrame } {
@@ -363,7 +364,7 @@ suite('Debug - CallStack', () => {
363364
get state(): State {
364365
return State.Stopped;
365366
}
366-
}({ resolved: { name: 'stoppedSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
367+
}(generateUuid(), { resolved: { name: 'stoppedSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
367368

368369
const runningSession = createMockSession(model);
369370
model.addSession(runningSession);

src/vs/workbench/contrib/debug/test/electron-browser/debugANSIHandling.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ suite('Debug - ANSI Handling', () => {
3030
*/
3131
setup(() => {
3232
model = new DebugModel([], [], [], [], [], <any>{ isDirty: (e: any) => false });
33-
session = new DebugSession({ resolved: { name: 'test', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
33+
session = new DebugSession(generateUuid(), { resolved: { name: 'test', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, NullOpenerService, undefined!, undefined!);
3434

3535
const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService();
3636
linkDetector = instantiationService.createInstance(LinkDetector);

0 commit comments

Comments
 (0)