ThreadContextTlsEntry.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. #ifdef RECYCLER_WRITE_BARRIER
  80. #ifdef TARGET_64
  81. if (!Memory::RecyclerWriteBarrierManager::OnThreadInit())
  82. {
  83. return false;
  84. }
  85. #endif
  86. #endif
  87. entry = CreateEntryForCurrentThread();
  88. #ifndef _WIN32
  89. ENTRY_FOR_CURRENT_THREAD() = entry;
  90. #endif
  91. }
  92. else if (entry->threadContext != NULL)
  93. {
  94. if (entry->threadContext == threadContext)
  95. {
  96. return true;
  97. }
  98. else
  99. {
  100. // If the thread has an active thread context and either that thread context is thread
  101. // bound (in which case it cannot be moved off this thread), or if the thread context
  102. // is running script, you cannot move it off this thread.
  103. if (entry->threadContext->IsThreadBound() || entry->threadContext->IsInScript())
  104. {
  105. return false;
  106. }
  107. ClearThreadContext(entry, true);
  108. }
  109. }
  110. SetThreadContext(entry, threadContext);
  111. return true;
  112. }
  113. void ThreadContextTLSEntry::SetThreadContext(ThreadContextTLSEntry * entry, ThreadContext * threadContext)
  114. {
  115. entry->threadContext = threadContext;
  116. threadContext->SetStackProber(&entry->prober);
  117. threadContext->SetCurrentThreadId(::GetCurrentThreadId());
  118. }
  119. bool ThreadContextTLSEntry::ClearThreadContext(bool isValid)
  120. {
  121. return ClearThreadContext(ENTRY_FOR_CURRENT_THREAD(), isValid, false);
  122. }
  123. bool ThreadContextTLSEntry::ClearThreadContext(ThreadContextTLSEntry * entry, bool isThreadContextValid, bool force)
  124. {
  125. ASSERT_ENTRY_INITIALIZED();
  126. if (entry != NULL)
  127. {
  128. if (entry->threadContext != NULL && isThreadContextValid)
  129. {
  130. // If the thread has an active thread context and either that thread context is thread
  131. // bound (in which case it cannot be moved off this thread), or if the thread context
  132. // is running script, you cannot move it off this thread.
  133. if (!force && (entry->threadContext->IsThreadBound() || entry->threadContext->IsInScript()))
  134. {
  135. return false;
  136. }
  137. entry->threadContext->SetCurrentThreadId(ThreadContext::NoThread);
  138. entry->threadContext->SetStackProber(NULL);
  139. }
  140. entry->threadContext = NULL;
  141. }
  142. return true;
  143. }
  144. void ThreadContextTLSEntry::Delete(ThreadContextTLSEntry * entry)
  145. {
  146. HeapDelete(entry);
  147. }
  148. ThreadContextTLSEntry * ThreadContextTLSEntry::GetEntryForCurrentThread()
  149. {
  150. ASSERT_ENTRY_INITIALIZED();
  151. #ifdef _WIN32
  152. return reinterpret_cast<ThreadContextTLSEntry *>(TlsGetValue(s_tlsSlot));
  153. #else
  154. return ENTRY_FOR_CURRENT_THREAD();
  155. #endif
  156. }
  157. ThreadContextTLSEntry * ThreadContextTLSEntry::CreateEntryForCurrentThread()
  158. {
  159. ASSERT_ENTRY_INITIALIZED();
  160. #ifdef _WIN32
  161. Assert(TlsGetValue(s_tlsSlot) == NULL);
  162. #endif
  163. ThreadContextTLSEntry * entry = HeapNewStructZ(ThreadContextTLSEntry);
  164. #pragma prefast(suppress:6001, "Memory from HeapNewStructZ are zero initialized")
  165. entry->prober.Initialize();
  166. TlsSetValue(s_tlsSlot, entry);
  167. return entry;
  168. }
  169. ThreadContext * ThreadContextTLSEntry::GetThreadContext()
  170. {
  171. return this->threadContext;
  172. }
  173. ThreadContextId ThreadContextTLSEntry::GetCurrentThreadContextId()
  174. {
  175. ThreadContextTLSEntry * entry = ENTRY_FOR_CURRENT_THREAD();
  176. if (entry != NULL && entry->GetThreadContext() != NULL)
  177. {
  178. return (ThreadContextId)entry->GetThreadContext();
  179. }
  180. return NoThreadContextId;
  181. }
  182. ThreadContextId ThreadContextTLSEntry::GetThreadContextId(ThreadContext * threadContext)
  183. {
  184. return threadContext;
  185. }