From b42cf8c24acfc9539bab8ae48685cbe4d0911511 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 18 Oct 2016 09:41:54 +0200 Subject: [PATCH] debug: move notion of session from debug service --- src/vs/workbench/parts/debug/common/debug.ts | 8 +++ .../parts/debug/common/debugModel.ts | 66 ++++++++++++------- .../parts/debug/common/debugViewModel.ts | 8 ++- .../debug/electron-browser/debugService.ts | 39 ++++++----- .../debug/test/common/debugViewModel.test.ts | 2 +- .../parts/debug/test/node/debugModel.test.ts | 7 ++ 6 files changed, 85 insertions(+), 45 deletions(-) diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 03ec260c304..6af45e9577d 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -31,6 +31,7 @@ export const DEBUG_SCHEME = 'debug'; export interface IRawModelUpdate { threadId: number; + sessionId: string; thread?: DebugProtocol.Thread; callStack?: DebugProtocol.StackFrame[]; stoppedDetails?: IRawStoppedDetails; @@ -64,6 +65,12 @@ export interface IExpression extends ITreeElement, IExpressionContainer { } export interface IThread extends ITreeElement { + + /** + * Id of the debug session the thread belongs to + */ + sessionId: string; + /** * Id of the thread generated by the debug adapter backend. */ @@ -159,6 +166,7 @@ export interface IExceptionBreakpoint extends IEnablement { // model interfaces export interface IViewModel extends ITreeElement { + activeSession: IRawDebugSession; getFocusedStackFrame(): IStackFrame; getSelectedExpression(): IExpression; getFocusedThreadId(): number; diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 27399ca2cca..ab8bb03ba81 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -89,7 +89,7 @@ export class Thread implements debug.IThread { public stoppedDetails: debug.IRawStoppedDetails; public stopped: boolean; - constructor(public name: string, public threadId: number) { + constructor(public sessionId: string, public name: string, public threadId: number) { this.promisedCallStack = undefined; this.stoppedDetails = undefined; this.cachedCallStack = undefined; @@ -97,7 +97,7 @@ export class Thread implements debug.IThread { } public getId(): string { - return `thread:${this.name}:${this.threadId}`; + return `thread:${this.sessionId}:${this.name}:${this.threadId}`; } public clearCallStack(): void { @@ -255,30 +255,31 @@ export abstract class ExpressionContainer implements debug.IExpressionContainer } else { // Check if object has named variables, fetch them independent from indexed variables #9670 - this.children = (!!this.namedVariables ? this.fetchVariables(session, undefined, undefined, 'named') : TPromise.as([])).then(childrenArray => { - // Use a dynamic chunk size based on the number of elements #9774 - let chunkSize = ExpressionContainer.BASE_CHUNK_SIZE; - while (this.indexedVariables > chunkSize * ExpressionContainer.BASE_CHUNK_SIZE) { - chunkSize *= ExpressionContainer.BASE_CHUNK_SIZE; - } - - if (this.indexedVariables > chunkSize) { - // There are a lot of children, create fake intermediate values that represent chunks #9537 - const numberOfChunks = Math.ceil(this.indexedVariables / chunkSize); - for (let i = 0; i < numberOfChunks; i++) { - const start = this.startOfVariables + i * chunkSize; - const count = Math.min(chunkSize, this.indexedVariables - i * chunkSize); - childrenArray.push(new Variable(this, this.reference, `[${start}..${start + count - 1}]`, '', null, count, null, true, start)); + this.children = (!!this.namedVariables ? this.fetchVariables(session, undefined, undefined, 'named') + : TPromise.as([])).then(childrenArray => { + // Use a dynamic chunk size based on the number of elements #9774 + let chunkSize = ExpressionContainer.BASE_CHUNK_SIZE; + while (this.indexedVariables > chunkSize * ExpressionContainer.BASE_CHUNK_SIZE) { + chunkSize *= ExpressionContainer.BASE_CHUNK_SIZE; } - return childrenArray; - } + if (this.indexedVariables > chunkSize) { + // There are a lot of children, create fake intermediate values that represent chunks #9537 + const numberOfChunks = Math.ceil(this.indexedVariables / chunkSize); + for (let i = 0; i < numberOfChunks; i++) { + const start = this.startOfVariables + i * chunkSize; + const count = Math.min(chunkSize, this.indexedVariables - i * chunkSize); + childrenArray.push(new Variable(this, this.reference, `[${start}..${start + count - 1}]`, '', null, count, null, true, start)); + } - const start = this.getChildrenInChunks ? this.startOfVariables : undefined; - const count = this.getChildrenInChunks ? this.indexedVariables : undefined; - return this.fetchVariables(session, start, count, 'indexed') - .then(variables => arrays.distinct(childrenArray.concat(variables), child => child.name)); - }); + return childrenArray; + } + + const start = this.getChildrenInChunks ? this.startOfVariables : undefined; + const count = this.getChildrenInChunks ? this.indexedVariables : undefined; + return this.fetchVariables(session, start, count, 'indexed') + .then(variables => arrays.distinct(childrenArray.concat(variables), child => child.name)); + }); } } @@ -455,8 +456,13 @@ export class ExceptionBreakpoint implements debug.IExceptionBreakpoint { } } +class DebugSession { + constructor(public id: string, public raw: debug.IRawDebugSession, public threads: { [reference: number]: debug.IThread; }) { } +} + export class Model implements debug.IModel { + private sessions: DebugSession[]; private threads: { [reference: number]: debug.IThread; }; private toDispose: lifecycle.IDisposable[]; private replElements: debug.ITreeElement[]; @@ -472,9 +478,10 @@ export class Model implements debug.IModel { private exceptionBreakpoints: debug.IExceptionBreakpoint[], private watchExpressions: Expression[] ) { - this.threads = {}; + this.sessions = []; this.replElements = []; this.toDispose = []; + this.threads = {}; this._onDidChangeBreakpoints = new Emitter(); this._onDidChangeCallStack = new Emitter(); this._onDidChangeWatchExpressions = new Emitter(); @@ -485,6 +492,15 @@ export class Model implements debug.IModel { return 'root'; } + public getSession(id: string): debug.IRawDebugSession { + return this.sessions.filter(s => s.id === id).map(s => s.raw).pop(); + } + + public removeSession(id: string): void { + this.sessions = this.sessions.filter(s => s.id !== id); + this._onDidChangeCallStack.fire(); + } + public get onDidChangeBreakpoints(): Event { return this._onDidChangeBreakpoints.event; } @@ -787,7 +803,7 @@ export class Model implements debug.IModel { public rawUpdate(data: debug.IRawModelUpdate): void { if (data.thread && !this.threads[data.threadId]) { // A new thread came in, initialize it. - this.threads[data.threadId] = new Thread(data.thread.name, data.thread.id); + this.threads[data.threadId] = new Thread(data.sessionId, data.thread.name, data.thread.id); } if (data.stoppedDetails) { diff --git a/src/vs/workbench/parts/debug/common/debugViewModel.ts b/src/vs/workbench/parts/debug/common/debugViewModel.ts index 5de4b50287f..2a76fdc68f6 100644 --- a/src/vs/workbench/parts/debug/common/debugViewModel.ts +++ b/src/vs/workbench/parts/debug/common/debugViewModel.ts @@ -12,6 +12,7 @@ export class ViewModel implements debug.IViewModel { private focusedThread: debug.IThread; private selectedExpression: debug.IExpression; private selectedFunctionBreakpoint: debug.IFunctionBreakpoint; + private _activeSession: debug.IRawDebugSession; private _onDidFocusStackFrame: Emitter; private _onDidSelectExpression: Emitter; private _onDidSelectFunctionBreakpoint: Emitter; @@ -28,13 +29,18 @@ export class ViewModel implements debug.IViewModel { return 'root'; } + public get activeSession(): debug.IRawDebugSession { + return this._activeSession; + } + public getFocusedStackFrame(): debug.IStackFrame { return this.focusedStackFrame; } - public setFocusedStackFrame(focusedStackFrame: debug.IStackFrame, focusedThread: debug.IThread): void { + public setFocusedStackFrame(focusedStackFrame: debug.IStackFrame, focusedThread: debug.IThread, activeSession: debug.IRawDebugSession): void { this.focusedStackFrame = focusedStackFrame; this.focusedThread = focusedThread; + this._activeSession = activeSession; this._onDidFocusStackFrame.fire(focusedStackFrame); } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index ebdc236558e..294ae5e6a8b 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -154,7 +154,7 @@ export class DebugService implements debug.IDebugService { } if (broadcast.channel === EXTENSION_TERMINATE_BROADCAST_CHANNEL) { - this.onSessionEnd(); + this.onSessionEnd(this.session); return; } @@ -259,8 +259,9 @@ export class DebugService implements debug.IDebugService { this.setStateAndEmit(debug.State.Stopped); const threadId = event.body.threadId; - this.getThreadData().done(() => { + this.getThreadData(session).done(() => { this.model.rawUpdate({ + sessionId: session.getId(), threadId, stoppedDetails: event.body, allThreadsStopped: event.body.allThreadsStopped @@ -285,7 +286,7 @@ export class DebugService implements debug.IDebugService { this.toDisposeOnSessionEnd.push(session.onDidThread(event => { if (event.body.reason === 'started') { - this.getThreadData().done(null, errors.onUnexpectedError); + this.getThreadData(session).done(null, errors.onUnexpectedError); } else if (event.body.reason === 'exited') { this.model.clearThreads(true, event.body.threadId); } @@ -337,7 +338,7 @@ export class DebugService implements debug.IDebugService { ipc.send('vscode:closeExtensionHostWindow', this.contextService.getWorkspace().resource.fsPath); } if (session && session.getId() === event.body.sessionId) { - this.onSessionEnd(); + this.onSessionEnd(session); } })); } @@ -347,10 +348,10 @@ export class DebugService implements debug.IDebugService { this.appendReplOutput(event.body.output, outputSeverity); } - private getThreadData(): TPromise { - return this.session.threads().then(response => { + private getThreadData(session: RawDebugSession): TPromise { + return session.threads().then(response => { if (response && response.body && response.body.threads) { - response.body.threads.forEach(thread => this.model.rawUpdate({ threadId: thread.id, thread })); + response.body.threads.forEach(thread => this.model.rawUpdate({ sessionId: session.getId(), threadId: thread.id, thread })); } }); } @@ -421,8 +422,9 @@ export class DebugService implements debug.IDebugService { if (!thread && focusedStackFrame) { thread = this.model.getThreads()[focusedStackFrame.threadId]; } + const session = this.model.getSession(thread.sessionId); - this.viewModel.setFocusedStackFrame(focusedStackFrame, thread); + this.viewModel.setFocusedStackFrame(focusedStackFrame, thread, session); if (focusedStackFrame) { return this.model.evaluateWatchExpressions(this.session, focusedStackFrame); } else { @@ -628,10 +630,11 @@ export class DebugService implements debug.IDebugService { this.customTelemetryService = new TelemetryService({ appender }, this.configurationService); } - this.session = this.instantiationService.createInstance(RawDebugSession, configuration.debugServer, this.configurationManager.adapter, this.customTelemetryService); - this.registerSessionListeners(this.session); + const session = this.instantiationService.createInstance(RawDebugSession, configuration.debugServer, this.configurationManager.adapter, this.customTelemetryService); + this.session = session; + this.registerSessionListeners(session); - return this.session.initialize({ + return session.initialize({ adapterID: configuration.type, pathFormat: 'path', linesStartAt1: true, @@ -644,8 +647,8 @@ export class DebugService implements debug.IDebugService { return TPromise.wrapError(new Error(nls.localize('debugAdapterCrash', "Debug adapter process has terminated unexpectedly"))); } - this.model.setExceptionBreakpoints(this.session.configuration.capabilities.exceptionBreakpointFilters); - return configuration.request === 'attach' ? this.session.attach(configuration) : this.session.launch(configuration); + this.model.setExceptionBreakpoints(session.configuration.capabilities.exceptionBreakpointFilters); + return configuration.request === 'attach' ? session.attach(configuration) : session.launch(configuration); }).then((result: DebugProtocol.Response) => { if (!this.session) { return TPromise.as(null); @@ -775,13 +778,13 @@ export class DebugService implements debug.IDebugService { return this.session; } - private onSessionEnd(): void { - if (this.session) { + private onSessionEnd(session: RawDebugSession): void { + if (session) { const bpsExist = this.model.getBreakpoints().length > 0; this.telemetryService.publicLog('debugSessionStop', { - type: this.session.configuration.type, - success: this.session.emittedStopped || !bpsExist, - sessionLengthInSeconds: this.session.getLengthInSeconds(), + type: session.configuration.type, + success: session.emittedStopped || !bpsExist, + sessionLengthInSeconds: session.getLengthInSeconds(), breakpointCount: this.model.getBreakpoints().length, watchExpressionsCount: this.model.getWatchExpressions().length }); diff --git a/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts b/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts index 9f961b9db3e..82d00af7a9e 100644 --- a/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts +++ b/src/vs/workbench/parts/debug/test/common/debugViewModel.test.ts @@ -22,7 +22,7 @@ suite('Debug - View Model', () => { assert.equal(model.getFocusedStackFrame(), null); assert.equal(model.getFocusedThreadId(), 0); const frame = new StackFrame(1, 1, null, 'app.js', 1, 1); - model.setFocusedStackFrame(frame, new Thread('myThread', 1)); + model.setFocusedStackFrame(frame, new Thread('sessionid', 'myThread', 1), null); assert.equal(model.getFocusedStackFrame(), frame); assert.equal(model.getFocusedThreadId(), 1); diff --git a/src/vs/workbench/parts/debug/test/node/debugModel.test.ts b/src/vs/workbench/parts/debug/test/node/debugModel.test.ts index 79a60afcda1..b8d2cb96eed 100644 --- a/src/vs/workbench/parts/debug/test/node/debugModel.test.ts +++ b/src/vs/workbench/parts/debug/test/node/debugModel.test.ts @@ -79,6 +79,7 @@ suite('Debug - Model', () => { var threadId = 1; var threadName = 'firstThread'; model.rawUpdate({ + sessionId: 'sessionid', threadId: threadId, thread: { id: threadId, @@ -105,6 +106,7 @@ suite('Debug - Model', () => { // Add the threads model.rawUpdate({ + sessionId: 'sessionid', threadId: threadId1, thread: { id: threadId1, @@ -113,6 +115,7 @@ suite('Debug - Model', () => { }); model.rawUpdate({ + sessionId: 'sessionid', threadId: threadId2, thread: { id: threadId2, @@ -122,6 +125,7 @@ suite('Debug - Model', () => { // Stopped event with all threads stopped model.rawUpdate({ + sessionId: 'sessionid', threadId: threadId1, stoppedDetails: { reason: stoppedReason, @@ -191,6 +195,7 @@ suite('Debug - Model', () => { // Add the threads model.rawUpdate({ + sessionId: 'sessionid', threadId: stoppedThreadId, thread: { id: stoppedThreadId, @@ -199,6 +204,7 @@ suite('Debug - Model', () => { }); model.rawUpdate({ + sessionId: 'sessionid', threadId: runningThreadId, thread: { id: runningThreadId, @@ -208,6 +214,7 @@ suite('Debug - Model', () => { // Stopped event with only one thread stopped model.rawUpdate({ + sessionId: 'sessionid', threadId: stoppedThreadId, stoppedDetails: { reason: stoppedReason, -- GitLab