Chromium Code Reviews| Index: runtime/vm/safepoint.h |
| diff --git a/runtime/vm/safepoint.h b/runtime/vm/safepoint.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1c13a872f379371d8ea07cf0f64274b3df16b917 |
| --- /dev/null |
| +++ b/runtime/vm/safepoint.h |
| @@ -0,0 +1,328 @@ |
| +// 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. |
| + |
| +#ifndef VM_SAFEPOINT_H_ |
| +#define VM_SAFEPOINT_H_ |
| + |
| +#include "vm/globals.h" |
| +#include "vm/lockers.h" |
| +#include "vm/thread.h" |
| + |
| +namespace dart { |
| + |
| +// A stack based scope that can be used to perform an operation after getting |
| +// all threads to a safepoint. At the end of the operation all the threads are |
| +// resumed. |
| +class SafepointOperationScope : public StackResource { |
| + public: |
| + explicit SafepointOperationScope(Thread* T); |
| + ~SafepointOperationScope(); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope); |
| +}; |
| + |
| + |
| +// Implements handling of safepoint operations for all threads in an Isolate. |
| +class SafepointHandler { |
| + public: |
| + explicit SafepointHandler(Isolate* I); |
| + ~SafepointHandler(); |
| + |
| + void EnterSafepointUsingLock(Thread* T); |
| + void ExitSafepointUsingLock(Thread* T); |
| + |
| + void SafepointThreads(Thread* T); |
| + void ResumeThreads(Thread* T); |
| + |
| + void BlockForSafepoint(Thread* T); |
| + |
| + private: |
| + Isolate* isolate() const { return isolate_; } |
| + Monitor* threads_lock() const { return isolate_->threads_lock(); } |
| + bool safepoint_in_progress() const { |
| + ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| + return safepoint_in_progress_; |
| + } |
| + void set_safepoint_in_progress(bool value) { |
| + ASSERT(threads_lock()->IsOwnedByCurrentThread()); |
| + safepoint_in_progress_ = value; |
| + } |
| + |
| + Isolate* isolate_; |
| + |
| + // Monitor used by thread initiating a safepoint operation to track threads |
| + // not at a safepoint and wait for these threads to reach a safepoint. |
| + Monitor* safepoint_lock_; |
| + int32_t number_threads_not_at_safepoint_; |
| + |
| + // Flag to indicate if a safepoint operation is currently in progress. |
| + bool safepoint_in_progress_; |
| + |
| + friend class Isolate; |
| + friend class SafepointOperationScope; |
| +}; |
| + |
| + |
| +/* |
| + * Set of StackResource classes to track thread execution state transitions: |
| + * |
| + * kThreadInGenerated transitioning to |
| + * ==> kThreadInVM: |
| + * - set_execution_state(kThreadInVM). |
| + * - block if safepoint is requested. |
| + * ==> kThreadInNative: |
| + * - set_execution_state(kThreadInNative). |
| + * - EnterSafepoint(). |
| + * ==> kThreadInBlockedState: |
| + * - Invalid transition |
| + * |
| + * kThreadInVM transitioning to |
| + * ==> kThreadInGenerated |
| + * - set_execution_state(kThreadInGenerated). |
| + * ==> kThreadInNative |
| + * - set_execution_state(kThreadInNative). |
| + * - EnterSafepoint. |
| + * ==> kThreadInBlockedState |
| + * - set_execution_state(kThreadInBlockedState). |
| + * - EnterSafepoint. |
| + * |
| + * kThreadInNative transitioning to |
| + * ==> kThreadInGenerated |
| + * - ExitSafepoint. |
| + * - set_execution_state(kThreadInGenerated). |
| + * ==> kThreadInVM |
| + * - ExitSafepoint. |
| + * - set_execution_state(kThreadInVM). |
| + * ==> kThreadInBlocked |
| + * - Invalid transition. |
| + * |
| + * kThreadInBlocked transitioning to |
| + * ==> kThreadInVM |
| + * - ExitSafepoint. |
| + * - set_execution_state(kThreadInVM). |
| + * ==> kThreadInNative |
| + * - Invalid transition. |
| + * ==> kThreadInGenerated |
| + * - Invalid transition. |
| + */ |
| +class TransitionSafepointState : public StackResource { |
| + public: |
| + explicit TransitionSafepointState(Thread* T) : StackResource(T) {} |
| + ~TransitionSafepointState() {} |
|
zra
2016/01/13 22:16:13
Does this destructor need to be virtual?
siva
2016/01/27 19:07:50
There are no virtual methods in any of the subclas
|
| + |
| + SafepointHandler* handler() const { |
| + ASSERT(thread()->isolate() != NULL); |
| + ASSERT(thread()->isolate()->safepoint_handler() != NULL); |
| + return thread()->isolate()->safepoint_handler(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState); |
| +}; |
| + |
| + |
| +// TransitionGeneratedToVM is used to transition the safepoint state of a |
| +// thread from "running generated code" to "running vm code" and ensures |
| +// that the state is reverted back to "running generated code" when |
| +// exiting the scope/frame. |
| +class TransitionGeneratedToVM : public TransitionSafepointState { |
| + public: |
| + explicit TransitionGeneratedToVM(Thread* T) : TransitionSafepointState(T) { |
| + ASSERT(T == Thread::Current()); |
| + ASSERT(T->execution_state() == Thread::kThreadInGenerated); |
| + T->set_execution_state(Thread::kThreadInVM); |
| + // Fast check to see if a safepoint is requested or not. |
| + // We do the more expensive operation of blocking the thread |
| + // only if a safepoint is requested. |
| + if (T->IsSafepointRequested()) { |
| + handler()->BlockForSafepoint(T); |
| + } |
| + } |
| + |
| + ~TransitionGeneratedToVM() { |
| + ASSERT(thread()->execution_state() == Thread::kThreadInVM); |
| + thread()->set_execution_state(Thread::kThreadInGenerated); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM); |
| +}; |
| + |
| + |
| +// TransitionGeneratedToNative is used to transition the safepoint state of a |
| +// thread from "running generated code" to "running native code" and ensures |
| +// that the state is reverted back to "running generated code" when |
| +// exiting the scope/frame. |
| +class TransitionGeneratedToNative : public TransitionSafepointState { |
| + public: |
| + explicit TransitionGeneratedToNative(Thread* T) |
| + : TransitionSafepointState(T) { |
| + // Native code is considered to be at a safepoint and so we mark it |
| + // accordingly. |
| + ASSERT(T->execution_state() == Thread::kThreadInGenerated); |
| + T->set_execution_state(Thread::kThreadInNative); |
| + T->EnterSafepoint(); |
| + } |
| + |
| + ~TransitionGeneratedToNative() { |
| + // We are returning to generated code and so we are not at a safepoint |
| + // anymore. |
| + ASSERT(thread()->execution_state() == Thread::kThreadInNative); |
| + thread()->ExitSafepoint(); |
| + thread()->set_execution_state(Thread::kThreadInGenerated); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative); |
| +}; |
| + |
| + |
| +// TransitionVMToBlocked is used to transition the safepoint state of a |
| +// thread from "running vm code" to "blocked on a monitor" and ensures |
| +// that the state is reverted back to "running vm code" when |
| +// exiting the scope/frame. |
| +class TransitionVMToBlocked : public TransitionSafepointState { |
| + public: |
| + explicit TransitionVMToBlocked(Thread* T) : TransitionSafepointState(T) { |
| + // A thread blocked on a monitor is considered to be at a safepoint. |
| + ASSERT(T->execution_state() == Thread::kThreadInVM); |
| + T->set_execution_state(Thread::kThreadInBlockedState); |
| + T->EnterSafepoint(); |
| + } |
| + |
| + ~TransitionVMToBlocked() { |
| + // We are returning to vm code and so we are not at a safepoint anymore. |
| + ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState); |
| + thread()->ExitSafepoint(); |
| + thread()->set_execution_state(Thread::kThreadInVM); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked); |
| +}; |
| + |
| + |
| +// TransitionVMToNative is used to transition the safepoint state of a |
| +// thread from "running vm code" to "running native code" and ensures |
| +// that the state is reverted back to "running vm code" when |
| +// exiting the scope/frame. |
| +class TransitionVMToNative : public TransitionSafepointState { |
| + public: |
| + explicit TransitionVMToNative(Thread* T) : TransitionSafepointState(T) { |
| + // A thread running native code is considered to be at a safepoint. |
| + ASSERT(T->execution_state() == Thread::kThreadInVM); |
| + T->set_execution_state(Thread::kThreadInNative); |
| + T->EnterSafepoint(); |
| + } |
| + |
| + ~TransitionVMToNative() { |
| + // We are returning to vm code and so we are not at a safepoint anymore. |
| + ASSERT(thread()->execution_state() == Thread::kThreadInNative); |
| + thread()->ExitSafepoint(); |
| + thread()->set_execution_state(Thread::kThreadInVM); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative); |
| +}; |
| + |
| + |
| +// TransitionVMToGenerated is used to transition the safepoint state of a |
| +// thread from "running vm code" to "running generated code" and ensures |
| +// that the state is reverted back to "running vm code" when |
| +// exiting the scope/frame. |
| +class TransitionVMToGenerated : public TransitionSafepointState { |
| + public: |
| + explicit TransitionVMToGenerated(Thread* T) : TransitionSafepointState(T) { |
| + ASSERT(T == Thread::Current()); |
| + ASSERT(T->execution_state() == Thread::kThreadInVM); |
| + T->set_execution_state(Thread::kThreadInGenerated); |
| + } |
| + |
| + ~TransitionVMToGenerated() { |
| + ASSERT(thread()->execution_state() == Thread::kThreadInGenerated); |
| + thread()->set_execution_state(Thread::kThreadInVM); |
| + // Fast check to see if a safepoint is requested or not. |
| + // We do the more expensive operation of blocking the thread |
| + // only if a safepoint is requested. |
| + if (thread()->IsSafepointRequested()) { |
| + handler()->BlockForSafepoint(thread()); |
| + } |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated); |
| +}; |
| + |
| + |
| +// TransitionNativeToVM is used to transition the safepoint state of a |
| +// thread from "running native code" to "running vm code" and ensures |
| +// that the state is reverted back to "running native code" when |
| +// exiting the scope/frame. |
| +class TransitionNativeToVM : public TransitionSafepointState { |
| + public: |
| + explicit TransitionNativeToVM(Thread* T) : TransitionSafepointState(T) { |
| + // We are about to execute vm code and so we are not at a safepoint anymore. |
| + ASSERT(T->execution_state() == Thread::kThreadInNative); |
| + T->ExitSafepoint(); |
| + T->set_execution_state(Thread::kThreadInVM); |
| + } |
| + |
| + ~TransitionNativeToVM() { |
| + // We are returning to native code and so we are at a safepoint. |
| + ASSERT(thread()->execution_state() == Thread::kThreadInVM); |
| + thread()->set_execution_state(Thread::kThreadInNative); |
| + thread()->EnterSafepoint(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM); |
| +}; |
| + |
| + |
| +// TransitionToGenerated is used to transition the safepoint state of a |
| +// thread from "running vm code" or "running native code" to |
| +// "running generated code" and ensures that the state is reverted back |
| +// to "running vm code" or "running native code" when exiting the |
| +// scope/frame. |
| +class TransitionToGenerated : public TransitionSafepointState { |
| + public: |
| + explicit TransitionToGenerated(Thread* T) |
| + : TransitionSafepointState(T), |
| + execution_state_(T->execution_state()) { |
| + ASSERT(T == Thread::Current()); |
| + ASSERT((execution_state_ == Thread::kThreadInVM) || |
| + (execution_state_ == Thread::kThreadInNative)); |
| + if (execution_state_ == Thread::kThreadInNative) { |
| + T->ExitSafepoint(); |
| + } |
| + T->set_execution_state(Thread::kThreadInGenerated); |
| + } |
| + |
| + ~TransitionToGenerated() { |
| + ASSERT(thread()->execution_state() == Thread::kThreadInGenerated); |
| + if (execution_state_ == Thread::kThreadInNative) { |
| + thread()->set_execution_state(Thread::kThreadInNative); |
| + thread()->EnterSafepoint(); |
| + } else { |
| + ASSERT(execution_state_ == Thread::kThreadInVM); |
| + thread()->set_execution_state(Thread::kThreadInVM); |
| + // Fast check to see if a safepoint is requested or not. |
| + // We do the more expensive operation of blocking the thread |
| + // only if a safepoint is requested. |
| + if (thread()->IsSafepointRequested()) { |
| + handler()->BlockForSafepoint(thread()); |
| + } |
| + } |
| + } |
| + |
| + private: |
| + int16_t execution_state_; |
| + DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated); |
| +}; |
| + |
| +} // namespace dart |
| + |
| +#endif // VM_SAFEPOINT_H_ |