Skip to content

Commit 130ae2a

Browse files
rmacnak-googleCommit Queue
authored and
Commit Queue
committed
[vm, isolates] Avoid three-way deadlock during isolate exit, take 2.
Give up the tasks lock before interrupting to finalize marking. TEST=ci, tsan, rr chaos mode Bug: #59574 Change-Id: I9f4ca977354b3860897654790fceb8f0e2e25aab Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398580 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 85c339c commit 130ae2a

File tree

5 files changed

+28
-17
lines changed

5 files changed

+28
-17
lines changed

runtime/vm/heap/marker.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,9 @@ class ConcurrentMarkTask : public ThreadPool::Task {
10661066
// Exit isolate cleanly *before* notifying it, to avoid shutdown race.
10671067
Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/true);
10681068
// This marker task is done. Notify the original isolate.
1069+
1070+
Dart_Port interrupt_port = isolate_group_->interrupt_port();
1071+
10691072
{
10701073
MonitorLocker ml(page_space_->tasks_lock());
10711074
page_space_->set_tasks(page_space_->tasks() - 1);
@@ -1076,10 +1079,12 @@ class ConcurrentMarkTask : public ThreadPool::Task {
10761079
ASSERT(page_space_->phase() == PageSpace::kMarking);
10771080
if (page_space_->concurrent_marker_tasks() == 0) {
10781081
page_space_->set_phase(PageSpace::kAwaitingFinalization);
1079-
isolate_group_->ScheduleInterrupts(Thread::kVMInterrupt);
10801082
}
10811083
ml.NotifyAll();
10821084
}
1085+
1086+
PortMap::PostMessage(Message::New(
1087+
interrupt_port, Smi::New(Thread::kVMInterrupt), Message::kOOBPriority));
10831088
}
10841089

10851090
private:

runtime/vm/isolate.cc

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,9 @@ IsolateGroup::~IsolateGroup() {
442442
void IsolateGroup::RegisterIsolate(Isolate* isolate) {
443443
SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
444444
ASSERT(isolates_lock_->IsCurrentThreadWriter());
445+
if (isolates_.IsEmpty()) {
446+
interrupt_port_ = isolate->main_port();
447+
}
445448
isolates_.Append(isolate);
446449
isolate_count_++;
447450
}
@@ -454,14 +457,14 @@ bool IsolateGroup::ContainsOnlyOneIsolate() {
454457
return isolate_count_ == 0 || isolate_count_ == 1;
455458
}
456459

457-
void IsolateGroup::RunWithLockedGroup(std::function<void()> fun) {
458-
SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
459-
fun();
460-
}
461-
462460
void IsolateGroup::UnregisterIsolate(Isolate* isolate) {
463461
SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
464462
isolates_.Remove(isolate);
463+
if (isolates_.IsEmpty()) {
464+
interrupt_port_ = ILLEGAL_PORT;
465+
} else {
466+
interrupt_port_ = isolates_.First()->main_port();
467+
}
465468
}
466469

467470
bool IsolateGroup::UnregisterIsolateDecrementCount() {
@@ -1424,6 +1427,13 @@ MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
14241427
}
14251428
}
14261429
}
1430+
} else if (msg.IsSmi()) {
1431+
uword interrupt_bits = Smi::Cast(msg).Value();
1432+
const Error& error =
1433+
Error::Handle(thread->HandleInterrupts(interrupt_bits));
1434+
if (!error.IsNull()) {
1435+
status = ProcessUnhandledException(error);
1436+
}
14271437
}
14281438
} else if (message->IsFinalizerInvocationRequest()) {
14291439
const Object& msg_handler = Object::Handle(
@@ -1954,13 +1964,6 @@ void IsolateGroup::SetupImagePage(const uint8_t* image_buffer,
19541964
is_executable);
19551965
}
19561966

1957-
void IsolateGroup::ScheduleInterrupts(uword interrupt_bits) {
1958-
SafepointReadRwLocker ml(Thread::Current(), isolates_lock_.get());
1959-
for (Isolate* isolate : isolates_) {
1960-
isolate->ScheduleInterrupts(interrupt_bits);
1961-
}
1962-
}
1963-
19641967
void Isolate::ScheduleInterrupts(uword interrupt_bits) {
19651968
// We take the threads lock here to ensure that the mutator thread does not
19661969
// exit the isolate while we are trying to schedule interrupts on it.

runtime/vm/isolate.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
327327

328328
bool ContainsOnlyOneIsolate();
329329

330-
void RunWithLockedGroup(std::function<void()> fun);
331-
332-
void ScheduleInterrupts(uword interrupt_bits);
330+
Dart_Port interrupt_port() { return interrupt_port_; }
333331

334332
ThreadRegistry* thread_registry() const { return thread_registry_.get(); }
335333
SafepointHandler* safepoint_handler() { return safepoint_handler_.get(); }
@@ -836,6 +834,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
836834
std::unique_ptr<MutatorThreadPool> thread_pool_;
837835
std::unique_ptr<SafepointRwLock> isolates_lock_;
838836
IntrusiveDList<Isolate> isolates_;
837+
RelaxedAtomic<Dart_Port> interrupt_port_ = ILLEGAL_PORT;
839838
intptr_t isolate_count_ = 0;
840839
bool initial_spawn_successful_ = false;
841840
Dart_LibraryTagHandler library_tag_handler_ = nullptr;

runtime/vm/thread.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,10 @@ uword Thread::GetAndClearInterrupts() {
757757
}
758758

759759
ErrorPtr Thread::HandleInterrupts() {
760-
uword interrupt_bits = GetAndClearInterrupts();
760+
return HandleInterrupts(GetAndClearInterrupts());
761+
}
762+
763+
ErrorPtr Thread::HandleInterrupts(uword interrupt_bits) {
761764
if ((interrupt_bits & kVMInterrupt) != 0) {
762765
CheckForSafepoint();
763766
if (isolate_group()->store_buffer()->Overflowed()) {

runtime/vm/thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ class Thread : public ThreadState {
507507

508508
void ScheduleInterrupts(uword interrupt_bits);
509509
ErrorPtr HandleInterrupts();
510+
ErrorPtr HandleInterrupts(uword interrupt_bits);
510511
uword GetAndClearInterrupts();
511512
bool HasScheduledInterrupts() const {
512513
return (stack_limit_.load() & kInterruptsMask) != 0;

0 commit comments

Comments
 (0)