From 322baef3e1761e47b404ec993bbad145a90a231e Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Thu, 5 Dec 2024 00:16:38 +0000 Subject: [PATCH] [io] Exit the isolate during Process.runSync and sleep. This prevents such an isolate from occupying one of the limited number of mutator slots and blocking other isolates in the same group from running. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/51254 Bug: https://github.com/dart-lang/sdk/issues/54687 Bug: https://github.com/dart-lang/sdk/issues/57119 Change-Id: Ic04bbaa7f482d533ad0ecf2c6da17ea9f00c264e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398927 Reviewed-by: Alexander Aprelev Commit-Queue: Ryan Macnak --- runtime/bin/dartutils.h | 14 +++++++++++ runtime/bin/process.cc | 2 ++ runtime/bin/process_linux.cc | 2 ++ runtime/bin/process_macos.cc | 2 ++ runtime/bin/process_win.cc | 2 ++ ...ates_blocked_at_process_run_sync_test.dart | 25 +++++++++++++++++++ .../many_isolates_blocked_at_sleep_test.dart | 25 +++++++++++++++++++ 7 files changed, 72 insertions(+) create mode 100644 runtime/tests/vm/dart/isolates/many_isolates_blocked_at_process_run_sync_test.dart create mode 100644 runtime/tests/vm/dart/isolates/many_isolates_blocked_at_sleep_test.dart diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h index 228779000fc..b414d731ca9 100644 --- a/runtime/bin/dartutils.h +++ b/runtime/bin/dartutils.h @@ -651,6 +651,20 @@ class ScopedBlockingCall { DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCall); }; +// Remove once we remove the limitation on the number of running mutators. +// https://github.com/dart-lang/sdk/issues/54687 +class LeaveIsolateScope { + public: + LeaveIsolateScope() : isolate_(Dart_CurrentIsolate()) { Dart_ExitIsolate(); } + ~LeaveIsolateScope() { Dart_EnterIsolate(isolate_); } + + private: + Dart_Isolate isolate_; + + DISALLOW_ALLOCATION(); + DISALLOW_COPY_AND_ASSIGN(LeaveIsolateScope); +}; + struct MagicNumberData { static constexpr intptr_t kMaxLength = 8; diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc index 309f69014d1..f990e80e3ac 100644 --- a/runtime/bin/process.cc +++ b/runtime/bin/process.cc @@ -285,6 +285,8 @@ void FUNCTION_NAME(Process_Sleep)(Dart_NativeArguments args) { int64_t milliseconds = 0; // Ignore result if passing invalid argument and just set exit code to 0. DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &milliseconds); + + LeaveIsolateScope leave_isolate; TimerUtils::Sleep(milliseconds); } diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc index 5439d4ec8a6..64e74fcfab9 100644 --- a/runtime/bin/process_linux.cc +++ b/runtime/bin/process_linux.cc @@ -849,6 +849,8 @@ bool Process::Wait(intptr_t pid, int alive = 3; while (alive > 0) { + LeaveIsolateScope leave_isolate; + // Blocking call waiting for events from the child process. if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) { return CloseProcessBuffers(fds, alive); diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc index 24300eeb3c7..d7eb45e4ae0 100644 --- a/runtime/bin/process_macos.cc +++ b/runtime/bin/process_macos.cc @@ -826,6 +826,8 @@ bool Process::Wait(intptr_t pid, int alive = 3; while (alive > 0) { + LeaveIsolateScope leave_isolate; + // Blocking call waiting for events from the child process. if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) { return CloseProcessBuffers(fds, alive); diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc index 44b61e0412c..e9a353b36c3 100644 --- a/runtime/bin/process_win.cc +++ b/runtime/bin/process_win.cc @@ -828,6 +828,8 @@ bool Process::Wait(intptr_t pid, // Continue until all handles are closed. int alive = kHandles; while (alive > 0) { + LeaveIsolateScope leave_isolate; + // Blocking call waiting for events from the child process. DWORD wait_result = WaitForMultipleObjects(alive, events, FALSE, INFINITE); diff --git a/runtime/tests/vm/dart/isolates/many_isolates_blocked_at_process_run_sync_test.dart b/runtime/tests/vm/dart/isolates/many_isolates_blocked_at_process_run_sync_test.dart new file mode 100644 index 00000000000..42d4d9aa5fa --- /dev/null +++ b/runtime/tests/vm/dart/isolates/many_isolates_blocked_at_process_run_sync_test.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import "dart:isolate"; +import "dart:io"; + +child(replyPort) { + replyPort.send(null); + Process.runSync("sleep", ["3600"]); +} + +main() async { + var pending = 0; + var port; + port = new RawReceivePort((msg) { + pending--; + if (pending == 0) exit(0); + }); + + for (var i = 0; i < 20; i++) { + Isolate.spawn(child, port.sendPort); + pending++; + } +} diff --git a/runtime/tests/vm/dart/isolates/many_isolates_blocked_at_sleep_test.dart b/runtime/tests/vm/dart/isolates/many_isolates_blocked_at_sleep_test.dart new file mode 100644 index 00000000000..d053d684868 --- /dev/null +++ b/runtime/tests/vm/dart/isolates/many_isolates_blocked_at_sleep_test.dart @@ -0,0 +1,25 @@ +// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import "dart:isolate"; +import "dart:io"; + +child(replyPort) { + replyPort.send(null); + sleep(Duration(minutes: 60)); +} + +main() async { + var pending = 0; + var port; + port = new RawReceivePort((msg) { + pending--; + if (pending == 0) exit(0); + }); + + for (var i = 0; i < 20; i++) { + Isolate.spawn(child, port.sendPort); + pending++; + } +}