Skip to content

Commit 02d9c3e

Browse files
DanTupCommit Bot
authored and
Commit Bot
committed
[dds] Improve suppression of auto-resuming threads when attaching to processes
Hopefully fixes #48274. Change-Id: I893a1f5dee54410986644a52b7c2bb406d4e51f3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237683 Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Ben Konyi <[email protected]>
1 parent c2a63d7 commit 02d9c3e

File tree

4 files changed

+36
-30
lines changed

4 files changed

+36
-30
lines changed

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,10 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
482482
isAttach = true;
483483
_subscribeToOutputStreams = true;
484484

485+
// When attaching to a process, suppress auto-resuming isolates until the
486+
// first time the user resumes anything.
487+
_isolateManager.autoResumeStartingIsolates = false;
488+
485489
// Common setup.
486490
await _prepareForLaunchOrAttach(null);
487491

@@ -538,13 +542,11 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
538542
/// The URI protocol will be changed to ws/wss but otherwise not normalised.
539543
/// The caller should handle any other normalisation (such as adding /ws to
540544
/// the end if required).
541-
///
542-
/// If [resumeIfStarting] is true, isolates waiting to start will
543-
/// automatically be resumed. This is usually desired in launch requests, but
544-
/// not when attaching.
545545
Future<void> connectDebugger(
546546
Uri uri, {
547-
required bool resumeIfStarting,
547+
// TODO(dantup): Remove this after parameter after updating the Flutter
548+
// DAP to not pass it.
549+
bool? resumeIfStarting,
548550
}) async {
549551
// Start up a DDS instance for this VM.
550552
if (enableDds) {
@@ -622,7 +624,7 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
622624
await debuggerConnected(vmInfo);
623625

624626
await _withErrorHandling(
625-
() => _configureExistingIsolates(vmService, vmInfo, resumeIfStarting),
627+
() => _configureExistingIsolates(vmService, vmInfo),
626628
);
627629

628630
_debuggerInitializedCompleter.complete();
@@ -633,7 +635,6 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
633635
Future<void> _configureExistingIsolates(
634636
vm.VmService vmService,
635637
vm.VM vmInfo,
636-
bool resumeIfStarting,
637638
) async {
638639
final existingIsolateRefs = vmInfo.isolates;
639640
final existingIsolates = existingIsolateRefs != null
@@ -659,12 +660,11 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
659660
if (isolate.pauseEvent?.kind?.startsWith('Pause') ?? false) {
660661
await _isolateManager.handleEvent(
661662
isolate.pauseEvent!,
662-
resumeIfStarting: resumeIfStarting,
663663
);
664664
} else if (isolate.runnable == true) {
665665
// If requested, automatically resume. Otherwise send a Stopped event to
666666
// inform the client UI the thread is paused.
667-
if (resumeIfStarting) {
667+
if (_isolateManager.autoResumeStartingIsolates) {
668668
await _isolateManager.resumeIsolate(isolate);
669669
} else {
670670
_isolateManager.sendStoppedOnEntryEvent(thread.threadId);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class DartCliDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
9494
if (debug) {
9595
vmServiceInfoFile = generateVmServiceInfoFile();
9696
unawaited(waitForVmServiceInfoFile(logger, vmServiceInfoFile)
97-
.then((uri) => connectDebugger(uri, resumeIfStarting: true)));
97+
.then((uri) => connectDebugger(uri)));
9898
}
9999

100100
final vmArgs = <String>[
@@ -191,7 +191,7 @@ class DartCliDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
191191
? Uri.parse(vmServiceUri)
192192
: await waitForVmServiceInfoFile(logger, File(vmServiceInfoFile!));
193193

194-
unawaited(connectDebugger(uri, resumeIfStarting: false));
194+
unawaited(connectDebugger(uri));
195195
}
196196

197197
/// Calls the client (via a `runInTerminal` request) to spawn the process so

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class DartTestDebugAdapter extends DartDebugAdapter<DartLaunchRequestArguments,
7979
if (debug) {
8080
vmServiceInfoFile = generateVmServiceInfoFile();
8181
unawaited(waitForVmServiceInfoFile(logger, vmServiceInfoFile)
82-
.then((uri) => connectDebugger(uri, resumeIfStarting: true)));
82+
.then((uri) => connectDebugger(uri)));
8383
}
8484

8585
final vmArgs = <String>[

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ class IsolateManager {
5656
/// [debugExternalPackageLibraries] in one step.
5757
bool debugExternalPackageLibraries = true;
5858

59+
/// Whether to automatically resume new isolates after configuring them.
60+
///
61+
/// This setting is almost always `true` because isolates are paused only so
62+
/// we can configure them (send breakpoints, pause-on-exceptions,
63+
/// setLibraryDebuggables) without races. It is set to `false` during the
64+
/// initial connection of an `attachRequest` to allow paused isolates to
65+
/// remain paused. In this case, it will be automatically re-set to `true` the
66+
/// first time the user resumes.
67+
bool autoResumeStartingIsolates = true;
68+
5969
/// The root of the Dart SDK containing the VM running the debug adapter.
6070
late final String sdkRoot;
6171

@@ -138,13 +148,7 @@ class IsolateManager {
138148
ThreadInfo? getThread(int threadId) => _threadsByThreadId[threadId];
139149

140150
/// Handles Isolate and Debug events.
141-
///
142-
/// If [resumeIfStarting] is `true`, PauseStart/PausePostStart events will be
143-
/// automatically resumed from.
144-
Future<void> handleEvent(
145-
vm.Event event, {
146-
bool resumeIfStarting = true,
147-
}) async {
151+
Future<void> handleEvent(vm.Event event) async {
148152
final isolateId = event.isolate?.id!;
149153

150154
final eventKind = event.kind;
@@ -163,7 +167,7 @@ class IsolateManager {
163167
if (eventKind == vm.EventKind.kIsolateExit) {
164168
_handleExit(event);
165169
} else if (eventKind?.startsWith('Pause') ?? false) {
166-
await _handlePause(event, resumeIfStarting: resumeIfStarting);
170+
await _handlePause(event);
167171
} else if (eventKind == vm.EventKind.kResume) {
168172
_handleResumed(event);
169173
}
@@ -236,6 +240,11 @@ class IsolateManager {
236240
/// [vm.StepOption.kOver], a [StepOption.kOverAsyncSuspension] step will be
237241
/// sent instead.
238242
Future<void> resumeThread(int threadId, [String? resumeType]) async {
243+
// The first time a user resumes a thread is our signal that the app is now
244+
// "running" and future isolates can be auto-resumed. This only affects
245+
// attach, as it's already `true` for launch requests.
246+
autoResumeStartingIsolates = true;
247+
239248
final thread = _threadsByThreadId[threadId];
240249
if (thread == null) {
241250
throw DebugAdapterException('Thread $threadId was not found');
@@ -408,21 +417,18 @@ class IsolateManager {
408417
///
409418
/// For [vm.EventKind.kPausePostRequest] which occurs after a restart, the
410419
/// isolate will be re-configured (pause-exception behaviour, debuggable
411-
/// libraries, breakpoints) and then (if [resumeIfStarting] is `true`)
412-
/// resumed.
420+
/// libraries, breakpoints) and then (if [autoResumeStartingIsolates] is
421+
/// `true`) resumed.
413422
///
414-
/// For [vm.EventKind.kPauseStart] and [resumeIfStarting] is `true`, the
415-
/// isolate will be resumed.
423+
/// For [vm.EventKind.kPauseStart] and [autoResumeStartingIsolates] is `true`,
424+
/// the isolate will be resumed.
416425
///
417426
/// For breakpoints with conditions that are not met and for logpoints, the
418427
/// isolate will be automatically resumed.
419428
///
420429
/// For all other pause types, the isolate will remain paused and a
421430
/// corresponding "Stopped" event sent to the editor.
422-
Future<void> _handlePause(
423-
vm.Event event, {
424-
bool resumeIfStarting = true,
425-
}) async {
431+
Future<void> _handlePause(vm.Event event) async {
426432
final eventKind = event.kind;
427433
final isolate = event.isolate!;
428434
final thread = _threadsByIsolateId[isolate.id!];
@@ -439,7 +445,7 @@ class IsolateManager {
439445
// after a hot restart.
440446
if (eventKind == vm.EventKind.kPausePostRequest) {
441447
await _configureIsolate(thread);
442-
if (resumeIfStarting) {
448+
if (autoResumeStartingIsolates) {
443449
await resumeThread(thread.threadId);
444450
}
445451
} else if (eventKind == vm.EventKind.kPauseStart) {
@@ -449,7 +455,7 @@ class IsolateManager {
449455
thread.startupHandled = true;
450456
// If requested, automatically resume. Otherwise send a Stopped event to
451457
// inform the client UI the thread is paused.
452-
if (resumeIfStarting) {
458+
if (autoResumeStartingIsolates) {
453459
await resumeThread(thread.threadId);
454460
} else {
455461
sendStoppedOnEntryEvent(thread.threadId);

0 commit comments

Comments
 (0)