Chromium Code Reviews| Index: runtime/vm/os_thread.cc |
| diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f72797769c8980962b8fa7ab4e9b8d98e2ef161a |
| --- /dev/null |
| +++ b/runtime/vm/os_thread.cc |
| @@ -0,0 +1,230 @@ |
| +// Copyright (c) 2015, 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. |
| + |
| +#include "vm/os_thread.h" |
| + |
| +#include "vm/atomic.h" |
| +#include "vm/lockers.h" |
| +#include "vm/log.h" |
| +#include "vm/thread_interrupter.h" |
| + |
| +namespace dart { |
| + |
| +// The single thread local key which stores all the thread local data |
| +// for a thread. |
| +ThreadLocalKey OSThread::thread_key_ = OSThread::kUnsetThreadLocalKey; |
| +OSThread* OSThread::thread_list_head_ = NULL; |
| +Mutex* OSThread::thread_list_lock_ = NULL; |
| + |
| + |
| +OSThread::OSThread() : |
| + BaseThread(true), |
| + id_(OSThread::GetCurrentThreadId()), |
| + join_id_(OSThread::GetCurrentThreadJoinId()), |
| + trace_id_(OSThread::GetCurrentThreadTraceId()), |
| + name_(NULL), |
| + timeline_block_lock_(new Mutex()), |
| + timeline_block_(NULL), |
| + thread_list_next_(NULL), |
| + thread_interrupt_disabled_(1), // Thread interrupts disabled by default. |
| + log_(new class Log()), |
| + stack_base_(0) { |
| + AddThreadToList(this); |
| +} |
| + |
| + |
| +OSThread::~OSThread() { |
| + RemoveThreadFromList(this); |
| + delete log_; |
| + log_ = NULL; |
| + if (Timeline::recorder() != NULL) { |
| + Timeline::recorder()->FinishBlock(timeline_block_); |
| + } |
| + timeline_block_ = NULL; |
| + delete timeline_block_lock_; |
| +} |
| + |
| + |
| +void OSThread::DisableThreadInterrupts() { |
| + ASSERT(OSThread::Current() == this); |
| + AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_); |
| +} |
| + |
| + |
| +void OSThread::EnableThreadInterrupts() { |
| + ASSERT(OSThread::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 OSThread::EnableThreadInterrupts()"); |
| + } |
| +} |
| + |
| + |
| +bool OSThread::ThreadInterruptsEnabled() { |
| + return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0; |
| +} |
| + |
| + |
| +static void DeleteThread(void* thread) { |
| + delete reinterpret_cast<OSThread*>(thread); |
| +} |
| + |
| + |
| +void OSThread::InitOnce() { |
| + // Allocate the global OSThread lock. |
| + ASSERT(thread_list_lock_ == NULL); |
| + thread_list_lock_ = new Mutex(); |
| + ASSERT(thread_list_lock_ != NULL); |
| + |
| + // Create the thread local key. |
| + ASSERT(thread_key_ == kUnsetThreadLocalKey); |
| + thread_key_ = CreateThreadLocal(DeleteThread); |
| + ASSERT(thread_key_ != kUnsetThreadLocalKey); |
| + |
| + // Create a new OSThread strcture and set it as the TLS. |
| + OSThread* os_thread = new OSThread(); |
| + OSThread::SetCurrent(os_thread); |
| + os_thread->set_name("Dart_Initialize"); |
| +} |
| + |
| + |
| +void OSThread::Cleanup() { |
| + if (thread_list_lock_ != NULL) { |
| + // Delete the current threads TLS, should result in the global OSThread |
| + // list to become empty. |
| + OSThread* thread = OSThread::Current(); |
| + ASSERT(thread != NULL); |
| + OSThread::SetCurrent(NULL); |
| + |
|
zra
2015/11/16 20:12:28
Does thread need to be deleted?
After that, I thi
siva
2015/11/17 20:52:25
As discussed offline moved the deletion of TLS to
|
| + // Delete the thread local key. |
| + ASSERT(thread_key_ != kUnsetThreadLocalKey); |
| + DeleteThreadLocal(thread_key_); |
| + thread_key_ = kUnsetThreadLocalKey; |
| + |
| + // Delete the global OSThread lock. |
| + ASSERT(thread_list_lock_ != NULL); |
| + delete thread_list_lock_; |
| + thread_list_lock_ = NULL; |
| + } |
| +} |
| + |
| + |
| +bool OSThread::IsThreadInList(ThreadId join_id) { |
| + if (join_id == OSThread::kInvalidThreadJoinId) { |
| + return false; |
| + } |
| + OSThreadIterator it; |
| + while (it.HasNext()) { |
| + ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
| + OSThread* 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; |
| +} |
| + |
| + |
| +OSThread* OSThread::GetOSThreadFromThread(Thread* thread) { |
| + ASSERT(thread->os_thread() != NULL); |
| + return thread->os_thread(); |
| +} |
| + |
| + |
| +void OSThread::AddThreadToList(OSThread* thread) { |
| + ASSERT(thread != 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. |
| + OSThread* 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 OSThread::RemoveThreadFromList(OSThread* thread) { |
| + ASSERT(thread != NULL); |
| + ASSERT(thread_list_lock_ != NULL); |
| + MutexLocker ml(thread_list_lock_); |
| + OSThread* current = thread_list_head_; |
| + OSThread* previous = NULL; |
| + |
| + // Scan across list and remove |thread|. |
| + while (current != NULL) { |
| + if (current == thread) { |
| + // We found |thread|, remove from list. |
| + if (previous == NULL) { |
| + thread_list_head_ = thread->thread_list_next_; |
| + } else { |
| + previous->thread_list_next_ = current->thread_list_next_; |
| + } |
| + thread->thread_list_next_ = NULL; |
| + return; |
| + } |
| + previous = current; |
| + current = current->thread_list_next_; |
| + } |
| + UNREACHABLE(); |
| +} |
| + |
| + |
| +void OSThread::SetCurrent(OSThread* current) { |
| + OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current)); |
| +} |
| + |
| + |
| +OSThreadIterator::OSThreadIterator() { |
| + ASSERT(OSThread::thread_list_lock_ != NULL); |
| + // Lock the thread list while iterating. |
| + OSThread::thread_list_lock_->Lock(); |
| + next_ = OSThread::thread_list_head_; |
| +} |
| + |
| + |
| +OSThreadIterator::~OSThreadIterator() { |
| + ASSERT(OSThread::thread_list_lock_ != NULL); |
| + // Unlock the thread list when done. |
| + OSThread::thread_list_lock_->Unlock(); |
| +} |
| + |
| + |
| +bool OSThreadIterator::HasNext() const { |
| + ASSERT(OSThread::thread_list_lock_ != NULL); |
| + ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
| + return next_ != NULL; |
| +} |
| + |
| + |
| +OSThread* OSThreadIterator::Next() { |
| + ASSERT(OSThread::thread_list_lock_ != NULL); |
| + ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); |
| + OSThread* current = next_; |
| + next_ = next_->thread_list_next_; |
| + return current; |
| +} |
| + |
| +} // namespace dart |