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..6f3d8e48d5f9c94d9a81e20b9522a9c5dda1e7cb |
--- /dev/null |
+++ b/runtime/vm/os_thread.cc |
@@ -0,0 +1,231 @@ |
+// 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), |
+ thread_(NULL) { |
+ 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 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; |
+ break; |
+ } |
+ previous = current; |
+ current = current->thread_list_next_; |
+ } |
+ } |
+ // Check if this is the last thread. The last thread does a cleanup |
+ // which removes the thread local key and the associated mutex. |
+ if (thread_list_head_ == NULL) { |
+ Cleanup(); |
+ } |
+} |
+ |
+ |
+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 |