Skip to content

Commit 1534912

Browse files
committed
src/goDebug: check if delve exited before attempting to get state
There is an initial ThreadsRequest after initialization from vscode. If the program exits too quickly, this request may come after delve has already exited. There is already a check to ignore an error from ListGoRoutines if the debugState.exited. This change adds the same check to threadsRequest before isDebuggeeRunning is called, which tries to get the debugState from delve. Updates #1113 Change-Id: I01b1f2af9d7357c2363709b94435b797aa042459 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/286492 Trust: Suzy Mueller <[email protected]> Run-TryBot: Suzy Mueller <[email protected]> Reviewed-by: Polina Sokolova <[email protected]>
1 parent 5f88d61 commit 1534912

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

src/debugAdapter/goDebug.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,11 @@ export class GoDebugSession extends LoggingDebugSession {
13631363
// Thread request to delve is synchronous and will block if a previous async continue request didn't return
13641364
response.body = { threads: [new Thread(1, 'Dummy')] };
13651365
return this.sendResponse(response);
1366+
} else if (this.debugState && this.debugState.exited) {
1367+
// If the program exits very quickly, the initial threadsRequest will complete after it has exited.
1368+
// A TerminatedEvent has already been sent. d
1369+
response.body = { threads: [] };
1370+
return this.sendResponse(response);
13661371
}
13671372
log('ThreadsRequest');
13681373
this.delve.call<DebugGoroutine[] | ListGoroutinesOut>('ListGoroutines', [], (err, out) => {
@@ -2429,6 +2434,9 @@ export class GoDebugSession extends LoggingDebugSession {
24292434
// instead of issuing a getDebugState call to Delve. Perhaps we want to
24302435
// do that to improve performance in the future.
24312436
private async isDebuggeeRunning(): Promise<boolean> {
2437+
if (this.debugState && this.debugState.exited) {
2438+
return false;
2439+
}
24322440
try {
24332441
this.debugState = await this.delve.getDebugState();
24342442
return this.debugState.Running;

test/integration/goDebug.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,53 @@ suite('Go Debug Adapter', function () {
592592
]);
593593
});
594594

595+
test('should handle threads request after initialization', async () => {
596+
const PROGRAM = path.join(DATA_ROOT, 'baseTest');
597+
598+
const config = {
599+
name: 'Launch',
600+
type: 'go',
601+
request: 'launch',
602+
mode: 'auto',
603+
program: PROGRAM,
604+
};
605+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
606+
607+
return Promise.all([
608+
dc.configurationSequence().then(() => {
609+
dc.threadsRequest().then((response) => {
610+
assert.ok(response.success);
611+
});
612+
}),
613+
dc.launch(debugConfig),
614+
dc.waitForEvent('terminated'),
615+
]);
616+
});
617+
618+
test('should handle delayed initial threads request', async () => {
619+
// If the program exits very quickly, the initial threadsRequest
620+
// will complete after it has exited.
621+
const PROGRAM = path.join(DATA_ROOT, 'baseTest');
622+
623+
const config = {
624+
name: 'Launch',
625+
type: 'go',
626+
request: 'launch',
627+
mode: 'auto',
628+
program: PROGRAM,
629+
};
630+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
631+
632+
await Promise.all([
633+
dc.configurationSequence(),
634+
dc.launch(debugConfig),
635+
dc.waitForEvent('terminated')
636+
]);
637+
638+
const response = await dc.threadsRequest();
639+
assert.ok(response.success);
640+
});
641+
595642
test('user-specified --listen flag should be ignored', () => {
596643
const PROGRAM = path.join(DATA_ROOT, 'baseTest');
597644
const config = {

0 commit comments

Comments
 (0)