Skip to content

Commit 93556ae

Browse files
ellietteCommit Queue
authored andcommitted
[DAP] Set requirePermissionToResume and requireUserPermissionToResume for onPauseStart and onPauseExit so that DDS waits for DAP's permission before resuming the isolate.
Bug: #54843 Change-Id: I12686d6c683983b7af5a3148681410ff9c684343 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/350649 Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Elliott Brooks <[email protected]>
1 parent 1afb12f commit 93556ae

File tree

13 files changed

+404
-99
lines changed

13 files changed

+404
-99
lines changed

pkg/dds/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
- [DAP]: Fixed an issue where breakpoint `changed` events might contain incorrect location information when new isolates are created, causing breakpoints to appear to move in the editor.
33
- [DAP]: For consistency with other values, automatic `toString()` invocations for debugger views no longer expand long strings and instead show truncated values. Full values continue to be returned for evaluation (`context=="repl"`) and when copying to the clipboard (`context=="clipboard"`).
44
- [DAP]: Improved handling of sentinel responses when building `variables` responses. This prevents entire map/list requests from failing when only some values inside are sentinels.
5+
- [DAP] Set `requirePermissionToResume` and `requireUserPermissionToResume` for `onPauseStart` and `onPauseExit` so that DDS waits for DAP's permission before resuming the isolate.
56

67
# 4.2.0
78
- [DAP] All `OutputEvent`s are now scanned for stack frames to attach `source` metadata to. The [parseStackFrames] parameter for `sendOutput` is ignored and deprecated.

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

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dart:io';
88

99
import 'package:collection/collection.dart';
1010
import 'package:dap/dap.dart';
11+
import 'package:dds_service_extensions/dds_service_extensions.dart';
1112
import 'package:json_rpc_2/error_code.dart' as json_rpc_errors;
1213
import 'package:meta/meta.dart';
1314
import 'package:path/path.dart' as path;
@@ -434,12 +435,19 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
434435
/// vs 'detached').
435436
bool isDetaching = false;
436437

437-
/// Whether isolates that pause in the PauseExit state should be automatically
438-
/// resumed after any in-process log events have completed.
438+
/// Whether this adapter set the --pause-isolates-on-start flag, specifying
439+
/// that isolates should pause on starting.
439440
///
440441
/// Normally this will be true, but it may be set to false if the user
441-
/// also manually passes pause-isolates-on-exit.
442-
bool resumeIsolatesAfterPauseExit = true;
442+
/// also manually passed the --pause-isolates-on-start flag.
443+
bool pauseIsolatesOnStartSetByDap = true;
444+
445+
/// Whether this adapter set the --pause-isolates-on-exit flag, specifying
446+
/// that isolates should pause on exiting.
447+
///
448+
/// Normally this will be true, but it may be set to false if the user
449+
/// also manually passed the --pause-isolates-on-exit flag.
450+
bool pauseIsolatesOnExitSetByDap = true;
443451

444452
/// A [Future] that completes when the last queued OutputEvent has been sent.
445453
///
@@ -559,10 +567,6 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
559567
isAttach = true;
560568
_subscribeToOutputStreams = true;
561569

562-
// When attaching to a process, suppress auto-resuming isolates until the
563-
// first time the user resumes anything.
564-
isolateManager.autoResumeStartingIsolates = false;
565-
566570
// Common setup.
567571
await _prepareForLaunchOrAttach(null);
568572

@@ -702,6 +706,7 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
702706
// Let the subclass do any existing setup once we have a connection.
703707
await debuggerConnected(vmInfo);
704708

709+
await _configureIsolateSettings(vmService);
705710
await _withErrorHandling(
706711
() => _configureExistingIsolates(vmService, vmInfo),
707712
);
@@ -756,6 +761,68 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
756761
return DapProgressReporter.start(this, id, title, message: message);
757762
}
758763

764+
Future<void> _configureIsolateSettings(
765+
vm.VmService vmService,
766+
) async {
767+
// If this is an attach workflow, check whether pause_isolates_on_start or
768+
// pause_isolates_on_exit were already set, and if not set them (note: this
769+
// is already done as part of the launch workflow):
770+
if (isAttach) {
771+
const pauseIsolatesOnStart = 'pause_isolates_on_start';
772+
const pauseIsolatesOnExit = 'pause_isolates_on_exit';
773+
final flags = (await vmService.getFlagList()).flags ?? <vm.Flag>[];
774+
for (final flag in flags) {
775+
final flagName = flag.name;
776+
final isPauseIsolatesFlag =
777+
flagName == pauseIsolatesOnStart || flagName == pauseIsolatesOnExit;
778+
if (flagName == null || !isPauseIsolatesFlag) continue;
779+
780+
if (flag.valueAsString == 'true') {
781+
if (flagName == pauseIsolatesOnStart) {
782+
pauseIsolatesOnStartSetByDap = false;
783+
}
784+
if (flagName == pauseIsolatesOnExit) {
785+
pauseIsolatesOnExitSetByDap = false;
786+
}
787+
} else {
788+
_setVmFlagTo(vmService, flagName: flagName, valueAsString: 'true');
789+
}
790+
}
791+
}
792+
793+
try {
794+
// Make sure DDS waits for DAP to be ready to resume before forwarding
795+
// resume requests to the VM Service:
796+
await vmService.requirePermissionToResume(
797+
onPauseStart: true,
798+
onPauseExit: true,
799+
);
800+
801+
// Specify whether DDS should wait for a user-initiated resume as well as a
802+
// DAP-initiated resume:
803+
await vmService.requireUserPermissionToResume(
804+
onPauseStart: !pauseIsolatesOnStartSetByDap,
805+
onPauseExit: !pauseIsolatesOnExitSetByDap,
806+
);
807+
} catch (e) {
808+
// If DDS is not enabled, calling these DDS service extensions will fail.
809+
// Therefore catch and log any errors.
810+
logger?.call('Failure configuring isolate settings: $e');
811+
}
812+
}
813+
814+
Future<void> _setVmFlagTo(
815+
vm.VmService vmService, {
816+
required String flagName,
817+
required String valueAsString,
818+
}) async {
819+
try {
820+
await vmService.setFlag(flagName, valueAsString);
821+
} catch (e) {
822+
logger?.call('Failed to to set VM flag $flagName to $valueAsString: $e');
823+
}
824+
}
825+
759826
/// Process any existing isolates that may have been created before the
760827
/// streams above were set up.
761828
Future<void> _configureExistingIsolates(
@@ -775,8 +842,7 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
775842
final pauseEventKind = isolate.runnable ?? false
776843
? vm.EventKind.kIsolateRunnable
777844
: vm.EventKind.kIsolateStart;
778-
final thread =
779-
await isolateManager.registerIsolate(isolate, pauseEventKind);
845+
await isolateManager.registerIsolate(isolate, pauseEventKind);
780846

781847
// If the Isolate already has a Pause event we can give it to the
782848
// IsolateManager to handle (if it's PausePostStart it will re-configure
@@ -788,13 +854,7 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
788854
isolate.pauseEvent!,
789855
);
790856
} else if (isolate.runnable == true) {
791-
// If requested, automatically resume. Otherwise send a Stopped event to
792-
// inform the client UI the thread is paused.
793-
if (isolateManager.autoResumeStartingIsolates) {
794-
await isolateManager.resumeIsolate(isolate);
795-
} else {
796-
isolateManager.sendStoppedOnEntryEvent(thread.threadId);
797-
}
857+
await isolateManager.readyToResumeIsolate(isolate);
798858
}
799859
}));
800860
}
@@ -2352,11 +2412,9 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
23522412
// We pause isolates on exit to allow requests for resolving URIs in
23532413
// stderr call stacks, so when we see an isolate pause, wait for any
23542414
// pending logs and then resume it (so it exits).
2355-
if (resumeIsolatesAfterPauseExit &&
2356-
eventKind == vm.EventKind.kPauseExit &&
2357-
isolate != null) {
2415+
if (eventKind == vm.EventKind.kPauseExit && isolate != null) {
23582416
await _waitForPendingOutputEvents();
2359-
await isolateManager.resumeIsolate(isolate);
2417+
await isolateManager.readyToResumeIsolate(isolate);
23602418
}
23612419
}
23622420

pkg/dds/lib/src/dap/adapters/dart_cli_adapter.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:dap/dap.dart';
1111
import 'package:path/path.dart' as path;
1212
import 'package:vm_service/vm_service.dart' as vm;
1313

14+
import '../utils.dart';
1415
import 'dart.dart';
1516
import 'mixins.dart';
1617

@@ -68,14 +69,6 @@ class DartCliDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
6869
terminatePids(ProcessSignal.sigkill);
6970
}
7071

71-
/// Checks whether [flag] is in [args], allowing for both underscore and
72-
/// dash format.
73-
bool _containsVmFlag(List<String> args, String flag) {
74-
final flagUnderscores = flag.replaceAll('-', '_');
75-
final flagDashes = flag.replaceAll('_', '-');
76-
return args.contains(flagUnderscores) || args.contains(flagDashes);
77-
}
78-
7972
@override
8073
Future<void> launchImpl() {
8174
throw UnsupportedError(
@@ -115,7 +108,6 @@ class DartCliDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
115108
...?args.vmAdditionalArgs,
116109
if (debug) ...[
117110
'--enable-vm-service=${args.vmServicePort ?? 0}${ipv6 ? '/::1' : ''}',
118-
'--pause_isolates_on_start',
119111
if (!enableAuthCodes) '--disable-service-auth-codes'
120112
],
121113
'--disable-dart-dev',
@@ -128,12 +120,20 @@ class DartCliDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
128120
final toolArgs = args.toolArgs ?? [];
129121
if (debug) {
130122
// If the user has explicitly set pause-isolates-on-exit we need to
131-
// not add it ourselves, and disable auto-resuming.
132-
if (_containsVmFlag(toolArgs, '--pause_isolates_on_exit')) {
133-
resumeIsolatesAfterPauseExit = false;
123+
// not add it ourselves, and specify that we didn't set it.
124+
if (containsVmFlag(toolArgs, '--pause_isolates_on_exit')) {
125+
pauseIsolatesOnExitSetByDap = false;
134126
} else {
135127
vmArgs.add('--pause_isolates_on_exit');
136128
}
129+
130+
// If the user has explicitly set pause-isolates-on-start we need to
131+
// not add it ourselves, and specify that we didn't set it.
132+
if (containsVmFlag(toolArgs, '--pause_isolates_on_start')) {
133+
pauseIsolatesOnStartSetByDap = false;
134+
} else {
135+
vmArgs.add('--pause_isolates_on_start');
136+
}
137137
}
138138

139139
// Handle customTool and deletion of any arguments for it.

pkg/dds/lib/src/dap/adapters/dart_test_adapter.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'dart:math' as math;
1010
import 'package:vm_service/vm_service.dart' as vm;
1111

1212
import '../stream_transformers.dart';
13+
import '../utils.dart';
1314
import 'dart.dart';
1415
import 'mixins.dart';
1516

@@ -78,17 +79,32 @@ class DartTestDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
7879
.then((uri) => connectDebugger(uri)));
7980
}
8081

81-
final vmArgs = <String>[
82+
var vmArgs = <String>[
8283
...?args.vmAdditionalArgs,
8384
if (debug) ...[
8485
'--enable-vm-service=${args.vmServicePort ?? 0}${ipv6 ? '/::1' : ''}',
85-
'--pause_isolates_on_start',
8686
if (!enableAuthCodes) '--disable-service-auth-codes'
8787
],
8888
if (debug && vmServiceInfoFile != null) ...[
8989
'-DSILENT_VM_SERVICE=true',
9090
'--write-service-info=${Uri.file(vmServiceInfoFile.path)}'
9191
],
92+
];
93+
94+
final toolArgs = args.toolArgs ?? [];
95+
if (debug) {
96+
// If the user has explicitly set pause-isolates-on-start we need to
97+
// not add it ourselves, and specify that we didn't set it.
98+
if (containsVmFlag(toolArgs, '--pause_isolates_on_start') ||
99+
containsVmFlag(vmArgs, '--pause_isolates_on_start')) {
100+
pauseIsolatesOnStartSetByDap = false;
101+
} else {
102+
vmArgs.add('--pause_isolates_on_start');
103+
}
104+
}
105+
106+
vmArgs = [
107+
...vmArgs,
92108
// TODO(dantup): This should be changed from "dart run test:test" to
93109
// "dart test" once the start-paused flags are working correctly.
94110
// Currently they start paused but do not write the vm-service-info file

0 commit comments

Comments
 (0)