mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 19:36:42 +00:00
[vm/isolates] Put limit on how many isolates are suspended.
Fixes https://github.com/dart-lang/sdk/issues/52154 TEST=ci Change-Id: I6f620113232cf8f771dd73be334ace0e385784f5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/297920 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
This commit is contained in:
parent
97a762b083
commit
86d754690a
|
@ -118,7 +118,7 @@ void FieldTable::Grow(intptr_t new_capacity) {
|
|||
// Ensure that new_table_ is populated before it is published
|
||||
// via store to table_.
|
||||
reinterpret_cast<AcqRelAtomic<ObjectPtr*>*>(&table_)->store(new_table);
|
||||
if (isolate_ != nullptr) {
|
||||
if (isolate_ != nullptr && isolate_->mutator_thread() != nullptr) {
|
||||
isolate_->mutator_thread()->field_table_values_ = table_;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,9 @@ void WeakCodeReferences::DisableCode(bool are_mutators_stopped) {
|
|||
isolate_group->ForEachIsolate(
|
||||
[&](Isolate* isolate) {
|
||||
auto mutator_thread = isolate->mutator_thread();
|
||||
if (mutator_thread == nullptr) {
|
||||
return;
|
||||
}
|
||||
DartFrameIterator iterator(
|
||||
mutator_thread, StackFrameIterator::kAllowCrossThreadIteration);
|
||||
StackFrame* frame = iterator.NextFrame();
|
||||
|
|
|
@ -1420,6 +1420,9 @@ void ProgramReloadContext::EnsuredUnoptimizedCodeForStack() {
|
|||
|
||||
IG->ForEachIsolate([](Isolate* isolate) {
|
||||
auto thread = isolate->mutator_thread();
|
||||
if (thread == nullptr) {
|
||||
return;
|
||||
}
|
||||
StackFrameIterator it(ValidationPolicy::kDontValidateFrames, thread,
|
||||
StackFrameIterator::kAllowCrossThreadIteration);
|
||||
|
||||
|
@ -1996,6 +1999,9 @@ void ProgramReloadContext::ResetUnoptimizedICsOnStack() {
|
|||
CallSiteResetter resetter(zone);
|
||||
|
||||
IG->ForEachIsolate([&](Isolate* isolate) {
|
||||
if (isolate->mutator_thread() == nullptr) {
|
||||
return;
|
||||
}
|
||||
DartFrameIterator iterator(isolate->mutator_thread(),
|
||||
StackFrameIterator::kAllowCrossThreadIteration);
|
||||
StackFrame* frame = iterator.NextFrame();
|
||||
|
|
|
@ -3307,6 +3307,9 @@ void DeoptimizeFunctionsOnStack() {
|
|||
isolate_group->ForEachIsolate(
|
||||
[&](Isolate* isolate) {
|
||||
auto mutator_thread = isolate->mutator_thread();
|
||||
if (mutator_thread == nullptr) {
|
||||
return;
|
||||
}
|
||||
DartFrameIterator iterator(
|
||||
mutator_thread, StackFrameIterator::kAllowCrossThreadIteration);
|
||||
StackFrame* frame = iterator.NextFrame();
|
||||
|
@ -3332,6 +3335,9 @@ static void DeoptimizeLastDartFrameIfOptimized() {
|
|||
auto isolate_group = thread->isolate_group();
|
||||
isolate_group->RunWithStoppedMutators([&]() {
|
||||
auto mutator_thread = isolate->mutator_thread();
|
||||
if (mutator_thread == nullptr) {
|
||||
return;
|
||||
}
|
||||
DartFrameIterator iterator(mutator_thread,
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
StackFrame* frame = iterator.NextFrame();
|
||||
|
|
|
@ -412,6 +412,22 @@ bool Thread::EnterIsolate(Isolate* isolate) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool ShouldSuspend(bool isolate_shutdown, Thread* thread) {
|
||||
// Must destroy thread.
|
||||
if (isolate_shutdown) return false;
|
||||
|
||||
// Must retain thread.
|
||||
if (thread->HasActiveState() || thread->OwnsSafepoint()) return true;
|
||||
|
||||
// Could do either. When there are few isolates suspend to avoid work
|
||||
// entering and leaving. When there are many isolate, destroy the thread to
|
||||
// avoid the root set growing too big.
|
||||
const intptr_t kMaxSuspendedThreads = 20;
|
||||
auto group = thread->isolate_group();
|
||||
return group->thread_registry()->active_isolates_count() <
|
||||
kMaxSuspendedThreads;
|
||||
}
|
||||
|
||||
void Thread::ExitIsolate(bool isolate_shutdown) {
|
||||
Thread* thread = Thread::Current();
|
||||
ASSERT(thread != nullptr);
|
||||
|
@ -438,11 +454,8 @@ void Thread::ExitIsolate(bool isolate_shutdown) {
|
|||
// makes entering/exiting quite fast as it mainly boils down to safepoint
|
||||
// transitions. Though any operation that walks over all active threads will
|
||||
// see this thread as well (e.g. safepoint operations).
|
||||
//
|
||||
// We could safely use `suspend = !HasActiveState()` here instead and may
|
||||
// consider doing so e.g. if the number of isolates is very large.
|
||||
const bool suspend = !isolate_shutdown;
|
||||
if (suspend) {
|
||||
const bool is_nested_exit = thread->top_exit_frame_info() != 0;
|
||||
if (ShouldSuspend(isolate_shutdown, thread)) {
|
||||
const auto tag =
|
||||
isolate->is_runnable() ? VMTag::kIdleTagId : VMTag::kLoadWaitTagId;
|
||||
SuspendThreadInternal(thread, tag);
|
||||
|
@ -462,7 +475,6 @@ void Thread::ExitIsolate(bool isolate_shutdown) {
|
|||
|
||||
// To let VM's thread pool (if we run on it) know that this thread is
|
||||
// occupying a mutator again (decreases its max size).
|
||||
const bool is_nested_exit = thread->top_exit_frame_info() != 0;
|
||||
ASSERT(!(isolate_shutdown && is_nested_exit));
|
||||
group->DecreaseMutatorCount(isolate, is_nested_exit);
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ void ThreadRegistry::AddToActiveListLocked(Thread* thread) {
|
|||
ASSERT(threads_lock()->IsOwnedByCurrentThread());
|
||||
thread->next_ = active_list_;
|
||||
active_list_ = thread;
|
||||
active_isolates_count_.fetch_add(1);
|
||||
}
|
||||
|
||||
void ThreadRegistry::RemoveFromActiveListLocked(Thread* thread) {
|
||||
|
@ -124,6 +125,7 @@ void ThreadRegistry::RemoveFromActiveListLocked(Thread* thread) {
|
|||
} else {
|
||||
prev->next_ = current->next_;
|
||||
}
|
||||
active_isolates_count_.fetch_sub(1);
|
||||
break;
|
||||
}
|
||||
prev = current;
|
||||
|
|
|
@ -19,11 +19,14 @@ class JSONStream;
|
|||
class JSONArray;
|
||||
#endif
|
||||
|
||||
// Unordered collection of threads relating to a particular isolate.
|
||||
// Unordered collection of threads relating to a particular isolate group.
|
||||
class ThreadRegistry {
|
||||
public:
|
||||
ThreadRegistry()
|
||||
: threads_lock_(), active_list_(nullptr), free_list_(nullptr) {}
|
||||
: threads_lock_(),
|
||||
active_list_(nullptr),
|
||||
free_list_(nullptr),
|
||||
active_isolates_count_(0) {}
|
||||
~ThreadRegistry();
|
||||
|
||||
void VisitObjectPointers(IsolateGroup* isolate_group_of_interest,
|
||||
|
@ -35,6 +38,9 @@ class ThreadRegistry {
|
|||
void AcquireMarkingStacks();
|
||||
void ReleaseMarkingStacks();
|
||||
|
||||
// Concurrent-approximate number of active isolates in the active_list
|
||||
intptr_t active_isolates_count() { return active_isolates_count_.load(); }
|
||||
|
||||
Monitor* threads_lock() const { return &threads_lock_; }
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -56,6 +62,7 @@ class ThreadRegistry {
|
|||
mutable Monitor threads_lock_;
|
||||
Thread* active_list_; // List of active threads in the isolate.
|
||||
Thread* free_list_; // Free list of Thread objects that can be reused.
|
||||
RelaxedAtomic<intptr_t> active_isolates_count_;
|
||||
|
||||
friend class Thread;
|
||||
friend class SafepointHandler;
|
||||
|
|
Loading…
Reference in a new issue