[vm] Use C++11 thread_local for TLS destructors.
Removes linker hack on Windows. TEST=ci Change-Id: Ib031f8f05e422084fa6652fee425f8e46884840e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/490341 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
Commit Queue
parent
659abef5a7
commit
1d0195cad4
+8
-21
@@ -16,12 +16,10 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
// The single thread local key which stores all the thread local data
|
||||
// for a thread.
|
||||
ThreadLocalKey OSThread::thread_key_ = kUnsetThreadLocalKey;
|
||||
OSThread* OSThread::thread_list_head_ = nullptr;
|
||||
Mutex* OSThread::thread_list_lock_ = nullptr;
|
||||
bool OSThread::creation_enabled_ = false;
|
||||
thread_local OSThreadPtr OSThread::current_os_thread_ = {};
|
||||
|
||||
#if defined(SUPPORT_TIMELINE)
|
||||
inline void UpdateTimelineTrackMetadata(const OSThread& thread) {
|
||||
@@ -87,6 +85,11 @@ OSThread* OSThread::CreateOSThread() {
|
||||
return os_thread;
|
||||
}
|
||||
|
||||
OSThreadPtr::~OSThreadPtr() {
|
||||
delete thread_;
|
||||
thread_ = nullptr;
|
||||
}
|
||||
|
||||
OSThread::~OSThread() {
|
||||
if (!is_os_thread()) {
|
||||
// If the embedder enters an isolate on this thread and does not exit the
|
||||
@@ -169,11 +172,6 @@ bool OSThread::ThreadInterruptsEnabled() {
|
||||
}
|
||||
#endif // defined(DART_INCLUDE_PROFILER)
|
||||
|
||||
static void DeleteThread(void* thread) {
|
||||
MSAN_UNPOISON(&thread, sizeof(thread));
|
||||
delete reinterpret_cast<OSThread*>(thread);
|
||||
}
|
||||
|
||||
void OSThread::Init() {
|
||||
// Allocate the global OSThread lock.
|
||||
if (thread_list_lock_ == nullptr) {
|
||||
@@ -181,12 +179,6 @@ void OSThread::Init() {
|
||||
}
|
||||
ASSERT(thread_list_lock_ != nullptr);
|
||||
|
||||
// Create the thread local key.
|
||||
if (thread_key_ == kUnsetThreadLocalKey) {
|
||||
thread_key_ = CreateThreadLocal(DeleteThread);
|
||||
}
|
||||
ASSERT(thread_key_ != kUnsetThreadLocalKey);
|
||||
|
||||
// Enable creation of OSThread structures in the VM.
|
||||
EnableOSThreadCreation();
|
||||
|
||||
@@ -198,15 +190,10 @@ void OSThread::Init() {
|
||||
}
|
||||
|
||||
void OSThread::Cleanup() {
|
||||
// We cannot delete the thread local key and thread list lock, yet.
|
||||
// We cannot delete the thread list lock, yet.
|
||||
// See the note on thread_list_lock_ in os_thread.h.
|
||||
#if 0
|
||||
if (thread_list_lock_ != nullptr) {
|
||||
// Delete the thread local key.
|
||||
ASSERT(thread_key_ != kUnsetThreadLocalKey);
|
||||
DeleteThreadLocal(thread_key_);
|
||||
thread_key_ = kUnsetThreadLocalKey;
|
||||
|
||||
// Delete the global OSThread lock.
|
||||
ASSERT(thread_list_lock_ != nullptr);
|
||||
delete thread_list_lock_;
|
||||
@@ -331,7 +318,7 @@ void OSThread::RemoveThreadFromList(OSThread* thread) {
|
||||
DART_NOINLINE
|
||||
void OSThread::SetCurrentTLS(BaseThread* value) {
|
||||
// Provides thread-local destructors.
|
||||
SetThreadLocal(thread_key_, reinterpret_cast<uword>(value));
|
||||
current_os_thread_.set(static_cast<OSThread*>(value));
|
||||
|
||||
// Allows the C compiler more freedom to optimize.
|
||||
if ((value != nullptr) && !value->is_os_thread()) {
|
||||
|
||||
+20
-12
@@ -58,6 +58,21 @@ class BaseThread {
|
||||
|
||||
using ThreadId = platform::ThreadId;
|
||||
|
||||
class OSThread;
|
||||
|
||||
// Wrapper to get TLS destructor.
|
||||
class OSThreadPtr {
|
||||
public:
|
||||
constexpr OSThreadPtr() {}
|
||||
~OSThreadPtr();
|
||||
|
||||
OSThread* get() const { return thread_; }
|
||||
void set(OSThread* value) { thread_ = value; }
|
||||
|
||||
private:
|
||||
OSThread* thread_ = nullptr;
|
||||
};
|
||||
|
||||
// Low-level operations on OS platform threads.
|
||||
class OSThread : public BaseThread {
|
||||
public:
|
||||
@@ -182,9 +197,7 @@ class OSThread : public BaseThread {
|
||||
uword stack_size = OSThread::GetMaxStackSize() - headroom;
|
||||
return stack_size;
|
||||
}
|
||||
static BaseThread* GetCurrentTLS() {
|
||||
return reinterpret_cast<BaseThread*>(OSThread::GetThreadLocal(thread_key_));
|
||||
}
|
||||
static BaseThread* GetCurrentTLS() { return current_os_thread_.get(); }
|
||||
static void SetCurrentTLS(BaseThread* value);
|
||||
|
||||
typedef void (*ThreadStartFunction)(uword parameter);
|
||||
@@ -202,13 +215,6 @@ class OSThread : public BaseThread {
|
||||
ThreadStartFunction function,
|
||||
uword parameter);
|
||||
|
||||
static ThreadLocalKey CreateThreadLocal(
|
||||
ThreadDestructor destructor = nullptr);
|
||||
static void DeleteThreadLocal(ThreadLocalKey key);
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
return ThreadInlineImpl::GetThreadLocal(key);
|
||||
}
|
||||
static void SetThreadLocal(ThreadLocalKey key, uword value);
|
||||
static intptr_t GetMaxStackSize();
|
||||
static void Join(ThreadJoinId id);
|
||||
static void Detach(ThreadJoinId id);
|
||||
@@ -273,8 +279,6 @@ class OSThread : public BaseThread {
|
||||
return (headroom > kStackSizeBufferMax) ? kStackSizeBufferMax : headroom;
|
||||
}
|
||||
|
||||
static ThreadLocalKey thread_key_;
|
||||
|
||||
const ThreadId id_;
|
||||
#if defined(DEBUG)
|
||||
// In DEBUG mode we use this field to ensure that GetCurrentThreadJoinId is
|
||||
@@ -322,6 +326,10 @@ class OSThread : public BaseThread {
|
||||
// initialization checks at each use.
|
||||
static inline thread_local ThreadState* current_vm_thread_ = nullptr;
|
||||
|
||||
// Inline initialization results in duplicate definition link errors on Mac.
|
||||
// But this TLS is rarely accessed, so the guard doesn't matter much.
|
||||
static thread_local OSThreadPtr current_os_thread_;
|
||||
|
||||
friend class Thread; // to access set_thread(Thread*).
|
||||
friend class OSThreadIterator;
|
||||
friend class ThreadInterrupterFuchsia;
|
||||
|
||||
@@ -148,26 +148,6 @@ int OSThread::TryStart(const char* name,
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
pthread_key_t key = kUnsetThreadLocalKey;
|
||||
int result = pthread_key_create(&key, destructor);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return key;
|
||||
}
|
||||
|
||||
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_key_delete(key);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
intptr_t OSThread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
@@ -217,7 +197,7 @@ void OSThread::Join(ThreadJoinId id) {
|
||||
}
|
||||
|
||||
void OSThread::Detach(ThreadJoinId id) {
|
||||
int result = pthread_detach(id);
|
||||
int result = pthread_detach(id); // NOLINT
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,28 +16,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
static_cast<pthread_key_t>(-1);
|
||||
|
||||
class ThreadInlineImpl {
|
||||
private:
|
||||
ThreadInlineImpl() {}
|
||||
~ThreadInlineImpl() {}
|
||||
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return reinterpret_cast<uword>(pthread_getspecific(key));
|
||||
}
|
||||
|
||||
friend class OSThread;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_ABSL_H_
|
||||
|
||||
@@ -126,26 +126,6 @@ int OSThread::TryStart(const char* name,
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
pthread_key_t key = kUnsetThreadLocalKey;
|
||||
int result = pthread_key_create(&key, destructor);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return key;
|
||||
}
|
||||
|
||||
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_key_delete(key);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
intptr_t OSThread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
@@ -183,7 +163,7 @@ void OSThread::Join(ThreadJoinId id) {
|
||||
}
|
||||
|
||||
void OSThread::Detach(ThreadJoinId id) {
|
||||
int result = pthread_detach(id);
|
||||
int result = pthread_detach(id); // NOLINT
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,28 +16,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
static_cast<pthread_key_t>(-1);
|
||||
|
||||
class ThreadInlineImpl {
|
||||
private:
|
||||
ThreadInlineImpl() {}
|
||||
~ThreadInlineImpl() {}
|
||||
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return reinterpret_cast<uword>(pthread_getspecific(key));
|
||||
}
|
||||
|
||||
friend class OSThread;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_ANDROID_H_
|
||||
|
||||
@@ -96,26 +96,6 @@ int OSThread::TryStart(const char* name,
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
pthread_key_t key = kUnsetThreadLocalKey;
|
||||
int result = pthread_key_create(&key, destructor);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return key;
|
||||
}
|
||||
|
||||
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_key_delete(key);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
intptr_t OSThread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
|
||||
@@ -17,28 +17,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
static_cast<pthread_key_t>(-1);
|
||||
|
||||
class ThreadInlineImpl {
|
||||
private:
|
||||
ThreadInlineImpl() {}
|
||||
~ThreadInlineImpl() {}
|
||||
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return reinterpret_cast<uword>(pthread_getspecific(key));
|
||||
}
|
||||
|
||||
friend class OSThread;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_FUCHSIA_H_
|
||||
|
||||
@@ -125,26 +125,6 @@ int OSThread::TryStart(const char* name,
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(0);
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
pthread_key_t key = kUnsetThreadLocalKey;
|
||||
int result = pthread_key_create(&key, destructor);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return key;
|
||||
}
|
||||
|
||||
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_key_delete(key);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
intptr_t OSThread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
@@ -182,7 +162,7 @@ void OSThread::Join(ThreadJoinId id) {
|
||||
}
|
||||
|
||||
void OSThread::Detach(ThreadJoinId id) {
|
||||
int result = pthread_detach(id);
|
||||
int result = pthread_detach(id); // NOLINT
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,28 +16,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
static_cast<pthread_key_t>(-1);
|
||||
|
||||
class ThreadInlineImpl {
|
||||
private:
|
||||
ThreadInlineImpl() {}
|
||||
~ThreadInlineImpl() {}
|
||||
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return reinterpret_cast<uword>(pthread_getspecific(key));
|
||||
}
|
||||
|
||||
friend class OSThread;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_LINUX_H_
|
||||
|
||||
@@ -122,26 +122,6 @@ int OSThread::TryStart(const char* name,
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId =
|
||||
static_cast<ThreadJoinId>(nullptr);
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
pthread_key_t key = kUnsetThreadLocalKey;
|
||||
int result = pthread_key_create(&key, destructor);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return key;
|
||||
}
|
||||
|
||||
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_key_delete(key);
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
intptr_t OSThread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
@@ -179,7 +159,7 @@ void OSThread::Join(ThreadJoinId id) {
|
||||
}
|
||||
|
||||
void OSThread::Detach(ThreadJoinId id) {
|
||||
int result = pthread_detach(id);
|
||||
int result = pthread_detach(id); // NOLINT
|
||||
VALIDATE_PTHREAD_RESULT(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,29 +16,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef pthread_key_t ThreadLocalKey;
|
||||
typedef pthread_t ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey =
|
||||
static_cast<pthread_key_t>(-1);
|
||||
|
||||
class ThreadInlineImpl {
|
||||
private:
|
||||
ThreadInlineImpl() {}
|
||||
~ThreadInlineImpl() {}
|
||||
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return reinterpret_cast<uword>(pthread_getspecific(key));
|
||||
}
|
||||
|
||||
friend class OSThread;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_MACOS_H_
|
||||
|
||||
@@ -98,30 +98,6 @@ int OSThread::TryStart(const char* name,
|
||||
|
||||
const ThreadJoinId OSThread::kInvalidThreadJoinId = nullptr;
|
||||
|
||||
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
|
||||
ThreadLocalKey key = TlsAlloc();
|
||||
if (key == kUnsetThreadLocalKey) {
|
||||
int error = GetLastError();
|
||||
char buffer[1024];
|
||||
FATAL("TlsAlloc failed %d (%s)\n", error,
|
||||
Utils::StrError(error, buffer, sizeof(buffer)));
|
||||
}
|
||||
ThreadLocalData::AddThreadLocal(key, destructor);
|
||||
return key;
|
||||
}
|
||||
|
||||
void OSThread::DeleteThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
BOOL result = TlsFree(key);
|
||||
if (!result) {
|
||||
int error = GetLastError();
|
||||
char buffer[1024];
|
||||
FATAL("TlsFree failed %d (%s)\n", error,
|
||||
Utils::StrError(error, buffer, sizeof(buffer)));
|
||||
}
|
||||
ThreadLocalData::RemoveThreadLocal(key);
|
||||
}
|
||||
|
||||
intptr_t OSThread::GetMaxStackSize() {
|
||||
const int kStackSize = (128 * kWordSize * KB);
|
||||
return kStackSize;
|
||||
@@ -199,172 +175,6 @@ void OSThread::SetCurrentSafestackPointer(uword ssp) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void OSThread::SetThreadLocal(ThreadLocalKey key, uword value) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
BOOL result = TlsSetValue(key, reinterpret_cast<void*>(value));
|
||||
if (!result) {
|
||||
int error = GetLastError();
|
||||
char buffer[1024];
|
||||
FATAL("TlsSetValue failed %d (%s)\n", error,
|
||||
Utils::StrError(error, buffer, sizeof(buffer)));
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadLocalData::AddThreadLocal(ThreadLocalKey key,
|
||||
ThreadDestructor destructor) {
|
||||
ASSERT(thread_locals_ != nullptr);
|
||||
if (destructor == nullptr) {
|
||||
// We only care about thread locals with destructors.
|
||||
return;
|
||||
}
|
||||
MutexLocker ml(mutex_);
|
||||
#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));
|
||||
}
|
||||
|
||||
void ThreadLocalData::RemoveThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(thread_locals_ != nullptr);
|
||||
MutexLocker ml(mutex_);
|
||||
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.
|
||||
return;
|
||||
}
|
||||
thread_locals_->RemoveAt(i);
|
||||
}
|
||||
|
||||
// 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() {
|
||||
// If an OS thread is created but ThreadLocalData::Init has not yet been
|
||||
// called, this method still runs. If this happens, there's nothing to clean
|
||||
// up here. See issue 33826.
|
||||
if (thread_locals_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
ASSERT(mutex_ != nullptr);
|
||||
MutexLocker ml(mutex_);
|
||||
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* ThreadLocalData::mutex_ = nullptr;
|
||||
MallocGrowableArray<ThreadLocalEntry>* ThreadLocalData::thread_locals_ =
|
||||
nullptr;
|
||||
|
||||
void ThreadLocalData::Init() {
|
||||
mutex_ = new Mutex();
|
||||
thread_locals_ = new MallocGrowableArray<ThreadLocalEntry>();
|
||||
}
|
||||
|
||||
void ThreadLocalData::Cleanup() {
|
||||
if (mutex_ != nullptr) {
|
||||
delete mutex_;
|
||||
mutex_ = nullptr;
|
||||
}
|
||||
if (thread_locals_ != nullptr) {
|
||||
delete thread_locals_;
|
||||
thread_locals_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
// The following was adapted from Chromium:
|
||||
// src/base/threading/thread_local_storage_win.cc
|
||||
|
||||
// Thread Termination Callbacks.
|
||||
// Windows doesn't support a per-thread destructor with its
|
||||
// TLS primitives. So, we build it manually by inserting a
|
||||
// function to be called on each thread's exit.
|
||||
// This magic is from http://www.codeproject.com/threads/tls.asp
|
||||
// and it works for VC++ 7.0 and later.
|
||||
|
||||
// Force a reference to _tls_used to make the linker create the TLS directory
|
||||
// if it's not already there. (e.g. if __declspec(thread) is not used).
|
||||
// Force a reference to p_thread_callback_dart to prevent whole program
|
||||
// optimization from discarding the variable.
|
||||
#ifdef _WIN64
|
||||
|
||||
#pragma comment(linker, "/INCLUDE:_tls_used")
|
||||
#pragma comment(linker, "/INCLUDE:p_thread_callback_dart")
|
||||
|
||||
#else // _WIN64
|
||||
|
||||
#pragma comment(linker, "/INCLUDE:__tls_used")
|
||||
#pragma comment(linker, "/INCLUDE:_p_thread_callback_dart")
|
||||
|
||||
#endif // _WIN64
|
||||
|
||||
// Static callback function to call with each thread termination.
|
||||
void NTAPI OnDartThreadExit(PVOID module, DWORD reason, PVOID reserved) {
|
||||
if (!dart::private_flag_windows_run_tls_destructors) {
|
||||
return;
|
||||
}
|
||||
// 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::ThreadLocalData::RunDestructors();
|
||||
}
|
||||
}
|
||||
|
||||
// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
|
||||
// called automatically by the OS loader code (not the CRT) when the module is
|
||||
// loaded and on thread creation. They are NOT called if the module has been
|
||||
// loaded by a LoadLibrary() call. It must have implicitly been loaded at
|
||||
// process startup.
|
||||
// By implicitly loaded, I mean that it is directly referenced by the main EXE
|
||||
// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
|
||||
// implicitly loaded.
|
||||
//
|
||||
// See VC\crt\src\tlssup.c for reference.
|
||||
|
||||
// extern "C" suppresses C++ name mangling so we know the symbol name for the
|
||||
// linker /INCLUDE:symbol pragma above.
|
||||
extern "C" {
|
||||
// The linker must not discard p_thread_callback_dart. (We force a reference
|
||||
// to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If
|
||||
// this variable is discarded, the OnDartThreadExit function will never be
|
||||
// called.
|
||||
#ifdef _WIN64
|
||||
|
||||
// .CRT section is merged with .rdata on x64 so it must be constant data.
|
||||
#pragma const_seg(".CRT$XLB")
|
||||
// When defining a const variable, it must have external linkage to be sure the
|
||||
// linker doesn't discard it.
|
||||
extern const PIMAGE_TLS_CALLBACK p_thread_callback_dart;
|
||||
const PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit;
|
||||
|
||||
// Reset the default section.
|
||||
#pragma const_seg()
|
||||
|
||||
#else // _WIN64
|
||||
|
||||
#pragma data_seg(".CRT$XLB")
|
||||
PIMAGE_TLS_CALLBACK p_thread_callback_dart = OnDartThreadExit;
|
||||
|
||||
// Reset the default section.
|
||||
#pragma data_seg()
|
||||
|
||||
#endif // _WIN64
|
||||
} // extern "C"
|
||||
|
||||
#endif // defined(DART_HOST_OS_WINDOWS) && !defined(DART_USE_ABSL)
|
||||
|
||||
@@ -16,67 +16,8 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef DWORD ThreadLocalKey;
|
||||
typedef HANDLE ThreadJoinId;
|
||||
|
||||
static const ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
|
||||
|
||||
class ThreadInlineImpl {
|
||||
private:
|
||||
ThreadInlineImpl() {}
|
||||
~ThreadInlineImpl() {}
|
||||
|
||||
static uword GetThreadLocal(ThreadLocalKey key) {
|
||||
ASSERT(key != kUnsetThreadLocalKey);
|
||||
return reinterpret_cast<uword>(TlsGetValue(key));
|
||||
}
|
||||
|
||||
friend class OSThread;
|
||||
friend unsigned int __stdcall ThreadEntry(void* data_ptr);
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
|
||||
};
|
||||
|
||||
typedef void (*ThreadDestructor)(void* parameter);
|
||||
|
||||
class ThreadLocalEntry {
|
||||
public:
|
||||
ThreadLocalEntry(ThreadLocalKey key, ThreadDestructor destructor)
|
||||
: key_(key), destructor_(destructor) {}
|
||||
|
||||
ThreadLocalKey key() const { return key_; }
|
||||
|
||||
ThreadDestructor destructor() const { return destructor_; }
|
||||
|
||||
private:
|
||||
ThreadLocalKey key_;
|
||||
ThreadDestructor destructor_;
|
||||
|
||||
DISALLOW_ALLOCATION();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MallocGrowableArray;
|
||||
|
||||
class ThreadLocalData : public AllStatic {
|
||||
public:
|
||||
static void RunDestructors();
|
||||
|
||||
private:
|
||||
static void AddThreadLocal(ThreadLocalKey key, ThreadDestructor destructor);
|
||||
static void RemoveThreadLocal(ThreadLocalKey key);
|
||||
|
||||
static Mutex* mutex_;
|
||||
static MallocGrowableArray<ThreadLocalEntry>* thread_locals_;
|
||||
|
||||
static void Init();
|
||||
static void Cleanup();
|
||||
|
||||
friend class OS;
|
||||
friend class OSThread;
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_OS_THREAD_WIN_H_
|
||||
|
||||
@@ -368,7 +368,6 @@ void OS::Init() {
|
||||
init_once_called = true;
|
||||
// Do not pop up a message box when abort is called.
|
||||
_set_abort_behavior(0, _WRITE_ABORT_MSG);
|
||||
ThreadLocalData::Init();
|
||||
LARGE_INTEGER ticks_per_sec;
|
||||
if (!QueryPerformanceFrequency(&ticks_per_sec)) {
|
||||
qpc_ticks_per_second = 0;
|
||||
@@ -377,10 +376,7 @@ void OS::Init() {
|
||||
}
|
||||
}
|
||||
|
||||
void OS::Cleanup() {
|
||||
// TODO(zra): Enable once VM can shutdown cleanly.
|
||||
// ThreadLocalData::Cleanup();
|
||||
}
|
||||
void OS::Cleanup() {}
|
||||
|
||||
void OS::PrepareToAbort() {
|
||||
// TODO(zra): Remove once VM shuts down cleanly.
|
||||
|
||||
Reference in New Issue
Block a user