Index: runtime/vm/thread.cc |
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc |
index 0d8493798217b5bfd188bfadc6348a523b4e54b6..7bdcff11e4c03a9f6afc8431aa983ad334fecc8d 100644 |
--- a/runtime/vm/thread.cc |
+++ b/runtime/vm/thread.cc |
@@ -20,183 +20,9 @@ |
namespace dart { |
-// The single thread local key which stores all the thread local data |
-// for a thread. |
-ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey; |
-Thread* Thread::thread_list_head_ = NULL; |
-Mutex* Thread::thread_list_lock_ = NULL; |
- |
-// Remove |thread| from each isolate's thread registry. |
-class ThreadPruner : public IsolateVisitor { |
- public: |
- explicit ThreadPruner(Thread* thread) |
- : thread_(thread) { |
- ASSERT(thread_ != NULL); |
- } |
- |
- void VisitIsolate(Isolate* isolate) { |
- ThreadRegistry* registry = isolate->thread_registry(); |
- ASSERT(registry != NULL); |
- registry->PruneThread(thread_); |
- } |
- private: |
- Thread* thread_; |
-}; |
- |
- |
-void Thread::AddThreadToList(Thread* thread) { |
- ASSERT(thread != NULL); |
- ASSERT(thread->isolate() == NULL); |
- ASSERT(thread_list_lock_ != NULL); |
- MutexLocker ml(thread_list_lock_); |
- |
- ASSERT(thread->thread_list_next_ == NULL); |
- |
-#if defined(DEBUG) |
- { |
- // Ensure that we aren't already in the list. |
- Thread* current = thread_list_head_; |
- while (current != NULL) { |
- ASSERT(current != thread); |
- current = current->thread_list_next_; |
- } |
- } |
-#endif |
- |
- // Insert at head of list. |
- thread->thread_list_next_ = thread_list_head_; |
- thread_list_head_ = thread; |
-} |
- |
- |
-void Thread::RemoveThreadFromList(Thread* thread) { |
- ASSERT(thread != NULL); |
- ASSERT(thread->isolate() == NULL); |
- ASSERT(thread_list_lock_ != NULL); |
- MutexLocker ml(thread_list_lock_); |
- |
- // Handle case where |thread| is head of list. |
- if (thread_list_head_ == thread) { |
- thread_list_head_ = thread->thread_list_next_; |
- thread->thread_list_next_ = NULL; |
- return; |
- } |
- |
- Thread* current = thread_list_head_; |
- Thread* previous = NULL; |
- |
- // Scan across list and remove |thread|. |
- while (current != NULL) { |
- previous = current; |
- current = current->thread_list_next_; |
- if (current == thread) { |
- // We found |thread|, remove from list. |
- previous->thread_list_next_ = current->thread_list_next_; |
- thread->thread_list_next_ = NULL; |
- return; |
- } |
- } |
- |
- UNREACHABLE(); |
-} |
- |
- |
-bool Thread::IsThreadInList(ThreadId join_id) { |
- if (join_id == OSThread::kInvalidThreadJoinId) { |
- return false; |
- } |
- ThreadIterator it; |
- while (it.HasNext()) { |
- Thread* t = it.Next(); |
- // An address test is not sufficient because the allocator may recycle |
- // the address for another Thread. Test against the thread's join id. |
- if (t->join_id() == join_id) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
- |
-static void DeleteThread(void* thread) { |
- delete reinterpret_cast<Thread*>(thread); |
-} |
- |
- |
-void Thread::Shutdown() { |
- if (thread_list_lock_ != NULL) { |
- // Delete the current thread. |
- Thread* thread = Current(); |
- ASSERT(thread != NULL); |
- delete thread; |
- thread = NULL; |
- SetCurrent(NULL); |
- |
- // Check that there are no more threads, then delete the lock. |
- { |
- MutexLocker ml(thread_list_lock_); |
- ASSERT(thread_list_head_ == NULL); |
- } |
- |
- // Clean up TLS. |
- OSThread::DeleteThreadLocal(thread_key_); |
- thread_key_ = OSThread::kUnsetThreadLocalKey; |
- |
- // Delete the thread list lock. |
- delete thread_list_lock_; |
- thread_list_lock_ = NULL; |
- } |
-} |
- |
- |
Thread::~Thread() { |
// We should cleanly exit any isolate before destruction. |
ASSERT(isolate_ == NULL); |
- // Clear |this| from all isolate's thread registry. |
- ThreadPruner pruner(this); |
- Isolate::VisitIsolates(&pruner); |
- delete log_; |
- log_ = NULL; |
- RemoveThreadFromList(this); |
-} |
- |
- |
-void Thread::InitOnceBeforeIsolate() { |
- ASSERT(thread_list_lock_ == NULL); |
- thread_list_lock_ = new Mutex(); |
- ASSERT(thread_list_lock_ != NULL); |
- ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey); |
- thread_key_ = OSThread::CreateThreadLocal(DeleteThread); |
- ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey); |
- ASSERT(Thread::Current() == NULL); |
- // Allocate a new Thread and postpone initialization of VM constants for |
- // this first thread. |
- Thread* thread = new Thread(false); |
- // Verify that current thread was set. |
- ASSERT(Thread::Current() == thread); |
-} |
- |
- |
-void Thread::InitOnceAfterObjectAndStubCode() { |
- Thread* thread = Thread::Current(); |
- ASSERT(thread != NULL); |
- ASSERT(thread->isolate() == Dart::vm_isolate()); |
- thread->InitVMConstants(); |
-} |
- |
- |
-void Thread::SetCurrent(Thread* current) { |
- OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current)); |
-} |
- |
- |
-void Thread::EnsureInit() { |
- if (Thread::Current() == NULL) { |
- // Allocate a new Thread. |
- Thread* thread = new Thread(); |
- // Verify that current thread was set. |
- ASSERT(Thread::Current() == thread); |
- } |
} |
@@ -211,28 +37,30 @@ void Thread::EnsureInit() { |
object##_handle_(NULL), |
-Thread::Thread(bool init_vm_constants) |
- : id_(OSThread::GetCurrentThreadId()), |
- join_id_(OSThread::GetCurrentThreadJoinId()), |
- trace_id_(OSThread::GetCurrentThreadTraceId()), |
- thread_interrupt_disabled_(1), // Thread interrupts disabled by default. |
+Thread::Thread(Isolate* isolate) |
+ : BaseThread(false), |
+ os_thread_(NULL), |
isolate_(NULL), |
heap_(NULL), |
- timeline_block_(NULL), |
+ zone_(NULL), |
+ top_exit_frame_info_(0), |
+ top_resource_(NULL), |
+ long_jump_base_(NULL), |
store_buffer_block_(NULL), |
- log_(new class Log()), |
- REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
- REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
+ no_callback_scope_depth_(0), |
+#if defined(DEBUG) |
+ top_handle_scope_(NULL), |
+ no_handle_scope_depth_(0), |
+ no_safepoint_scope_depth_(0), |
+#endif |
reusable_handles_(), |
cha_(NULL), |
deopt_id_(0), |
vm_tag_(0), |
pending_functions_(GrowableObjectArray::null()), |
- no_callback_scope_depth_(0), |
- thread_list_next_(NULL), |
- name_(NULL) { |
- ClearState(); |
- |
+ REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS) |
+ REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT) |
+ next_(NULL) { |
#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \ |
member_name = default_init_value; |
CACHED_CONSTANTS_LIST(DEFAULT_INIT) |
@@ -248,11 +76,11 @@ RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT) |
#undef DEFAULT_INIT |
- if (init_vm_constants) { |
+ // We cannot initialize the VM constants here for the vm isolate thread |
+ // due to boot strapping issues. |
+ if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) { |
InitVMConstants(); |
} |
- SetCurrent(this); |
- AddThreadToList(this); |
} |
@@ -288,12 +116,6 @@ LEAF_RUNTIME_ENTRY_LIST(INIT_VALUE) |
} |
-void Thread::ClearState() { |
- memset(&state_, 0, sizeof(state_)); |
- pending_functions_ = GrowableObjectArray::null(); |
-} |
- |
- |
RawGrowableObjectArray* Thread::pending_functions() { |
if (pending_functions_ == GrowableObjectArray::null()) { |
pending_functions_ = GrowableObjectArray::New(Heap::kOld); |
@@ -302,96 +124,67 @@ RawGrowableObjectArray* Thread::pending_functions() { |
} |
-void Thread::Schedule(Isolate* isolate, bool bypass_safepoint) { |
- State st; |
- if (isolate->thread_registry()->RestoreStateTo(this, &st, bypass_safepoint)) { |
- ASSERT(isolate->thread_registry()->Contains(this)); |
- state_ = st; |
- } |
-} |
- |
- |
-void Thread::Unschedule(bool bypass_safepoint) { |
- ThreadRegistry* reg = isolate_->thread_registry(); |
- ASSERT(reg->Contains(this)); |
- reg->SaveStateFrom(this, state_, bypass_safepoint); |
- ClearState(); |
-} |
- |
- |
void Thread::EnterIsolate(Isolate* isolate) { |
- Thread* thread = Thread::Current(); |
- ASSERT(thread != NULL); |
- ASSERT(thread->isolate() == NULL); |
- ASSERT(!isolate->HasMutatorThread()); |
- thread->isolate_ = isolate; |
+ const bool kIsMutatorThread = true; |
+ const bool kDontBypassSafepoints = false; |
+ ThreadRegistry* tr = isolate->thread_registry(); |
+ Thread* thread = tr->Schedule( |
+ isolate, kIsMutatorThread, kDontBypassSafepoints); |
isolate->MakeCurrentThreadMutator(thread); |
thread->set_vm_tag(VMTag::kVMTagId); |
ASSERT(thread->store_buffer_block_ == NULL); |
thread->StoreBufferAcquire(); |
- ASSERT(isolate->heap() != NULL); |
- thread->heap_ = isolate->heap(); |
- thread->Schedule(isolate); |
- thread->EnableThreadInterrupts(); |
} |
void Thread::ExitIsolate() { |
Thread* thread = Thread::Current(); |
- // TODO(koda): Audit callers; they should know whether they're in an isolate. |
- if (thread == NULL || thread->isolate() == NULL) return; |
+ ASSERT(thread != NULL); |
+ ASSERT(thread->IsMutatorThread()); |
#if defined(DEBUG) |
ASSERT(!thread->IsAnyReusableHandleScopeActive()); |
#endif // DEBUG |
- thread->DisableThreadInterrupts(); |
// Clear since GC will not visit the thread once it is unscheduled. |
thread->ClearReusableHandles(); |
- Isolate* isolate = thread->isolate(); |
- thread->Unschedule(); |
- // TODO(koda): Move store_buffer_block_ into State. |
thread->StoreBufferRelease(); |
+ Isolate* isolate = thread->isolate(); |
+ ASSERT(isolate != NULL); |
if (isolate->is_runnable()) { |
thread->set_vm_tag(VMTag::kIdleTagId); |
} else { |
thread->set_vm_tag(VMTag::kLoadWaitTagId); |
} |
+ const bool kIsMutatorThread = true; |
+ const bool kDontBypassSafepoints = false; |
+ ThreadRegistry* tr = isolate->thread_registry(); |
+ tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints); |
isolate->ClearMutatorThread(); |
- thread->isolate_ = NULL; |
- ASSERT(Isolate::Current() == NULL); |
- thread->heap_ = NULL; |
} |
void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) { |
- Thread* thread = Thread::Current(); |
- ASSERT(thread != NULL); |
- ASSERT(thread->isolate() == NULL); |
- thread->isolate_ = isolate; |
+ const bool kIsNotMutatorThread = false; |
+ ThreadRegistry* tr = isolate->thread_registry(); |
+ Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint); |
ASSERT(thread->store_buffer_block_ == NULL); |
// TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge. |
thread->store_buffer_block_ = |
thread->isolate()->store_buffer()->PopEmptyBlock(); |
- ASSERT(isolate->heap() != NULL); |
- thread->heap_ = isolate->heap(); |
- // Do not update isolate->mutator_thread, but perform sanity check: |
- // this thread should not be both the main mutator and helper. |
+ // This thread should not be the main mutator. |
ASSERT(!thread->IsMutatorThread()); |
- thread->Schedule(isolate, bypass_safepoint); |
- thread->EnableThreadInterrupts(); |
} |
void Thread::ExitIsolateAsHelper(bool bypass_safepoint) { |
Thread* thread = Thread::Current(); |
- thread->DisableThreadInterrupts(); |
+ ASSERT(thread != NULL); |
+ ASSERT(!thread->IsMutatorThread()); |
+ thread->StoreBufferRelease(); |
Isolate* isolate = thread->isolate(); |
ASSERT(isolate != NULL); |
- thread->Unschedule(bypass_safepoint); |
- // TODO(koda): Move store_buffer_block_ into State. |
- thread->StoreBufferRelease(); |
- thread->isolate_ = NULL; |
- thread->heap_ = NULL; |
- ASSERT(!thread->IsMutatorThread()); |
+ const bool kIsNotMutatorThread = false; |
+ ThreadRegistry* tr = isolate->thread_registry(); |
+ tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint); |
} |
@@ -459,23 +252,6 @@ bool Thread::HasExitedDartCode() const { |
} |
-CHA* Thread::cha() const { |
- ASSERT(isolate_ != NULL); |
- return cha_; |
-} |
- |
- |
-void Thread::set_cha(CHA* value) { |
- ASSERT(isolate_ != NULL); |
- cha_ = value; |
-} |
- |
- |
-Log* Thread::log() const { |
- return log_; |
-} |
- |
- |
template<class C> |
C* Thread::AllocateReusableHandle() { |
C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle()); |
@@ -505,34 +281,6 @@ void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
} |
-void Thread::DisableThreadInterrupts() { |
- ASSERT(Thread::Current() == this); |
- AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_); |
-} |
- |
- |
-void Thread::EnableThreadInterrupts() { |
- ASSERT(Thread::Current() == this); |
- uintptr_t old = |
- AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_); |
- if (old == 1) { |
- // We just decremented from 1 to 0. |
- // Make sure the thread interrupter is awake. |
- ThreadInterrupter::WakeUp(); |
- } |
- if (old == 0) { |
- // We just decremented from 0, this means we've got a mismatched pair |
- // of calls to EnableThreadInterrupts and DisableThreadInterrupts. |
- FATAL("Invalid call to Thread::EnableThreadInterrupts()"); |
- } |
-} |
- |
- |
-bool Thread::ThreadInterruptsEnabled() { |
- return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0; |
-} |
- |
- |
bool Thread::CanLoadFromThread(const Object& object) { |
#define CHECK_OBJECT(type_name, member_name, expr, default_init_value) \ |
if (object.raw() == expr) return true; |
@@ -585,48 +333,21 @@ LEAF_RUNTIME_ENTRY_LIST(COMPUTE_OFFSET) |
} |
-ThreadIterator::ThreadIterator() { |
- ASSERT(Thread::thread_list_lock_ != NULL); |
- // Lock the thread list while iterating. |
- Thread::thread_list_lock_->Lock(); |
- next_ = Thread::thread_list_head_; |
-} |
- |
- |
-ThreadIterator::~ThreadIterator() { |
- ASSERT(Thread::thread_list_lock_ != NULL); |
- // Unlock the thread list when done. |
- Thread::thread_list_lock_->Unlock(); |
-} |
- |
- |
-bool ThreadIterator::HasNext() const { |
- ASSERT(Thread::thread_list_lock_ != NULL); |
- ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); |
- return next_ != NULL; |
-} |
- |
- |
-Thread* ThreadIterator::Next() { |
- ASSERT(Thread::thread_list_lock_ != NULL); |
- ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread()); |
- Thread* current = next_; |
- next_ = next_->thread_list_next_; |
- return current; |
-} |
- |
- |
DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread) |
: StackResource(thread) { |
if (thread != NULL) { |
- thread->DisableThreadInterrupts(); |
+ OSThread* os_thread = thread->os_thread(); |
+ ASSERT(os_thread != NULL); |
+ os_thread->DisableThreadInterrupts(); |
} |
} |
DisableThreadInterruptsScope::~DisableThreadInterruptsScope() { |
if (thread() != NULL) { |
- thread()->EnableThreadInterrupts(); |
+ OSThread* os_thread = thread()->os_thread(); |
+ ASSERT(os_thread != NULL); |
+ os_thread->EnableThreadInterrupts(); |
} |
} |