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() {} |
+ |
+ 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_ |