Index: runtime/vm/thread.h |
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h |
index ad073afba47f266280bd45b41e6c2738ab110206..2f1b4dff014ca3495615400ff215f69fc1fe7084 100644 |
--- a/runtime/vm/thread.h |
+++ b/runtime/vm/thread.h |
@@ -6,6 +6,9 @@ |
#define VM_THREAD_H_ |
#include "include/dart_api.h" |
+#include "platform/assert.h" |
+#include "vm/atomic.h" |
+#include "vm/bitfield.h" |
#include "vm/globals.h" |
#include "vm/handles.h" |
#include "vm/os_thread.h" |
@@ -143,6 +146,9 @@ class Thread : public BaseThread { |
os_thread_ = os_thread; |
} |
+ // Monitor corresponding to this thread. |
+ Monitor* thread_lock() const { return thread_lock_; } |
+ |
// The topmost zone used for allocation in this thread. |
Zone* zone() const { return zone_; } |
@@ -209,7 +215,9 @@ class Thread : public BaseThread { |
return OFFSET_OF(Thread, store_buffer_block_); |
} |
- uword top_exit_frame_info() const { return top_exit_frame_info_; } |
+ uword top_exit_frame_info() const { |
+ return top_exit_frame_info_; |
+ } |
static intptr_t top_exit_frame_info_offset() { |
return OFFSET_OF(Thread, top_exit_frame_info_); |
} |
@@ -356,6 +364,8 @@ LEAF_RUNTIME_ENTRY_LIST(DEFINE_OFFSET_METHOD) |
return OFFSET_OF(Thread, vm_tag_); |
} |
+ RawGrowableObjectArray* pending_functions(); |
+ |
#if defined(DEBUG) |
#define REUSABLE_HANDLE_SCOPE_ACCESSORS(object) \ |
void set_reusable_##object##_handle_scope_active(bool value) { \ |
@@ -385,7 +395,120 @@ LEAF_RUNTIME_ENTRY_LIST(DEFINE_OFFSET_METHOD) |
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE) |
#undef REUSABLE_HANDLE |
- RawGrowableObjectArray* pending_functions(); |
+ /* |
+ * Fields used to support safepointing a thread. |
+ * |
+ * - Bit 0 of the safepoint_state_ field is used to indicate if the thread is |
+ * already at a safepoint, |
+ * - Bit 1 of the safepoint_state_ field is used to indicate if a safepoint |
+ * operation is requested for this thread. |
+ * - Bit 2 of the safepoint_state_ field is used to indicate that the thread |
+ * is blocked for the safepoint operation to complete. |
+ * |
+ * The safepoint execution state (described above) for a thread is stored in |
+ * in the execution_state_ field. |
+ * Potential execution states a thread could be in: |
+ * kThreadInGenerated - The thread is running jitted dart/stub code. |
+ * kThreadInVM - The thread is running VM code. |
+ * kThreadInNative - The thread is running native code. |
+ * kThreadInBlockedState - The thread is blocked waiting for a resource. |
+ */ |
+ static intptr_t safepoint_state_offset() { |
+ return OFFSET_OF(Thread, safepoint_state_); |
+ } |
+ static bool IsAtSafepoint(uint32_t state) { |
+ return AtSafepointField::decode(state); |
+ } |
+ bool IsAtSafepoint() const { |
+ return AtSafepointField::decode(safepoint_state_); |
+ } |
+ static uint32_t SetAtSafepoint(bool value, uint32_t state) { |
+ return AtSafepointField::update(value, state); |
+ } |
+ void SetAtSafepoint(bool value) { |
+ ASSERT(thread_lock()->IsOwnedByCurrentThread()); |
+ safepoint_state_ = AtSafepointField::update(value, safepoint_state_); |
+ } |
+ bool IsSafepointRequested() const { |
+ return SafepointRequestedField::decode(safepoint_state_); |
+ } |
+ static uint32_t SetSafepointRequested(bool value, uint32_t state) { |
+ return SafepointRequestedField::update(value, state); |
+ } |
+ uint32_t SetSafepointRequested(bool value) { |
+ ASSERT(thread_lock()->IsOwnedByCurrentThread()); |
+ uint32_t old_state; |
+ uint32_t new_state; |
+ do { |
+ old_state = safepoint_state_; |
+ new_state = SafepointRequestedField::update(value, old_state); |
+ } while (AtomicOperations::CompareAndSwapUint32(&safepoint_state_, |
+ old_state, |
+ new_state) != old_state); |
+ return old_state; |
+ } |
+ static bool IsBlockedForSafepoint(uint32_t state) { |
+ return BlockedForSafepointField::decode(state); |
+ } |
+ bool IsBlockedForSafepoint() const { |
+ return BlockedForSafepointField::decode(safepoint_state_); |
+ } |
+ void SetBlockedForSafepoint(bool value) { |
+ ASSERT(thread_lock()->IsOwnedByCurrentThread()); |
+ safepoint_state_ = |
+ BlockedForSafepointField::update(value, safepoint_state_); |
+ } |
+ |
+ enum ExecutionState { |
+ kThreadInVM = 0, |
+ kThreadInGenerated, |
+ kThreadInNative, |
+ kThreadInBlockedState |
+ }; |
+ |
+ ExecutionState execution_state() const { |
+ return static_cast<ExecutionState>(execution_state_); |
+ } |
+ void set_execution_state(ExecutionState state) { |
+ execution_state_ = static_cast<uint32_t>(state); |
+ } |
+ static intptr_t execution_state_offset() { |
+ return OFFSET_OF(Thread, execution_state_); |
+ } |
+ |
+ void EnterSafepoint() { |
+ // First try a fast update of the thread state to indicate it is at a |
+ // safepoint. |
+ uint32_t new_state = SetAtSafepoint(true, 0); |
+ uword addr = reinterpret_cast<uword>(this) + safepoint_state_offset(); |
+ if (AtomicOperations::CompareAndSwapUint32( |
+ reinterpret_cast<uint32_t*>(addr), 0, new_state) != 0) { |
+ // Fast update failed which means we could potentially be in the middle |
+ // of a safepoint operation. |
+ EnterSafepointUsingLock(); |
+ } |
+ } |
+ |
+ void ExitSafepoint() { |
+ // First try a fast update of the thread state to indicate it is not at a |
+ // safepoint anymore. |
+ uint32_t old_state = SetAtSafepoint(true, 0); |
+ uword addr = reinterpret_cast<uword>(this) + safepoint_state_offset(); |
+ if (AtomicOperations::CompareAndSwapUint32( |
+ reinterpret_cast<uint32_t*>(addr), old_state, 0) != old_state) { |
+ // Fast update failed which means we could potentially be in the middle |
+ // of a safepoint operation. |
+ ExitSafepointUsingLock(); |
+ } |
+ } |
+ |
+ void CheckForSafepoint() { |
+ if (IsSafepointRequested()) { |
+ BlockForSafepoint(); |
+ } |
+ } |
+ |
+ Thread* next() const { return next_; } |
// Visit all object pointers. |
void VisitObjectPointers(ObjectPointerVisitor* visitor); |
@@ -401,6 +524,7 @@ LEAF_RUNTIME_ENTRY_LIST(DEFINE_OFFSET_METHOD) |
template<class T> T* AllocateReusableHandle(); |
OSThread* os_thread_; |
+ Monitor* thread_lock_; |
Isolate* isolate_; |
Heap* heap_; |
Zone* zone_; |
@@ -453,6 +577,12 @@ LEAF_RUNTIME_ENTRY_LIST(DECLARE_MEMBERS) |
#undef REUSABLE_HANDLE_SCOPE_VARIABLE |
#endif // defined(DEBUG) |
+ class AtSafepointField : public BitField<bool, 0, 1> {}; |
+ class SafepointRequestedField : public BitField<bool, 1, 1> {}; |
+ class BlockedForSafepointField : public BitField<bool, 2, 1> {}; |
+ uint32_t safepoint_state_; |
+ uint32_t execution_state_; |
+ |
Thread* next_; // Used to chain the thread structures in an isolate. |
explicit Thread(Isolate* isolate); |
@@ -469,6 +599,13 @@ LEAF_RUNTIME_ENTRY_LIST(DECLARE_MEMBERS) |
top_exit_frame_info_ = top_exit_frame_info; |
} |
+ void set_safepoint_state(uint32_t value) { |
+ safepoint_state_ = value; |
+ } |
+ void EnterSafepointUsingLock(); |
+ void ExitSafepointUsingLock(); |
+ void BlockForSafepoint(); |
+ |
static void SetCurrent(Thread* current) { |
OSThread::SetCurrentTLS(reinterpret_cast<uword>(current)); |
} |