| 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();
|
| }
|
| }
|
|
|
|
|