Chromium Code Reviews| Index: runtime/vm/thread.cc |
| diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc |
| index 0d8493798217b5bfd188bfadc6348a523b4e54b6..7793fc5c79cacd06acd9120f7eca925107198bcd 100644 |
| --- a/runtime/vm/thread.cc |
| +++ b/runtime/vm/thread.cc |
| @@ -20,183 +20,15 @@ |
| 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); |
|
zra
2015/11/16 20:12:28
What prunes threads from the registry now?
siva
2015/11/17 20:52:25
The thread registry destructor deletes any remaini
|
| - 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); |
| - } |
| + OSThread::SetThreadLocal(OSThread::thread_key_, |
| + reinterpret_cast<uword>(current)); |
| } |
| @@ -211,28 +43,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 +82,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 +122,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 +130,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 +258,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 +287,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 +339,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(); |
| } |
| } |