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++; + } +}