|
|
@@ -5,22 +5,72 @@
|
|
|
#include "RuntimeBasePch.h"
|
|
|
#include "Base/ThreadContextTlsEntry.h"
|
|
|
|
|
|
-static THREAD_LOCAL ThreadContextTLSEntry* s_tlvSlot = nullptr;
|
|
|
+#ifdef _WIN32
|
|
|
+uint32 ThreadContextTLSEntry::s_tlsSlot = TLS_OUT_OF_INDEXES;
|
|
|
+#define ENTRY_FOR_CURRENT_THREAD() GetEntryForCurrentThread()
|
|
|
+#define ASSERT_ENTRY_INITIALIZED() Assert(s_tlsSlot != TLS_OUT_OF_INDEXES)
|
|
|
+#else // !_WIN32
|
|
|
+// entry doesn't need a special initialization
|
|
|
+#define ASSERT_ENTRY_INITIALIZED() Assert(true)
|
|
|
+static THREAD_LOCAL ThreadContextTLSEntry* s_tlsSlot = nullptr;
|
|
|
+#define TlsSetValue(a,b) a = b
|
|
|
+// clang may not optimize the access to THREAD_LOCAL from a sub function
|
|
|
+#define ENTRY_FOR_CURRENT_THREAD() s_tlsSlot
|
|
|
+#endif
|
|
|
+
|
|
|
+bool ThreadContextTLSEntry::InitializeProcess()
|
|
|
+{
|
|
|
+#ifdef _WIN32
|
|
|
+ Assert(s_tlsSlot == TLS_OUT_OF_INDEXES);
|
|
|
+ s_tlsSlot = TlsAlloc();
|
|
|
+ return (s_tlsSlot != TLS_OUT_OF_INDEXES);
|
|
|
+#else
|
|
|
+ return true;
|
|
|
+#endif
|
|
|
+}
|
|
|
|
|
|
-void ThreadContextTLSEntry::CleanupThread()
|
|
|
+void ThreadContextTLSEntry::CleanupProcess()
|
|
|
+{
|
|
|
+#ifdef _WIN32
|
|
|
+ Assert(s_tlsSlot != TLS_OUT_OF_INDEXES);
|
|
|
+ TlsFree(s_tlsSlot);
|
|
|
+ s_tlsSlot = TLS_OUT_OF_INDEXES;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+bool ThreadContextTLSEntry::IsProcessInitialized()
|
|
|
+{
|
|
|
+#ifdef _WIN32
|
|
|
+ return s_tlsSlot != TLS_OUT_OF_INDEXES;
|
|
|
+#else
|
|
|
+ return true;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+void ThreadContextTLSEntry::InitializeThread()
|
|
|
{
|
|
|
- ThreadContextTLSEntry * entry = s_tlvSlot;
|
|
|
+#ifdef _WIN32
|
|
|
+ Assert(s_tlsSlot != TLS_OUT_OF_INDEXES);
|
|
|
+ Assert(!TlsGetValue(s_tlsSlot));
|
|
|
+ TlsSetValue(s_tlsSlot, NULL);
|
|
|
+#endif
|
|
|
+}
|
|
|
|
|
|
- if (entry != nullptr)
|
|
|
+void ThreadContextTLSEntry::CleanupThread()
|
|
|
+{
|
|
|
+ ASSERT_ENTRY_INITIALIZED();
|
|
|
+ ThreadContextTLSEntry* entry = ENTRY_FOR_CURRENT_THREAD();
|
|
|
+ if (entry != NULL)
|
|
|
{
|
|
|
HeapDelete(entry);
|
|
|
- s_tlvSlot = nullptr;
|
|
|
+ TlsSetValue(s_tlsSlot, NULL);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool ThreadContextTLSEntry::TrySetThreadContext(ThreadContext * threadContext)
|
|
|
{
|
|
|
Assert(threadContext != NULL);
|
|
|
+ ASSERT_ENTRY_INITIALIZED();
|
|
|
|
|
|
DWORD threadContextThreadId = threadContext->GetCurrentThreadId();
|
|
|
|
|
|
@@ -32,13 +82,15 @@ bool ThreadContextTLSEntry::TrySetThreadContext(ThreadContext * threadContext)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- ThreadContextTLSEntry * entry = s_tlvSlot;
|
|
|
+ ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
|
|
|
|
|
|
- if (entry == nullptr)
|
|
|
+ if (entry == NULL)
|
|
|
{
|
|
|
Assert(!threadContext->IsThreadBound());
|
|
|
entry = CreateEntryForCurrentThread();
|
|
|
- s_tlvSlot = entry;
|
|
|
+#ifndef _WIN32
|
|
|
+ ENTRY_FOR_CURRENT_THREAD() = entry;
|
|
|
+#endif
|
|
|
}
|
|
|
else if (entry->threadContext != NULL && entry->threadContext != threadContext)
|
|
|
{
|
|
|
@@ -67,12 +119,14 @@ void ThreadContextTLSEntry::SetThreadContext(ThreadContextTLSEntry * entry, Thre
|
|
|
|
|
|
bool ThreadContextTLSEntry::ClearThreadContext(bool isValid)
|
|
|
{
|
|
|
- return ClearThreadContext(s_tlvSlot, isValid, false);
|
|
|
+ return ClearThreadContext(ENTRY_FOR_CURRENT_THREAD(), isValid, false);
|
|
|
}
|
|
|
|
|
|
bool ThreadContextTLSEntry::ClearThreadContext(ThreadContextTLSEntry * entry, bool isThreadContextValid, bool force)
|
|
|
{
|
|
|
- if (entry != nullptr)
|
|
|
+ ASSERT_ENTRY_INITIALIZED();
|
|
|
+
|
|
|
+ if (entry != NULL)
|
|
|
{
|
|
|
if (entry->threadContext != NULL && isThreadContextValid)
|
|
|
{
|
|
|
@@ -100,15 +154,25 @@ void ThreadContextTLSEntry::Delete(ThreadContextTLSEntry * entry)
|
|
|
|
|
|
ThreadContextTLSEntry * ThreadContextTLSEntry::GetEntryForCurrentThread()
|
|
|
{
|
|
|
- return s_tlvSlot;
|
|
|
+ ASSERT_ENTRY_INITIALIZED();
|
|
|
+#ifdef _WIN32
|
|
|
+ return reinterpret_cast<ThreadContextTLSEntry *>(TlsGetValue(s_tlsSlot));
|
|
|
+#else
|
|
|
+ return ENTRY_FOR_CURRENT_THREAD();
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
ThreadContextTLSEntry * ThreadContextTLSEntry::CreateEntryForCurrentThread()
|
|
|
{
|
|
|
+ ASSERT_ENTRY_INITIALIZED();
|
|
|
+#ifdef _WIN32
|
|
|
+ Assert(TlsGetValue(s_tlsSlot) == NULL);
|
|
|
+#endif
|
|
|
+
|
|
|
ThreadContextTLSEntry * entry = HeapNewStructZ(ThreadContextTLSEntry);
|
|
|
#pragma prefast(suppress:6001, "Memory from HeapNewStructZ are zero initialized")
|
|
|
entry->prober.Initialize();
|
|
|
- s_tlvSlot = entry;
|
|
|
+ TlsSetValue(s_tlsSlot, entry);
|
|
|
|
|
|
return entry;
|
|
|
}
|
|
|
@@ -120,8 +184,8 @@ ThreadContext * ThreadContextTLSEntry::GetThreadContext()
|
|
|
|
|
|
ThreadContextId ThreadContextTLSEntry::GetCurrentThreadContextId()
|
|
|
{
|
|
|
- ThreadContextTLSEntry * entry = s_tlvSlot;
|
|
|
- if (entry != nullptr && entry->GetThreadContext() != NULL)
|
|
|
+ ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
|
|
|
+ if (entry != NULL && entry->GetThreadContext() != NULL)
|
|
|
{
|
|
|
return (ThreadContextId)entry->GetThreadContext();
|
|
|
}
|