mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 18:49:37 +00:00
[dds/dap] Handle some additional error causes when resuming isolates
Fixes https://github.com/flutter/flutter/issues/125064. Change-Id: I521fe29d0f269694dc6c2b993d1e400c495b0605 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/296560 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
493f36690f
commit
facfcf0f92
|
@ -1,3 +1,6 @@
|
|||
# 2.7.9
|
||||
- [DAP] Configuring and resuming isolates will no longer cause a crash if the isolate exits before the request is processed.
|
||||
|
||||
# 2.7.8
|
||||
- [DAP] Sentinel values (such as uninitialized fields/locals) will no longer cause `scopesRequest`/`variablesRequest` to fail, instead showing appropriate text (like "<not initialized>") against the variable.
|
||||
|
||||
|
|
|
@ -279,6 +279,17 @@ class IsolateManager {
|
|||
thread.hasPendingResume = true;
|
||||
try {
|
||||
await _adapter.vmService?.resume(thread.isolate.id!, step: resumeType);
|
||||
} on vm.SentinelException {
|
||||
// It's possible during these async requests that the isolate went away
|
||||
// (for example a shutdown/restart) and we no longer care about
|
||||
// resuming it.
|
||||
} on vm.RPCError catch (e) {
|
||||
if (e.code == RpcErrorCodes.kIsolateMustBePaused) {
|
||||
// It's possible something else resumed the thread (such as if another
|
||||
// debugger is attached), we can just continue.
|
||||
} else {
|
||||
rethrow;
|
||||
}
|
||||
} finally {
|
||||
thread.hasPendingResume = false;
|
||||
}
|
||||
|
@ -612,13 +623,19 @@ class IsolateManager {
|
|||
) async {
|
||||
final isolateId = isolate.id!;
|
||||
final uriStrings = uris.map((uri) => uri.toString()).toList();
|
||||
final res = await _adapter.vmService
|
||||
?.lookupResolvedPackageUris(isolateId, uriStrings, local: true);
|
||||
try {
|
||||
final res = await _adapter.vmService
|
||||
?.lookupResolvedPackageUris(isolateId, uriStrings, local: true);
|
||||
|
||||
return res?.uris
|
||||
?.cast<String?>()
|
||||
.map((uri) => uri != null ? Uri.parse(uri) : null)
|
||||
.toList();
|
||||
return res?.uris
|
||||
?.cast<String?>()
|
||||
.map((uri) => uri != null ? Uri.parse(uri) : null)
|
||||
.toList();
|
||||
} on vm.SentinelException {
|
||||
// If the isolate disappeared before we sent this request, just return
|
||||
// null responses.
|
||||
return uris.map((e) => null).toList();
|
||||
}
|
||||
}
|
||||
|
||||
/// Interpolates and prints messages for any log points.
|
||||
|
|
|
@ -31,7 +31,7 @@ abstract class RpcErrorCodes {
|
|||
static const kStreamNotSubscribed = 104;
|
||||
|
||||
// static const kIsolateMustBeRunnable = 105;
|
||||
// static const kIsolateMustBePaused = 106;
|
||||
static const kIsolateMustBePaused = 106;
|
||||
// static const kCannotResume = 107;
|
||||
// static const kIsolateIsReloading = 108;
|
||||
// static const kIsolateReloadBarred = 109;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: dds
|
||||
version: 2.7.8
|
||||
version: 2.7.9
|
||||
description: >-
|
||||
A library used to spawn the Dart Developer Service, used to communicate with
|
||||
a Dart VM Service instance.
|
||||
|
|
|
@ -533,6 +533,41 @@ void main(List<String> args) async {
|
|||
client.stepIn(stop.threadId!),
|
||||
], eagerError: true);
|
||||
});
|
||||
|
||||
test('does not fail if two debug clients resume the same thread', () async {
|
||||
final testFile = dap.createTestFile(infiniteRunningProgram);
|
||||
final breakpointLine = lineWith(testFile, breakpointMarker);
|
||||
|
||||
// Start a program and hit a breakpoint.
|
||||
final client1 = dap.client;
|
||||
final stop1 = await client1.hitBreakpoint(testFile, breakpointLine);
|
||||
final vmServiceUri = (await client1.vmServiceUri)!;
|
||||
final thread1 = stop1.threadId!;
|
||||
|
||||
// Attach a second debug adapter to it.
|
||||
final dap2 = await DapTestSession.setUp();
|
||||
final client2 = dap2.client;
|
||||
await Future.wait([
|
||||
// We'll still get event for existing pause.
|
||||
client2.expectStop('breakpoint'),
|
||||
client2.start(
|
||||
launch: () => client2.attach(
|
||||
vmServiceUri: vmServiceUri.toString(),
|
||||
autoResume: false,
|
||||
cwd: dap.testAppDir.path,
|
||||
),
|
||||
),
|
||||
]);
|
||||
final thread2 = (await client2.getValidThreads()).threads.single.id;
|
||||
|
||||
// Send resumes to both and ensure they complete without errors.
|
||||
await Future.wait([
|
||||
client1.continue_(thread1),
|
||||
client2.continue_(thread2),
|
||||
], eagerError: true);
|
||||
|
||||
await dap2.tearDown();
|
||||
});
|
||||
}, timeout: Timeout.none);
|
||||
|
||||
group('debug mode conditional breakpoints', () {
|
||||
|
|
|
@ -91,6 +91,19 @@ String stringPrintingProgram(String text) {
|
|||
''';
|
||||
}
|
||||
|
||||
/// A simple Dart script that just loops forever sleeping for 1 second each
|
||||
/// iteration.
|
||||
///
|
||||
/// A breakpoint marker is included before the loop.
|
||||
const infiniteRunningProgram = '''
|
||||
void main(List<String> args) async {
|
||||
print('Looping'); $breakpointMarker
|
||||
while (true) {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
}
|
||||
}
|
||||
''';
|
||||
|
||||
/// A simple async Dart script that when stopped at the line of '// BREAKPOINT'
|
||||
/// will contain multiple stack frames across some async boundaries.
|
||||
const simpleAsyncProgram = '''
|
||||
|
|
Loading…
Reference in a new issue