7d82391e89
Unsynchronized access to the contents of another thread is dangerous, even for just ASSERTs, as shown by issue 23958. Verify the bidirectional Isolate<->Thread pointer invariant when *setting* the mutator_thread_ field, and limit the interface to comparisons with NULL and the current thread. BUG=https://github.com/dart-lang/sdk/issues/23958 R=johnmccutchan@google.com Review URL: https://codereview.chromium.org//1260283007 .
85 lines
2.7 KiB
C++
85 lines
2.7 KiB
C++
// Copyright (c) 2015, 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.
|
|
|
|
#include "vm/thread_registry.h"
|
|
|
|
#include "vm/isolate.h"
|
|
#include "vm/lockers.h"
|
|
|
|
namespace dart {
|
|
|
|
void ThreadRegistry::SafepointThreads() {
|
|
MonitorLocker ml(monitor_);
|
|
// First wait for any older rounds that are still in progress.
|
|
while (in_rendezvous_) {
|
|
// Assert we are not the organizer trying to nest calls to SafepointThreads.
|
|
ASSERT(remaining_ > 0);
|
|
CheckSafepointLocked();
|
|
}
|
|
// Start a new round.
|
|
in_rendezvous_ = true;
|
|
++round_; // Overflows after 240+ years @ 10^9 safepoints per second.
|
|
remaining_ = CountScheduledLocked();
|
|
Isolate* isolate = Isolate::Current();
|
|
// We only expect this method to be called from within the isolate itself.
|
|
ASSERT(isolate->thread_registry() == this);
|
|
// TODO(koda): Rename Thread::PrepareForGC and call it here?
|
|
--remaining_; // Exclude this thread from the count.
|
|
// Ensure the main mutator will reach a safepoint (could be running Dart).
|
|
if (!isolate->MutatorThreadIsCurrentThread()) {
|
|
isolate->ScheduleInterrupts(Isolate::kVMInterrupt);
|
|
}
|
|
while (remaining_ > 0) {
|
|
ml.Wait(Monitor::kNoTimeout);
|
|
}
|
|
}
|
|
|
|
|
|
void ThreadRegistry::ResumeAllThreads() {
|
|
MonitorLocker ml(monitor_);
|
|
ASSERT(in_rendezvous_);
|
|
in_rendezvous_ = false;
|
|
ml.NotifyAll();
|
|
}
|
|
|
|
|
|
void ThreadRegistry::CheckSafepointLocked() {
|
|
int64_t last_round = -1;
|
|
while (in_rendezvous_) {
|
|
ASSERT(round_ >= last_round);
|
|
if (round_ != last_round) {
|
|
ASSERT((last_round == -1) || (round_ == (last_round + 1)));
|
|
last_round = round_;
|
|
// Participate in this round.
|
|
// TODO(koda): Rename Thread::PrepareForGC and call it here?
|
|
if (--remaining_ == 0) {
|
|
// Ensure the organizing thread is notified.
|
|
// TODO(koda): Use separate condition variables and plain 'Notify'.
|
|
monitor_->NotifyAll();
|
|
}
|
|
}
|
|
monitor_->Wait(Monitor::kNoTimeout);
|
|
// Note: Here, round_ is needed to detect and distinguish two cases:
|
|
// a) The old rendezvous is still in progress, so just keep waiting, or
|
|
// b) after ResumeAllThreads, another call to SafepointThreads was
|
|
// made before this thread got a chance to reaquire monitor_, thus this
|
|
// thread should (again) decrease remaining_ to indicate cooperation in
|
|
// this new round.
|
|
}
|
|
}
|
|
|
|
|
|
intptr_t ThreadRegistry::CountScheduledLocked() {
|
|
intptr_t count = 0;
|
|
for (int i = 0; i < entries_.length(); ++i) {
|
|
const Entry& entry = entries_[i];
|
|
if (entry.scheduled) {
|
|
++count;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
} // namespace dart
|