Thread.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #include "BeefySysLib/Common.h"
  2. #include "BfObjects.h"
  3. #include "Thread.h"
  4. //#include "ThreadLocalStorage.h"
  5. #include "StompAlloc.h"
  6. //#include <crtdbg.h>
  7. //#define USE_STOMP_ALLOC
  8. #undef MemoryBarrier
  9. using namespace bf::System;
  10. using namespace bf::System::Threading;
  11. #ifdef BF_THREAD_TLS
  12. BF_TLS_DECLSPEC Thread* Thread::sCurrentThread;
  13. #endif
  14. static volatile int gLiveThreadCount;
  15. static volatile int gBackgroundThreadCount;
  16. static Beefy::SyncEvent gThreadsDoneEvent;
  17. #ifdef BF_PLATFORM_WINDOWS
  18. extern DWORD gBfTLSKey;
  19. #else
  20. extern pthread_key_t gBfTLSKey;
  21. #endif
  22. bf::System::Threading::Thread* BfGetCurrentThread()
  23. {
  24. #ifdef BF_THREAD_TLS
  25. return Thread::sCurrentThread;
  26. #else
  27. Thread* internalThread = (Thread*)BfpTLS_GetValue(BfTLSManager::sInternalThreadKey);
  28. return internalThread;
  29. #endif
  30. }
  31. void Thread::Suspend()
  32. {
  33. BfpThread_Suspend(GetInternalThread()->mThreadHandle, NULL);
  34. }
  35. void Thread::Resume()
  36. {
  37. BfpThread_Resume(GetInternalThread()->mThreadHandle, NULL);
  38. }
  39. void Thread::SetJoinOnDelete(bool joinOnDelete)
  40. {
  41. auto internalThread = GetInternalThread();
  42. Beefy::AutoCrit autoCrit(internalThread->mCritSect);
  43. internalThread->mJoinOnDelete = joinOnDelete;
  44. }
  45. int Thread::GetPriorityNative()
  46. {
  47. return (int)BfpThread_GetPriority(GetInternalThread()->mThreadHandle, NULL) + 2;
  48. }
  49. void Thread::SetPriorityNative(int priority)
  50. {
  51. return BfpThread_SetPriority(GetInternalThread()->mThreadHandle, (BfpThreadPriority)(priority - 2), NULL);
  52. }
  53. bool Thread::GetIsAlive()
  54. {
  55. if (GetInternalThread() == NULL)
  56. return false;
  57. bool success = BfpThread_WaitFor(GetInternalThread()->mThreadHandle, 0);
  58. return !success;
  59. }
  60. bool Thread::GetIsThreadPoolThread()
  61. {
  62. return false;
  63. }
  64. bool Thread::JoinInternal(int millisecondsTimeout)
  65. {
  66. auto internalThread = GetInternalThread();
  67. if (internalThread == NULL)
  68. return true;
  69. bool success = BfpThread_WaitFor(internalThread->mThreadHandle, millisecondsTimeout);
  70. return success;
  71. }
  72. void Thread::SleepInternal(int millisecondsTimeout)
  73. {
  74. BfpThread_Sleep(millisecondsTimeout);
  75. }
  76. void Thread::SpinWaitInternal(int iterations)
  77. {
  78. BF_COMPILER_FENCE();
  79. BF_SPINWAIT_NOP();
  80. }
  81. bool Thread::YieldInternal()
  82. {
  83. return BfpThread_Yield();
  84. }
  85. Thread* Thread::GetCurrentThreadNative()
  86. {
  87. return BfGetCurrentThread();
  88. }
  89. unsigned long Thread::GetProcessDefaultStackSize()
  90. {
  91. return 0;
  92. }
  93. static void BF_CALLTYPE CStartProc(void* threadParam)
  94. {
  95. Thread* thread = (Thread*)threadParam;
  96. #ifdef BF_THREAD_TLS
  97. Thread::sCurrentThread = thread;
  98. #else
  99. BfpTLS_SetValue(BfTLSManager::sInternalThreadKey, thread);
  100. #endif
  101. auto internalThread = thread->GetInternalThread();
  102. // Hold lock until we get ThreadStarted callback
  103. internalThread->mCritSect.Lock();
  104. internalThread->mStartedEvent.Set(true);
  105. internalThread->mThreadHandle = BfpThread_GetCurrent();
  106. internalThread->mStackStart = (intptr)&thread;
  107. internalThread->ThreadStarted();
  108. bool isAutoDelete = gBfRtCallbacks.Thread_IsAutoDelete(thread);
  109. gBfRtCallbacks.Thread_ThreadProc(thread);
  110. if (internalThread->mIsBackground)
  111. BfpSystem_InterlockedExchangeAdd32((uint32*)&gBackgroundThreadCount, -1);
  112. bool isLastThread = (int32)BfpSystem_InterlockedExchangeAdd32((uint32*)&gLiveThreadCount, -1) <= gBackgroundThreadCount + 1;
  113. //printf("Stopping thread\n");
  114. bool wantsDelete = false;
  115. //
  116. {
  117. internalThread->ThreadStopped();
  118. Beefy::AutoCrit autoCrit(internalThread->mCritSect);
  119. if (isAutoDelete)
  120. gBfRtCallbacks.Thread_AutoDelete(thread);
  121. internalThread->mDone = true;
  122. if (internalThread->mThread == NULL)
  123. {
  124. // If the thread was already deleted then we need to delete ourselves now
  125. wantsDelete = true;
  126. }
  127. }
  128. if (wantsDelete)
  129. delete internalThread;
  130. if (isLastThread)
  131. gThreadsDoneEvent.Set(false);
  132. //printf("Thread stopped\n");
  133. }
  134. void BfInternalThread::WaitForAllDone()
  135. {
  136. if ((gBfRtFlags & BfRtFlags_NoThreadExitWait) != 0)
  137. return;
  138. while (gLiveThreadCount > gBackgroundThreadCount)
  139. {
  140. // Clear out any old done events
  141. gThreadsDoneEvent.WaitFor();
  142. }
  143. }
  144. BfInternalThread* Thread::SetupInternalThread()
  145. {
  146. BfInternalThread* internalThread;
  147. internalThread = new BfInternalThread();
  148. SetInternalThread(internalThread);
  149. return internalThread;
  150. }
  151. void Thread::ManualThreadInit()
  152. {
  153. #ifdef BF_THREAD_TLS
  154. sCurrentThread = this;
  155. #else
  156. BfpTLS_SetValue(BfTLSManager::sInternalThreadKey, this);
  157. #endif
  158. BfInternalThread* internalThread = SetupInternalThread();
  159. internalThread->ManualThreadInit(this);
  160. }
  161. void Thread::StartInternal()
  162. {
  163. BfpSystem_InterlockedExchangeAdd32((uint32*)&gLiveThreadCount, 1);
  164. BfInternalThread* internalThread = SetupInternalThread();
  165. Beefy::AutoCrit autoCrit(internalThread->mCritSect);
  166. internalThread->mStarted = true;
  167. internalThread->mThread = this;
  168. #ifdef _WIN32
  169. internalThread->mThreadHandle = BfpThread_Create(CStartProc, (void*)this, GetMaxStackSize(), (BfpThreadCreateFlags)(BfpThreadCreateFlag_StackSizeReserve | BfpThreadCreateFlag_Suspended), &internalThread->mThreadId);
  170. SetInternalThread(internalThread);
  171. BfpThread_Resume(internalThread->mThreadHandle, NULL);
  172. #else
  173. internalThread->mThreadHandle = BfpThread_Create(CStartProc, (void*)this, GetMaxStackSize(), (BfpThreadCreateFlags)(BfpThreadCreateFlag_StackSizeReserve), &internalThread->mThreadId);
  174. SetInternalThread(internalThread);
  175. #endif
  176. }
  177. void Thread::RequestExitNotify()
  178. {
  179. // Do we already have implicit exiting notification?
  180. if (BfGetCurrentThread() != NULL)
  181. return;
  182. #ifdef BF_PLATFORM_WINDOWS
  183. FlsSetValue(gBfTLSKey, (void*)&gBfRtCallbacks);
  184. #else
  185. pthread_setspecific(gBfTLSKey, (void*)&gBfRtCallbacks);
  186. #endif
  187. }
  188. void Thread::ThreadStarted()
  189. {
  190. auto internalThread = GetInternalThread();
  191. internalThread->mCritSect.Unlock();
  192. }
  193. intptr Thread::GetThreadId()
  194. {
  195. return GetInternalThread()->mThreadId;
  196. }
  197. void Thread::SetStackStart(void* ptr)
  198. {
  199. GetInternalThread()->mRunning = true;
  200. GetInternalThread()->mStackStart = (intptr)ptr;
  201. }
  202. void Thread::InternalFinalize()
  203. {
  204. auto internalThread = GetInternalThread();
  205. if (internalThread == NULL)
  206. return;
  207. bool wantsJoin = false;
  208. bool started = false;
  209. //
  210. {
  211. Beefy::AutoCrit autoCrit(internalThread->mCritSect);
  212. started = internalThread->mStarted;
  213. }
  214. if (started)
  215. internalThread->mStartedEvent.WaitFor();
  216. //
  217. {
  218. Beefy::AutoCrit autoCrit(internalThread->mCritSect);
  219. if ((!internalThread->mDone) && (internalThread->mJoinOnDelete))
  220. {
  221. if (this != BfGetCurrentThread())
  222. {
  223. wantsJoin = true;
  224. }
  225. }
  226. }
  227. if (wantsJoin)
  228. JoinInternal(0);
  229. bool wantsDelete = false;
  230. //
  231. {
  232. Beefy::AutoCrit autoCrit(internalThread->mCritSect);
  233. if (!internalThread->mDone)
  234. {
  235. // We need to let the internal thread delete itself when it's done...
  236. internalThread->mThread = NULL;
  237. }
  238. else
  239. {
  240. wantsDelete = true;
  241. }
  242. SetInternalThread(NULL);
  243. }
  244. if (internalThread->mIsManualInit)
  245. wantsDelete = true;
  246. if (wantsDelete)
  247. delete internalThread;
  248. }
  249. bool Thread::IsBackgroundNative()
  250. {
  251. auto internalThread = GetInternalThread();
  252. if (internalThread == NULL)
  253. return false;
  254. return internalThread->mIsBackground;
  255. }
  256. void Thread::SetBackgroundNative(bool isBackground)
  257. {
  258. auto internalThread = GetInternalThread();
  259. if (internalThread == NULL)
  260. return;
  261. if (isBackground != internalThread->mIsBackground)
  262. {
  263. internalThread->mIsBackground = isBackground;
  264. BfpSystem_InterlockedExchangeAdd32((uint32*)&gBackgroundThreadCount, isBackground ? 1 : -1);
  265. }
  266. }
  267. int Thread::GetThreadStateNative()
  268. {
  269. return 0;
  270. }
  271. void Thread::InformThreadNameChange(String* name)
  272. {
  273. Beefy::String nameStr;
  274. if (name != NULL)
  275. nameStr = name->ToStringView();
  276. BfpThread_SetName(GetInternalThread()->mThreadHandle, nameStr.c_str(), NULL);
  277. }
  278. void Thread::MemoryBarrier()
  279. {
  280. BF_FULL_MEMORY_FENCE();
  281. }