| Index: runtime/vm/os_thread_win.cc
|
| diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
|
| index bcb5a5398138c38b67cd9f76942c2d0d9d2d755f..d2ae84c0c5c67ea87d69a8584cc50849f5016f44 100644
|
| --- a/runtime/vm/os_thread_win.cc
|
| +++ b/runtime/vm/os_thread_win.cc
|
| @@ -5,6 +5,7 @@
|
| #include "platform/globals.h" // NOLINT
|
| #if defined(TARGET_OS_WINDOWS)
|
|
|
| +#include "vm/growable_array.h"
|
| #include "vm/os_thread.h"
|
|
|
| #include <process.h> // NOLINT
|
| @@ -73,11 +74,12 @@ ThreadLocalKey OSThread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
|
| ThreadId OSThread::kInvalidThreadId = 0;
|
| ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
|
|
|
| -ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor unused) {
|
| +ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
| ThreadLocalKey key = TlsAlloc();
|
| if (key == kUnsetThreadLocalKey) {
|
| FATAL1("TlsAlloc failed %d", GetLastError());
|
| }
|
| + ThreadLocalData::AddThreadLocal(key, destructor);
|
| return key;
|
| }
|
|
|
| @@ -88,6 +90,7 @@ void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
| if (!result) {
|
| FATAL1("TlsFree failed %d", GetLastError());
|
| }
|
| + ThreadLocalData::RemoveThreadLocal(key);
|
| }
|
|
|
|
|
| @@ -482,14 +485,87 @@ void Monitor::NotifyAll() {
|
| data_.SignalAndRemoveAllWaiters();
|
| }
|
|
|
| -// This function is defined in thread.cc.
|
| -extern void ThreadCleanupOnExit();
|
|
|
| -} // namespace dart
|
| +void ThreadLocalData::AddThreadLocal(ThreadLocalKey key,
|
| + ThreadDestructor destructor) {
|
| + ASSERT(thread_locals_ != NULL);
|
| + if (destructor == NULL) {
|
| + // We only care about thread locals with destructors.
|
| + return;
|
| + }
|
| + mutex_->Lock();
|
| +#if defined(DEBUG)
|
| + // Verify that we aren't added twice.
|
| + for (intptr_t i = 0; i < thread_locals_->length(); i++) {
|
| + const ThreadLocalEntry& entry = thread_locals_->At(i);
|
| + ASSERT(entry.key() != key);
|
| + }
|
| +#endif
|
| + // Add to list.
|
| + thread_locals_->Add(ThreadLocalEntry(key, destructor));
|
| + mutex_->Unlock();
|
| +}
|
| +
|
| +
|
| +void ThreadLocalData::RemoveThreadLocal(ThreadLocalKey key) {
|
| + ASSERT(thread_locals_ != NULL); mutex_->Lock();
|
| + intptr_t i = 0;
|
| + for (; i < thread_locals_->length(); i++) {
|
| + const ThreadLocalEntry& entry = thread_locals_->At(i);
|
| + if (entry.key() == key) {
|
| + break;
|
| + }
|
| + }
|
| + if (i == thread_locals_->length()) {
|
| + // Not found.
|
| + mutex_->Unlock();
|
| + return;
|
| + }
|
| + thread_locals_->RemoveAt(i);
|
| + mutex_->Unlock();
|
| +}
|
| +
|
| +
|
| +// This function is executed on the thread that is exiting. It is invoked
|
| +// by |OnDartThreadExit| (see below for notes on TLS destructors on Windows).
|
| +void ThreadLocalData::RunDestructors() {
|
| + ASSERT(thread_locals_ != NULL);
|
| + ASSERT(mutex_ != NULL);
|
| + mutex_->Lock();
|
| + for (intptr_t i = 0; i < thread_locals_->length(); i++) {
|
| + const ThreadLocalEntry& entry = thread_locals_->At(i);
|
| + // We access the exiting thread's TLS variable here.
|
| + void* p = reinterpret_cast<void*>(OSThread::GetThreadLocal(entry.key()));
|
| + // We invoke the constructor here.
|
| + entry.destructor()(p);
|
| + }
|
| + mutex_->Unlock();
|
| +}
|
| +
|
| +
|
| +Mutex* ThreadLocalData::mutex_ = NULL;
|
| +MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ = NULL;
|
| +
|
| +
|
| +void ThreadLocalData::InitOnce() {
|
| + mutex_ = new Mutex();
|
| + thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>();
|
| +}
|
|
|
| -// NOTE: We still do not respect arbitrary TLS destructors on Windows, but,
|
| -// we do run known TLS cleanup functions. See |OnThreadExit| below for
|
| -// the list of functions that are called.
|
| +
|
| +void ThreadLocalData::Shutdown() {
|
| + if (mutex_ != NULL) {
|
| + delete mutex_;
|
| + mutex_ = NULL;
|
| + }
|
| + if (thread_locals_ != NULL) {
|
| + delete thread_locals_;
|
| + thread_locals_ = NULL;
|
| + }
|
| +}
|
| +
|
| +
|
| +} // namespace dart
|
|
|
| // The following was adapted from Chromium:
|
| // src/base/threading/thread_local_storage_win.cc
|
| @@ -522,7 +598,7 @@ void NTAPI OnDartThreadExit(PVOID module, DWORD reason, PVOID reserved) {
|
| // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
|
| // and on W2K and W2K3. So don't assume it is sent.
|
| if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason) {
|
| - dart::ThreadCleanupOnExit();
|
| + dart::ThreadLocalData::RunDestructors();
|
| dart::MonitorWaitData::ThreadExit();
|
| }
|
| }
|
|
|