| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "RuntimeBasePch.h"
- #include "Base/ThreadContextTlsEntry.h"
- #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::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()
- {
- #ifdef _WIN32
- Assert(s_tlsSlot != TLS_OUT_OF_INDEXES);
- Assert(!TlsGetValue(s_tlsSlot));
- TlsSetValue(s_tlsSlot, NULL);
- #endif
- }
- void ThreadContextTLSEntry::CleanupThread()
- {
- ASSERT_ENTRY_INITIALIZED();
- ThreadContextTLSEntry* entry = ENTRY_FOR_CURRENT_THREAD();
- if (entry != NULL)
- {
- HeapDelete(entry);
- TlsSetValue(s_tlsSlot, NULL);
- }
- }
- bool ThreadContextTLSEntry::TrySetThreadContext(ThreadContext * threadContext)
- {
- Assert(threadContext != NULL);
- ASSERT_ENTRY_INITIALIZED();
- DWORD threadContextThreadId = threadContext->GetCurrentThreadId();
- // If a thread context is current on another thread, then you cannot set it to current on this one.
- if (threadContextThreadId != ThreadContext::NoThread && threadContextThreadId != ::GetCurrentThreadId())
- {
- // the thread doesn't support rental thread and try to set on a different thread???
- Assert(!threadContext->IsThreadBound());
- return false;
- }
- ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
- if (entry == NULL)
- {
- Assert(!threadContext->IsThreadBound());
- entry = CreateEntryForCurrentThread();
- #ifndef _WIN32
- ENTRY_FOR_CURRENT_THREAD() = entry;
- #endif
- }
- else if (entry->threadContext != NULL)
- {
- if (entry->threadContext == threadContext)
- {
- return true;
- }
- else
- {
- // If the thread has an active thread context and either that thread context is thread
- // bound (in which case it cannot be moved off this thread), or if the thread context
- // is running script, you cannot move it off this thread.
- if (entry->threadContext->IsThreadBound() || entry->threadContext->IsInScript())
- {
- return false;
- }
- ClearThreadContext(entry, true);
- }
- }
- SetThreadContext(entry, threadContext);
- return true;
- }
- void ThreadContextTLSEntry::SetThreadContext(ThreadContextTLSEntry * entry, ThreadContext * threadContext)
- {
- entry->threadContext = threadContext;
- threadContext->SetStackProber(&entry->prober);
- threadContext->SetCurrentThreadId(::GetCurrentThreadId());
- }
- bool ThreadContextTLSEntry::ClearThreadContext(bool isValid)
- {
- return ClearThreadContext(ENTRY_FOR_CURRENT_THREAD(), isValid, false);
- }
- bool ThreadContextTLSEntry::ClearThreadContext(ThreadContextTLSEntry * entry, bool isThreadContextValid, bool force)
- {
- ASSERT_ENTRY_INITIALIZED();
- if (entry != NULL)
- {
- if (entry->threadContext != NULL && isThreadContextValid)
- {
- // If the thread has an active thread context and either that thread context is thread
- // bound (in which case it cannot be moved off this thread), or if the thread context
- // is running script, you cannot move it off this thread.
- if (!force && (entry->threadContext->IsThreadBound() || entry->threadContext->IsInScript()))
- {
- return false;
- }
- entry->threadContext->SetCurrentThreadId(ThreadContext::NoThread);
- entry->threadContext->SetStackProber(NULL);
- }
- entry->threadContext = NULL;
- }
- return true;
- }
- void ThreadContextTLSEntry::Delete(ThreadContextTLSEntry * entry)
- {
- HeapDelete(entry);
- }
- ThreadContextTLSEntry * ThreadContextTLSEntry::GetEntryForCurrentThread()
- {
- 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();
- TlsSetValue(s_tlsSlot, entry);
- return entry;
- }
- ThreadContext * ThreadContextTLSEntry::GetThreadContext()
- {
- return this->threadContext;
- }
- ThreadContextId ThreadContextTLSEntry::GetCurrentThreadContextId()
- {
- ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
- if (entry != NULL && entry->GetThreadContext() != NULL)
- {
- return (ThreadContextId)entry->GetThreadContext();
- }
- return NoThreadContextId;
- }
- ThreadContextId ThreadContextTLSEntry::GetThreadContextId(ThreadContext * threadContext)
- {
- return threadContext;
- }
|