Chromium Code Reviews| Index: runtime/vm/thread_registry.cc |
| diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6543397eb85f1aee400b1b9c89add953676f7b44 |
| --- /dev/null |
| +++ b/runtime/vm/thread_registry.cc |
| @@ -0,0 +1,82 @@ |
| +// 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::SafepointAllThreads() { |
| + MonitorLocker ml(monitor_); |
| + // First wait for any older rounds that are still in progress. |
| + while (in_rendezvous_) { |
| + CheckSafepointLocked(); |
| + } |
| + // Start a new round. |
| + in_rendezvous_ = true; |
| + ++round_; |
| + 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 (Thread::Current() != isolate->mutator_thread()) { |
| + isolate->ScheduleInterrupts(Isolate::kSafepointInterrrupt); |
|
Ivan Posva
2015/07/31 20:28:09
Talk like a pirate constants?
koda
2015/07/31 22:40:44
Rrrenamed to 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(); |
|
Ivan Posva
2015/07/31 20:28:09
Having to use NotifyAll generally points at some p
koda
2015/07/31 22:40:44
I agree that it is inelegant that they all wake up
|
| + } |
| + } |
| + 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 SafepointAllThreads 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 |