Skip to content

Commit 2a08770

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] If waiting for an active mutator slot for too long, steal a slot from a thread at a native safepoint.
The thread whose slot was stolen will take the slow path attempting to exit its safepoint and wait to reacquire an active mutator slot. TEST=ci Bug: #54687 Change-Id: I49c4c12b38d38d7afa4df6b346c2a464f75ef6e0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/406404 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent a78235c commit 2a08770

23 files changed

+254
-97
lines changed

runtime/bin/dartutils.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -651,20 +651,6 @@ class ScopedBlockingCall {
651651
DISALLOW_COPY_AND_ASSIGN(ScopedBlockingCall);
652652
};
653653

654-
// Remove once we remove the limitation on the number of running mutators.
655-
// https://github.com/dart-lang/sdk/issues/54687
656-
class LeaveIsolateScope {
657-
public:
658-
LeaveIsolateScope() : isolate_(Dart_CurrentIsolate()) { Dart_ExitIsolate(); }
659-
~LeaveIsolateScope() { Dart_EnterIsolate(isolate_); }
660-
661-
private:
662-
Dart_Isolate isolate_;
663-
664-
DISALLOW_ALLOCATION();
665-
DISALLOW_COPY_AND_ASSIGN(LeaveIsolateScope);
666-
};
667-
668654
struct MagicNumberData {
669655
static constexpr intptr_t kMaxLength = 8;
670656

runtime/bin/process.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,6 @@ void FUNCTION_NAME(Process_Sleep)(Dart_NativeArguments args) {
285285
int64_t milliseconds = 0;
286286
// Ignore result if passing invalid argument and just set exit code to 0.
287287
DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &milliseconds);
288-
289-
LeaveIsolateScope leave_isolate;
290288
TimerUtils::Sleep(milliseconds);
291289
}
292290

runtime/bin/process_linux.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -861,8 +861,6 @@ bool Process::Wait(intptr_t pid,
861861

862862
int alive = 3;
863863
while (alive > 0) {
864-
LeaveIsolateScope leave_isolate;
865-
866864
// Blocking call waiting for events from the child process.
867865
if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) {
868866
return CloseProcessBuffers(fds, alive);

runtime/bin/process_macos.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,6 @@ bool Process::Wait(intptr_t pid,
826826

827827
int alive = 3;
828828
while (alive > 0) {
829-
LeaveIsolateScope leave_isolate;
830-
831829
// Blocking call waiting for events from the child process.
832830
if (TEMP_FAILURE_RETRY(poll(fds, alive, -1)) <= 0) {
833831
return CloseProcessBuffers(fds, alive);

runtime/bin/process_win.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -866,8 +866,6 @@ bool Process::Wait(intptr_t pid,
866866
// Continue until all handles are closed.
867867
int alive = kHandles;
868868
while (alive > 0) {
869-
LeaveIsolateScope leave_isolate;
870-
871869
// Blocking call waiting for events from the child process.
872870
DWORD wait_result = WaitForMultipleObjects(alive, events, FALSE, INFINITE);
873871

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) 2025, 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:isolate";
6+
import "dart:io";
7+
import "dart:ffi";
8+
9+
typedef CSleep = Void Function(Int32);
10+
typedef DartSleep = void Function(int);
11+
12+
child(replyPort) {
13+
replyPort.send(null);
14+
15+
var sleep = DynamicLibrary.process().lookupFunction<CSleep, DartSleep>(
16+
"sleep",
17+
);
18+
sleep(60 * 60);
19+
}
20+
21+
main() async {
22+
var pending = 0;
23+
var port;
24+
port = new RawReceivePort((msg) {
25+
pending--;
26+
if (pending == 0) exit(0);
27+
});
28+
29+
for (var i = 0; i < 20; i++) {
30+
Isolate.spawn(child, port.sendPort);
31+
pending++;
32+
}
33+
}

runtime/tests/vm/vm.status

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ dart/kernel_determinism_test: SkipSlow
5656
dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow with optimization_counter_threshold
5757

5858
[ $compiler == app_jitk ]
59+
dart/isolates/many_isolates_blocked_at_ffi_test: Skip # App snapshot creation needs regular isolate shutdown
60+
dart/isolates/many_isolates_blocked_at_process_run_sync_test: Skip # App snapshot creation needs regular isolate shutdown
61+
dart/isolates/many_isolates_blocked_at_sleep_test: Skip # App snapshot creation needs regular isolate shutdown
5962
dart/snapshot_version_test: RuntimeError
6063

6164
[ $compiler == dartk ]

runtime/vm/compiler/assembler/assembler_arm.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -590,10 +590,10 @@ void Assembler::EnterFullSafepoint(Register addr, Register state) {
590590
add(addr, THR, Operand(addr));
591591
Bind(&retry);
592592
ldrex(state, addr);
593-
cmp(state, Operand(target::Thread::full_safepoint_state_unacquired()));
593+
cmp(state, Operand(target::Thread::native_safepoint_state_unacquired()));
594594
b(&slow_path, NE);
595595

596-
mov(state, Operand(target::Thread::full_safepoint_state_acquired()));
596+
mov(state, Operand(target::Thread::native_safepoint_state_acquired()));
597597
strex(TMP, state, addr);
598598
cmp(TMP, Operand(0)); // 0 means strex was successful.
599599
b(&done, EQ);
@@ -651,10 +651,10 @@ void Assembler::ExitFullSafepoint(Register tmp1,
651651
add(addr, THR, Operand(addr));
652652
Bind(&retry);
653653
ldrex(state, addr);
654-
cmp(state, Operand(target::Thread::full_safepoint_state_acquired()));
654+
cmp(state, Operand(target::Thread::native_safepoint_state_acquired()));
655655
b(&slow_path, NE);
656656

657-
mov(state, Operand(target::Thread::full_safepoint_state_unacquired()));
657+
mov(state, Operand(target::Thread::native_safepoint_state_unacquired()));
658658
strex(TMP, state, addr);
659659
cmp(TMP, Operand(0)); // 0 means strex was successful.
660660
b(&done, EQ);
@@ -690,8 +690,8 @@ void Assembler::TransitionNativeToGenerated(Register addr,
690690
ASSERT(!ignore_unwind_in_progress);
691691
#if defined(DEBUG)
692692
// Ensure we've already left the safepoint.
693-
ASSERT(target::Thread::full_safepoint_state_acquired() != 0);
694-
LoadImmediate(state, target::Thread::full_safepoint_state_acquired());
693+
ASSERT(target::Thread::native_safepoint_state_acquired() != 0);
694+
LoadImmediate(state, target::Thread::native_safepoint_state_acquired());
695695
ldr(TMP, Address(THR, target::Thread::safepoint_state_offset()));
696696
ands(TMP, TMP, Operand(state));
697697
Label ok;

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,10 +1564,10 @@ void Assembler::EnterFullSafepoint(Register state) {
15641564
add(addr, THR, Operand(addr));
15651565
Bind(&retry);
15661566
ldxr(state, addr);
1567-
cmp(state, Operand(target::Thread::full_safepoint_state_unacquired()));
1567+
cmp(state, Operand(target::Thread::native_safepoint_state_unacquired()));
15681568
b(&slow_path, NE);
15691569

1570-
movz(state, Immediate(target::Thread::full_safepoint_state_acquired()), 0);
1570+
movz(state, Immediate(target::Thread::native_safepoint_state_acquired()), 0);
15711571
stxr(TMP, state, addr);
15721572
cbz(&done, TMP); // 0 means stxr was successful.
15731573

@@ -1637,10 +1637,11 @@ void Assembler::ExitFullSafepoint(Register state,
16371637
add(addr, THR, Operand(addr));
16381638
Bind(&retry);
16391639
ldxr(state, addr);
1640-
cmp(state, Operand(target::Thread::full_safepoint_state_acquired()));
1640+
cmp(state, Operand(target::Thread::native_safepoint_state_acquired()));
16411641
b(&slow_path, NE);
16421642

1643-
movz(state, Immediate(target::Thread::full_safepoint_state_unacquired()), 0);
1643+
movz(state, Immediate(target::Thread::native_safepoint_state_unacquired()),
1644+
0);
16441645
stxr(TMP, state, addr);
16451646
cbz(&done, TMP); // 0 means stxr was successful.
16461647

@@ -1674,8 +1675,8 @@ void Assembler::TransitionNativeToGenerated(Register state,
16741675
ASSERT(!ignore_unwind_in_progress);
16751676
#if defined(DEBUG)
16761677
// Ensure we've already left the safepoint.
1677-
ASSERT(target::Thread::full_safepoint_state_acquired() != 0);
1678-
LoadImmediate(state, target::Thread::full_safepoint_state_acquired());
1678+
ASSERT(target::Thread::native_safepoint_state_acquired() != 0);
1679+
LoadImmediate(state, target::Thread::native_safepoint_state_acquired());
16791680
ldr(TMP, Address(THR, target::Thread::safepoint_state_offset()));
16801681
and_(TMP, TMP, Operand(state));
16811682
Label ok;

runtime/vm/compiler/assembler/assembler_ia32.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,12 +2495,12 @@ void Assembler::EnterFullSafepoint(Register scratch) {
24952495
}
24962496

24972497
pushl(EAX);
2498-
movl(EAX, Immediate(target::Thread::full_safepoint_state_unacquired()));
2499-
movl(scratch, Immediate(target::Thread::full_safepoint_state_acquired()));
2498+
movl(EAX, Immediate(target::Thread::native_safepoint_state_unacquired()));
2499+
movl(scratch, Immediate(target::Thread::native_safepoint_state_acquired()));
25002500
LockCmpxchgl(Address(THR, target::Thread::safepoint_state_offset()), scratch);
25012501
movl(scratch, EAX);
25022502
popl(EAX);
2503-
cmpl(scratch, Immediate(target::Thread::full_safepoint_state_unacquired()));
2503+
cmpl(scratch, Immediate(target::Thread::native_safepoint_state_unacquired()));
25042504

25052505
if (!FLAG_use_slow_path) {
25062506
j(EQUAL, &done);
@@ -2551,12 +2551,12 @@ void Assembler::ExitFullSafepoint(Register scratch,
25512551
}
25522552

25532553
pushl(EAX);
2554-
movl(EAX, Immediate(target::Thread::full_safepoint_state_acquired()));
2555-
movl(scratch, Immediate(target::Thread::full_safepoint_state_unacquired()));
2554+
movl(EAX, Immediate(target::Thread::native_safepoint_state_acquired()));
2555+
movl(scratch, Immediate(target::Thread::native_safepoint_state_unacquired()));
25562556
LockCmpxchgl(Address(THR, target::Thread::safepoint_state_offset()), scratch);
25572557
movl(scratch, EAX);
25582558
popl(EAX);
2559-
cmpl(scratch, Immediate(target::Thread::full_safepoint_state_acquired()));
2559+
cmpl(scratch, Immediate(target::Thread::native_safepoint_state_acquired()));
25602560

25612561
if (!FLAG_use_slow_path) {
25622562
j(EQUAL, &done);
@@ -2589,7 +2589,7 @@ void Assembler::TransitionNativeToGenerated(Register scratch,
25892589
#if defined(DEBUG)
25902590
// Ensure we've already left the safepoint.
25912591
movl(scratch, Address(THR, target::Thread::safepoint_state_offset()));
2592-
andl(scratch, Immediate(target::Thread::full_safepoint_state_acquired()));
2592+
andl(scratch, Immediate(target::Thread::native_safepoint_state_acquired()));
25932593
Label ok;
25942594
j(ZERO, &ok);
25952595
Breakpoint();

0 commit comments

Comments
 (0)