ThreadContextTlsEntry.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeBasePch.h"
  6. #include "Base/ThreadContextTlsEntry.h"
  7. #ifdef _WIN32
  8. uint32 ThreadContextTLSEntry::s_tlsSlot = TLS_OUT_OF_INDEXES;
  9. #define ENTRY_FOR_CURRENT_THREAD() GetEntryForCurrentThread()
  10. #define ASSERT_ENTRY_INITIALIZED() Assert(s_tlsSlot != TLS_OUT_OF_INDEXES)
  11. #else // !_WIN32
  12. // entry doesn't need a special initialization
  13. #define ASSERT_ENTRY_INITIALIZED() Assert(true)
  14. static THREAD_LOCAL ThreadContextTLSEntry* s_tlsSlot = nullptr;
  15. #define TlsSetValue(a,b) a = b
  16. // clang may not optimize the access to THREAD_LOCAL from a sub function
  17. #define ENTRY_FOR_CURRENT_THREAD() s_tlsSlot
  18. #endif
  19. bool ThreadContextTLSEntry::InitializeProcess()
  20. {
  21. #ifdef _WIN32
  22. Assert(s_tlsSlot == TLS_OUT_OF_INDEXES);
  23. s_tlsSlot = TlsAlloc();
  24. return (s_tlsSlot != TLS_OUT_OF_INDEXES);
  25. #else
  26. return true;
  27. #endif
  28. }
  29. void ThreadContextTLSEntry::CleanupProcess()
  30. {
  31. #ifdef _WIN32
  32. Assert(s_tlsSlot != TLS_OUT_OF_INDEXES);
  33. TlsFree(s_tlsSlot);
  34. s_tlsSlot = TLS_OUT_OF_INDEXES;
  35. #endif
  36. }
  37. bool ThreadContextTLSEntry::IsProcessInitialized()
  38. {
  39. #ifdef _WIN32
  40. return s_tlsSlot != TLS_OUT_OF_INDEXES;
  41. #else
  42. return true;
  43. #endif
  44. }
  45. void ThreadContextTLSEntry::InitializeThread()
  46. {
  47. #ifdef _WIN32
  48. Assert(s_tlsSlot != TLS_OUT_OF_INDEXES);
  49. Assert(!TlsGetValue(s_tlsSlot));
  50. TlsSetValue(s_tlsSlot, NULL);
  51. #endif
  52. }
  53. void ThreadContextTLSEntry::CleanupThread()
  54. {
  55. ASSERT_ENTRY_INITIALIZED();
  56. ThreadContextTLSEntry* entry = ENTRY_FOR_CURRENT_THREAD();
  57. if (entry != NULL)
  58. {
  59. HeapDelete(entry);
  60. TlsSetValue(s_tlsSlot, NULL);
  61. }
  62. }
  63. bool ThreadContextTLSEntry::TrySetThreadContext(ThreadContext * threadContext)
  64. {
  65. Assert(threadContext != NULL);
  66. ASSERT_ENTRY_INITIALIZED();
  67. DWORD threadContextThreadId = threadContext->GetCurrentThreadId();
  68. // If a thread context is current on another thread, then you cannot set it to current on this one.
  69. if (threadContextThreadId != ThreadContext::NoThread && threadContextThreadId != ::GetCurrentThreadId())
  70. {
  71. // the thread doesn't support rental thread and try to set on a different thread???
  72. Assert(!threadContext->IsThreadBound());
  73. return false;
  74. }
  75. ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
  76. if (entry == NULL)
  77. {
  78. Assert(!threadContext->IsThreadBound());
  79. entry = CreateEntryForCurrentThread();
  80. #ifndef _WIN32
  81. ENTRY_FOR_CURRENT_THREAD() = entry;
  82. #endif
  83. }
  84. else if (entry->threadContext != NULL)
  85. {
  86. if (entry->threadContext == threadContext)
  87. {
  88. return true;
  89. }
  90. else
  91. {
  92. // If the thread has an active thread context and either that thread context is thread
  93. // bound (in which case it cannot be moved off this thread), or if the thread context
  94. // is running script, you cannot move it off this thread.
  95. if (entry->threadContext->IsThreadBound() || entry->threadContext->IsInScript())
  96. {
  97. return false;
  98. }
  99. ClearThreadContext(entry, true);
  100. }
  101. }
  102. SetThreadContext(entry, threadContext);
  103. return true;
  104. }
  105. void ThreadContextTLSEntry::SetThreadContext(ThreadContextTLSEntry * entry, ThreadContext * threadContext)
  106. {
  107. entry->threadContext = threadContext;
  108. threadContext->SetStackProber(&entry->prober);
  109. threadContext->SetCurrentThreadId(::GetCurrentThreadId());
  110. }
  111. bool ThreadContextTLSEntry::ClearThreadContext(bool isValid)
  112. {
  113. return ClearThreadContext(ENTRY_FOR_CURRENT_THREAD(), isValid, false);
  114. }
  115. bool ThreadContextTLSEntry::ClearThreadContext(ThreadContextTLSEntry * entry, bool isThreadContextValid, bool force)
  116. {
  117. ASSERT_ENTRY_INITIALIZED();
  118. if (entry != NULL)
  119. {
  120. if (entry->threadContext != NULL && isThreadContextValid)
  121. {
  122. // If the thread has an active thread context and either that thread context is thread
  123. // bound (in which case it cannot be moved off this thread), or if the thread context
  124. // is running script, you cannot move it off this thread.
  125. if (!force && (entry->threadContext->IsThreadBound() || entry->threadContext->IsInScript()))
  126. {
  127. return false;
  128. }
  129. entry->threadContext->SetCurrentThreadId(ThreadContext::NoThread);
  130. entry->threadContext->SetStackProber(NULL);
  131. }
  132. entry->threadContext = NULL;
  133. }
  134. return true;
  135. }
  136. void ThreadContextTLSEntry::Delete(ThreadContextTLSEntry * entry)
  137. {
  138. HeapDelete(entry);
  139. }
  140. ThreadContextTLSEntry * ThreadContextTLSEntry::GetEntryForCurrentThread()
  141. {
  142. ASSERT_ENTRY_INITIALIZED();
  143. #ifdef _WIN32
  144. return reinterpret_cast<ThreadContextTLSEntry *>(TlsGetValue(s_tlsSlot));
  145. #else
  146. return ENTRY_FOR_CURRENT_THREAD();
  147. #endif
  148. }
  149. ThreadContextTLSEntry * ThreadContextTLSEntry::CreateEntryForCurrentThread()
  150. {
  151. ASSERT_ENTRY_INITIALIZED();
  152. #ifdef _WIN32
  153. Assert(TlsGetValue(s_tlsSlot) == NULL);
  154. #endif
  155. ThreadContextTLSEntry * entry = HeapNewStructZ(ThreadContextTLSEntry);
  156. #pragma prefast(suppress:6001, "Memory from HeapNewStructZ are zero initialized")
  157. entry->prober.Initialize();
  158. TlsSetValue(s_tlsSlot, entry);
  159. return entry;
  160. }
  161. ThreadContext * ThreadContextTLSEntry::GetThreadContext()
  162. {
  163. return this->threadContext;
  164. }
  165. ThreadContextId ThreadContextTLSEntry::GetCurrentThreadContextId()
  166. {
  167. ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
  168. if (entry != NULL && entry->GetThreadContext() != NULL)
  169. {
  170. return (ThreadContextId)entry->GetThreadContext();
  171. }
  172. return NoThreadContextId;
  173. }
  174. ThreadContextId ThreadContextTLSEntry::GetThreadContextId(ThreadContext * threadContext)
  175. {
  176. return threadContext;
  177. }