Skip to content

Commit cad8a34

Browse files
bkonyicommit-bot@chromium.org
authored andcommitted
[ VM / Service ] Add setIsolatePauseMode RPC
Allows for service clients to set pause behaviors on a per-isolate basis at runtime. setIsolatePauseMode is a more general version of setExceptionPauseMode and setExceptionPauseMode has been marked as deprecated. TEST=pause_on_exceptions_*_test.dart,should_pause_on_exit_test.dart Change-Id: I09d80aa2123791dd74d02441c162c19cc0486955 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/219580 Commit-Queue: Ben Konyi <[email protected]> Reviewed-by: Siva Annamalai <[email protected]>
1 parent 2b96453 commit cad8a34

20 files changed

+453
-15
lines changed

pkg/dds/lib/src/dap/isolate_manager.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,10 @@ class IsolateManager {
581581
return;
582582
}
583583

584-
await service.setExceptionPauseMode(isolate.id!, _exceptionPauseMode);
584+
await service.setIsolatePauseMode(
585+
isolate.id!,
586+
exceptionPauseMode: _exceptionPauseMode,
587+
);
585588
}
586589

587590
/// Calls setLibraryDebuggable for all libraries in the given isolate based

pkg/dds/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ dependencies:
2525
shelf_web_socket: ^1.0.0
2626
sse: ^4.0.0
2727
stream_channel: ^2.0.0
28-
vm_service: ^7.2.0
28+
vm_service: ^7.5.0
2929
web_socket_channel: ^2.0.0
3030

3131
dev_dependencies:

pkg/vm_service/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 7.5.0
4+
- Update to version `3.53` of the spec.
5+
- Added `setIsolatePauseMode` RPC.
6+
- Deprecated `setExceptionPauseMode` in favor of `setIsolatePauseMode`.
7+
38
## 7.4.0
49
- Update to version `3.52` of the spec.
510
- Added `lookupResolvedPackageUris` and `lookupPackageUris` RPCs and `UriList`

pkg/vm_service/java/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ src/org/dartlang/vm/service/consumer/RequestHeapSnapshotConsumer.java
3636
src/org/dartlang/vm/service/consumer/ResumeConsumer.java
3737
src/org/dartlang/vm/service/consumer/SetExceptionPauseModeConsumer.java
3838
src/org/dartlang/vm/service/consumer/SetFlagConsumer.java
39+
src/org/dartlang/vm/service/consumer/SetIsolatePauseModeConsumer.java
3940
src/org/dartlang/vm/service/consumer/SetLibraryDebuggableConsumer.java
4041
src/org/dartlang/vm/service/consumer/SetNameConsumer.java
4142
src/org/dartlang/vm/service/consumer/SetTraceClassAllocationConsumer.java
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version=3.52
1+
version=3.53

pkg/vm_service/lib/src/vm_service.dart

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export 'snapshot_graph.dart'
2626
HeapSnapshotObjectNoData,
2727
HeapSnapshotObjectNullData;
2828

29-
const String vmServiceVersion = '3.52.0';
29+
const String vmServiceVersion = '3.53.0';
3030

3131
/// @optional
3232
const String optional = 'optional';
@@ -236,6 +236,7 @@ Map<String, List<String>> _methodReturnTypes = {
236236
'resume': const ['Success'],
237237
'setBreakpointState': const ['Breakpoint'],
238238
'setExceptionPauseMode': const ['Success'],
239+
'setIsolatePauseMode': const ['Success'],
239240
'setFlag': const ['Success', 'Error'],
240241
'setLibraryDebuggable': const ['Success'],
241242
'setName': const ['Success'],
@@ -1078,9 +1079,34 @@ abstract class VmServiceInterface {
10781079
///
10791080
/// This method will throw a [SentinelException] in the case a [Sentinel] is
10801081
/// returned.
1082+
@Deprecated('Use setIsolatePauseMode instead')
10811083
Future<Success> setExceptionPauseMode(
10821084
String isolateId, /*ExceptionPauseMode*/ String mode);
10831085

1086+
/// The `setIsolatePauseMode` RPC is used to control if or when an isolate
1087+
/// will pause due to a change in execution state.
1088+
///
1089+
/// The `shouldPauseOnExit` parameter specify whether the target isolate
1090+
/// should pause on exit.
1091+
///
1092+
/// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
1093+
/// when an exception is thrown.
1094+
///
1095+
/// mode | meaning
1096+
/// ---- | -------
1097+
/// None | Do not pause isolate on thrown exceptions
1098+
/// Unhandled | Pause isolate on unhandled exceptions
1099+
/// All | Pause isolate on all thrown exceptions
1100+
///
1101+
/// If `isolateId` refers to an isolate which has exited, then the `Collected`
1102+
/// [Sentinel] is returned.
1103+
///
1104+
/// This method will throw a [SentinelException] in the case a [Sentinel] is
1105+
/// returned.
1106+
Future<Success> setIsolatePauseMode(String isolateId,
1107+
{/*ExceptionPauseMode*/ String? exceptionPauseMode,
1108+
bool? shouldPauseOnExit});
1109+
10841110
/// The `setFlag` RPC is used to set a VM flag at runtime. Returns an error if
10851111
/// the named flag does not exist, the flag may not be set at runtime, or the
10861112
/// value is of the wrong type for the flag.
@@ -1101,6 +1127,7 @@ abstract class VmServiceInterface {
11011127
/// provided value. If set to false when the profiler is already running, the
11021128
/// profiler will be stopped but may not free its sample buffer depending on
11031129
/// platform limitations.
1130+
/// - Isolate pause settings will only be applied to newly spawned isolates.
11041131
///
11051132
/// See [Success].
11061133
///
@@ -1549,11 +1576,19 @@ class VmServerConnection {
15491576
);
15501577
break;
15511578
case 'setExceptionPauseMode':
1579+
// ignore: deprecated_member_use_from_same_package
15521580
response = await _serviceImplementation.setExceptionPauseMode(
15531581
params!['isolateId'],
15541582
params['mode'],
15551583
);
15561584
break;
1585+
case 'setIsolatePauseMode':
1586+
response = await _serviceImplementation.setIsolatePauseMode(
1587+
params!['isolateId'],
1588+
exceptionPauseMode: params['exceptionPauseMode'],
1589+
shouldPauseOnExit: params['shouldPauseOnExit'],
1590+
);
1591+
break;
15571592
case 'setFlag':
15581593
response = await _serviceImplementation.setFlag(
15591594
params!['name'],
@@ -2081,11 +2116,23 @@ class VmService implements VmServiceInterface {
20812116
'enable': enable
20822117
});
20832118

2119+
@Deprecated('Use setIsolatePauseMode instead')
20842120
@override
20852121
Future<Success> setExceptionPauseMode(
20862122
String isolateId, /*ExceptionPauseMode*/ String mode) =>
20872123
_call('setExceptionPauseMode', {'isolateId': isolateId, 'mode': mode});
20882124

2125+
@override
2126+
Future<Success> setIsolatePauseMode(String isolateId,
2127+
{/*ExceptionPauseMode*/ String? exceptionPauseMode,
2128+
bool? shouldPauseOnExit}) =>
2129+
_call('setIsolatePauseMode', {
2130+
'isolateId': isolateId,
2131+
if (exceptionPauseMode != null)
2132+
'exceptionPauseMode': exceptionPauseMode,
2133+
if (shouldPauseOnExit != null) 'shouldPauseOnExit': shouldPauseOnExit,
2134+
});
2135+
20892136
@override
20902137
Future<Response> setFlag(String name, String value) =>
20912138
_call('setFlag', {'name': name, 'value': value});

pkg/vm_service/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: >-
33
A library to communicate with a service implementing the Dart VM
44
service protocol.
55
6-
version: 7.4.0
6+
version: 7.5.0
77

88
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
99

pkg/vm_service/test/common/test_helper.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ class _ServiceTesterRunner {
277277
vm = await vmServiceConnectUri(serviceWebsocketAddress);
278278
print('Done loading VM');
279279
isolate = await getFirstIsolate(vm);
280-
print('Got first isolate');
281280
});
282281
});
283282

@@ -335,14 +334,12 @@ class _ServiceTesterRunner {
335334
if (event.kind == EventKind.kIsolateRunnable) {
336335
print(event.isolate!.name);
337336
vm = await service.getVM();
338-
//assert(vmIsolates.isNotEmpty);
339337
await subscription.cancel();
340338
await service.streamCancel(EventStreams.kIsolate);
341339
completer!.complete(event.isolate!);
342340
completer = null;
343341
}
344342
});
345-
346343
await service.streamListen(EventStreams.kIsolate);
347344

348345
// The isolate may have started before we subscribed.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
7+
import 'package:test/test.dart';
8+
import 'package:vm_service/vm_service.dart';
9+
10+
import 'common/test_helper.dart';
11+
12+
doThrow() {
13+
throw "TheException"; // Line 13.
14+
}
15+
16+
doCaught() {
17+
try {
18+
doThrow();
19+
} catch (e) {
20+
return "end of doCaught";
21+
}
22+
}
23+
24+
doUncaught() {
25+
doThrow();
26+
return "end of doUncaught";
27+
}
28+
29+
final tests = <IsolateTest>[
30+
(VmService service, IsolateRef isolateRef) async {
31+
final isolate = await service.getIsolate(isolateRef.id!);
32+
final lib = await service.getObject(isolateRef.id!, isolate.rootLib!.id!);
33+
34+
Completer? onPaused;
35+
Completer? onResume;
36+
37+
final stream = service.onDebugEvent;
38+
final subscription = stream.listen((Event event) {
39+
print("Event $event");
40+
if (event.kind == EventKind.kPauseException) {
41+
if (onPaused == null) throw "Unexpected pause event $event";
42+
final t = onPaused;
43+
onPaused = null;
44+
t!.complete(event);
45+
}
46+
if (event.kind == EventKind.kResume) {
47+
if (onResume == null) throw "Unexpected resume event $event";
48+
final t = onResume;
49+
onResume = null;
50+
t!.complete(event);
51+
}
52+
});
53+
await service.streamListen(EventStreams.kDebug);
54+
55+
test(String pauseMode, String expression, bool shouldPause,
56+
bool shouldBeCaught) async {
57+
print("Evaluating $expression with pause on $pauseMode exception");
58+
59+
// ignore: deprecated_member_use_from_same_package
60+
await service.setExceptionPauseMode(isolate.id!, pauseMode);
61+
62+
late Completer t;
63+
if (shouldPause) {
64+
t = Completer();
65+
onPaused = t;
66+
}
67+
final fres = service.evaluate(isolate.id!, lib.id!, expression);
68+
if (shouldPause) {
69+
await t.future;
70+
71+
final stack = await service.getStack(isolate.id!);
72+
expect(stack.frames![0].function!.name, 'doThrow');
73+
74+
t = Completer();
75+
onResume = t;
76+
await service.resume(isolate.id!);
77+
await t.future;
78+
}
79+
80+
dynamic res = await fres;
81+
if (shouldBeCaught) {
82+
expect(res is InstanceRef, true);
83+
expect(res.kind, 'String');
84+
expect(res.valueAsString, equals("end of doCaught"));
85+
} else {
86+
print(res.json);
87+
expect(res is ErrorRef, true);
88+
res = await service.getObject(isolate.id!, res.id!);
89+
expect(res is Error, true);
90+
expect(res.exception.kind, 'String');
91+
expect(res.exception.valueAsString, equals("TheException"));
92+
}
93+
}
94+
95+
await test("All", "doCaught()", true, true);
96+
await test("All", "doUncaught()", true, false);
97+
98+
await test("Unhandled", "doCaught()", false, true);
99+
await test("Unhandled", "doUncaught()", true, false);
100+
101+
await test("None", "doCaught()", false, true);
102+
await test("None", "doUncaught()", false, false);
103+
104+
await subscription.cancel();
105+
},
106+
];
107+
108+
main([args = const <String>[]]) => runIsolateTests(
109+
args,
110+
tests,
111+
'pause_on_exceptions_test.dart',
112+
);

0 commit comments

Comments
 (0)