[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:
Ryan Macnak
2026-03-25 11:58:38 -07:00
committed by Commit Queue
parent 659abef5a7
commit 1d0195cad4
15 changed files with 33 additions and 492 deletions
+8 -21
View File
@@ -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
View File
@@ -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;
+1 -21
View File
@@ -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);
}
-20
View File
@@ -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_
+1 -21
View File
@@ -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);
}
-20
View File
@@ -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_
-20
View File
@@ -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;
-20
View File
@@ -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_
+1 -21
View File
@@ -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);
}
-20
View File
@@ -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_
+1 -21
View File
@@ -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);
}
-21
View File
@@ -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_
-190
View File
@@ -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)
-59
View File
@@ -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_
+1 -5
View File
@@ -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.