| Index: runtime/vm/safepoint.cc
|
| diff --git a/runtime/vm/safepoint.cc b/runtime/vm/safepoint.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..47ef2576ef6b6b9ff277887e7f72d61f2d046363
|
| --- /dev/null
|
| +++ b/runtime/vm/safepoint.cc
|
| @@ -0,0 +1,174 @@
|
| +// Copyright (c) 2016, 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/safepoint.h"
|
| +
|
| +#include "vm/thread.h"
|
| +#include "vm/thread_registry.h"
|
| +
|
| +namespace dart {
|
| +
|
| +SafepointOperationScope::SafepointOperationScope(Thread* T) : StackResource(T) {
|
| + ASSERT(T != NULL);
|
| + Isolate* I = T->isolate();
|
| + ASSERT(I != NULL);
|
| + ASSERT(T->no_safepoint_scope_depth() == 0);
|
| +
|
| + SafepointHandler* handler = I->safepoint_handler();
|
| + ASSERT(handler != NULL);
|
| +
|
| + // Signal all threads to get to a safepoint and wait for them to
|
| + // get to a safepoint.
|
| + handler->SafepointThreads(T);
|
| +}
|
| +
|
| +
|
| +SafepointOperationScope::~SafepointOperationScope() {
|
| + Thread* T = thread();
|
| + ASSERT(T != NULL);
|
| + Isolate* I = T->isolate();
|
| + ASSERT(I != NULL);
|
| +
|
| + // Resume all threads which are blocked for the safepoint operation.
|
| + SafepointHandler* handler = I->safepoint_handler();
|
| + ASSERT(handler != NULL);
|
| + handler->ResumeThreads(T);
|
| +}
|
| +
|
| +
|
| +SafepointHandler::SafepointHandler(Isolate* isolate)
|
| + : isolate_(isolate),
|
| + safepoint_lock_(new Monitor()),
|
| + number_threads_not_at_safepoint_(0),
|
| + safepoint_in_progress_(false) {
|
| +}
|
| +
|
| +
|
| +SafepointHandler::~SafepointHandler() {
|
| + ASSERT(safepoint_in_progress_ == false);
|
| + delete safepoint_lock_;
|
| + safepoint_lock_ = NULL;
|
| + isolate_ = NULL;
|
| +}
|
| +
|
| +
|
| +void SafepointHandler::SafepointThreads(Thread* T) {
|
| + {
|
| + // First grab the threads list lock for this isolate
|
| + // and check if a safepoint is already in progress. This
|
| + // ensures that two threads do not start a safepoint operation
|
| + // at the same time.
|
| + MonitorLocker sl(threads_lock());
|
| +
|
| + // Now check to see if a safepoint operation is already in progress
|
| + // for this isolate, block if an operation is in progress.
|
| + while (safepoint_in_progress()) {
|
| + sl.WaitWithSafepointCheck(T);
|
| + }
|
| +
|
| + // Set safepoint in progress by this thread.
|
| + set_safepoint_in_progress(true);
|
| +
|
| + // Go over the active thread list and ensure that all threads active
|
| + // in the isolate reach a safepoint.
|
| + Thread* current = isolate()->thread_registry()->active_list();
|
| + while (current != NULL) {
|
| + MonitorLocker tl(current->thread_lock());
|
| + if (current != T) {
|
| + uint32_t state = current->SetSafepointRequested(true);
|
| + if (!Thread::IsAtSafepoint(state)) {
|
| + // Thread is not already at a safepoint so try to
|
| + // get it to a safepoint and wait for it to check in.
|
| + if (current->IsMutatorThread()) {
|
| + ASSERT(T->isolate() != NULL);
|
| + T->isolate()->ScheduleInterrupts(Isolate::kVMInterrupt);
|
| + }
|
| + MonitorLocker sl(safepoint_lock_);
|
| + ++number_threads_not_at_safepoint_;
|
| + }
|
| + } else {
|
| + current->SetAtSafepoint(true);
|
| + }
|
| + current = current->next();
|
| + }
|
| + }
|
| + // Now wait for all threads that are not already at a safepoint to check-in.
|
| + {
|
| + MonitorLocker sl(safepoint_lock_);
|
| + while (number_threads_not_at_safepoint_ > 0) {
|
| + sl.Wait();
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafepointHandler::ResumeThreads(Thread* T) {
|
| + // First resume all the threads which are blocked for the safepoint
|
| + // operation.
|
| + MonitorLocker sl(threads_lock());
|
| + Thread* current = isolate()->thread_registry()->active_list();
|
| + while (current != NULL) {
|
| + MonitorLocker tl(current->thread_lock());
|
| + if (current != T) {
|
| + uint32_t state = current->SetSafepointRequested(false);
|
| + if (Thread::IsBlockedForSafepoint(state)) {
|
| + tl.Notify();
|
| + }
|
| + } else {
|
| + current->SetAtSafepoint(false);
|
| + }
|
| + current = current->next();
|
| + }
|
| + // Now set the safepoint_in_progress_ flag to false and notify all threads
|
| + // that are waiting to enter the isolate or waiting to start another
|
| + // safepoint operation.
|
| + set_safepoint_in_progress(false);
|
| + sl.NotifyAll();
|
| +}
|
| +
|
| +
|
| +void SafepointHandler::EnterSafepointUsingLock(Thread* T) {
|
| + MonitorLocker tl(T->thread_lock());
|
| + T->SetAtSafepoint(true);
|
| + if (T->IsSafepointRequested()) {
|
| + MonitorLocker sl(safepoint_lock_);
|
| + ASSERT(number_threads_not_at_safepoint_ > 0);
|
| + number_threads_not_at_safepoint_ -= 1;
|
| + sl.Notify();
|
| + }
|
| +}
|
| +
|
| +
|
| +void SafepointHandler::ExitSafepointUsingLock(Thread* T) {
|
| + MonitorLocker tl(T->thread_lock());
|
| + ASSERT(T->IsAtSafepoint());
|
| + while (T->IsSafepointRequested()) {
|
| + T->SetBlockedForSafepoint(true);
|
| + tl.Wait();
|
| + T->SetBlockedForSafepoint(false);
|
| + }
|
| + T->SetAtSafepoint(false);
|
| +}
|
| +
|
| +
|
| +void SafepointHandler::BlockForSafepoint(Thread* T) {
|
| + MonitorLocker tl(T->thread_lock());
|
| + if (T->IsSafepointRequested()) {
|
| + T->SetAtSafepoint(true);
|
| + {
|
| + MonitorLocker sl(safepoint_lock_);
|
| + ASSERT(number_threads_not_at_safepoint_ > 0);
|
| + number_threads_not_at_safepoint_ -= 1;
|
| + sl.Notify();
|
| + }
|
| + while (T->IsSafepointRequested()) {
|
| + T->SetBlockedForSafepoint(true);
|
| + tl.Wait();
|
| + T->SetBlockedForSafepoint(false);
|
| + }
|
| + T->SetAtSafepoint(false);
|
| + }
|
| +}
|
| +
|
| +} // namespace dart
|
|
|