Skip to content

Commit

Permalink
[dds/dap] Include Isolate IDs in Threads when used over DDS
Browse files Browse the repository at this point in the history
See #53086

Change-Id: I380744f9e0d604168f026684b31fe689bb8947c8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317701
Reviewed-by: Ben Konyi <[email protected]>
  • Loading branch information
DanTup authored and bkonyi committed Aug 21, 2023
1 parent eda6963 commit 45d06f2
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 1 deletion.
1 change: 1 addition & 0 deletions pkg/dds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 2.9.5
- [DAP] The change to use VM Service Isolate numbers for `threadId`s has been reverted because Isolate numbers can be larger than the 32-bit integers allowed in DAP.
- [DAP] Threads returned from `threadsRequest` from the DDS DAP handler now include `isolateId` fields to allow mapping back to VM Service Isolates.

# 2.9.4
- Updated `devtools_shared` to ^2.26.1
Expand Down
41 changes: 41 additions & 0 deletions pkg/dds/lib/src/dap/adapters/dds_hosted_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,28 @@ class DdsHostedAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
unawaited(connectDebugger(ddsUri!));
}

/// Handles a request from the client for the list of threads.
///
/// Unlike the base implementation, the DDS version includes additional fields
/// in the response for `isolateId`.
@override
Future<void> threadsRequest(
Request request,
void args,
void Function(ThreadsResponseBody) sendResponse,
) async {
final threads = [
for (final thread in isolateManager.threads)
ThreadWithIsolateId(
id: thread.threadId,
name: thread.isolate.name ?? '<unnamed isolate>',
isolateId:
thread.isolate.id ?? '<unknown isolate ${thread.threadId}>',
)
];
sendResponse(ThreadsResponseBody(threads: threads));
}

/// Handles custom requests that are specific to the DDS-hosted adapter, such
/// as translating between VM IDs and DAP IDs.
@override
Expand Down Expand Up @@ -228,3 +250,22 @@ class DdsHostedAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
_dapEventsController.stream.listen(eventHandler);
}
}

/// Extends [Thread] with [isolateId] for easier mapping for clients using both
/// DAP and VM Service.
class ThreadWithIsolateId extends Thread {
/// The ID of the Isolate this thread represents.
final String isolateId;

ThreadWithIsolateId({
required super.id,
required super.name,
required this.isolateId,
});

@override
Map<String, Object?> toJson() => {
...super.toJson(),
'isolateId': isolateId,
};
}
1 change: 1 addition & 0 deletions pkg/dds/lib/src/dap/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Command {
static const initialize = 'initialize';
static const configurationDone = 'configurationDone';
static const attach = 'attach';
static const threads = 'threads';
static const createVariableForInstance = r'$/createVariableForInstance';
static const getVariablesInstanceId = r'$/getVariablesInstanceId';
}
Expand Down
27 changes: 26 additions & 1 deletion pkg/dds/test/dap_handler_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ void main() {
});

var nextSeq = 1;
Future<DapResponse> sendDapRequest(String request, Object? arguments) async {
Future<DapResponse> sendDapRequest(String request,
[Object? arguments]) async {
final result = await service.sendDapRequest(
jsonEncode(
Request(
Expand Down Expand Up @@ -153,4 +154,28 @@ void main() {
expect(await variableToString(variablesReference), 'MyClass');
expect(await instanceToString(isolateId, mappedInstanceId), 'MyClass');
});

test('DAP includes Isolate IDs in Threads', () async {
await createProcess(pauseOnStart: false);
dds = await DartDevelopmentService.startDartDevelopmentService(
remoteVmServiceUri,
);
service = await vmServiceConnectUri(dds!.wsUri!.toString());

// Get the expected isolateId.
final isolateId = (await service.getVM()).isolates!.first.id!;

// Ask DAP for all threads.
final threadsResult = await sendDapRequest(Command.threads);
final threadsBody = threadsResult.dapResponse.body as Map<String, Object?>;

final threads = threadsBody['threads'] as List;
expect(threads, hasLength(1));
final thread = threads[0] as Map<String, Object?>;
expect(thread, {
'id': 1,
'name': 'main',
'isolateId': isolateId,
});
});
}

0 comments on commit 45d06f2

Please sign in to comment.