thread.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * Copyright 2010-2016 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #ifndef BX_THREAD_H_HEADER_GUARD
  6. #define BX_THREAD_H_HEADER_GUARD
  7. #if BX_PLATFORM_POSIX
  8. # include <pthread.h>
  9. #if defined(__GLIBC__)
  10. #if!((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
  11. #include <sys/prctl.h>
  12. #endif
  13. #endif
  14. #elif BX_PLATFORM_WINRT
  15. using namespace Platform;
  16. using namespace Windows::Foundation;
  17. using namespace Windows::System::Threading;
  18. #endif
  19. #include "sem.h"
  20. #if BX_CONFIG_SUPPORTS_THREADING
  21. namespace bx
  22. {
  23. typedef int32_t (*ThreadFn)(void* _userData);
  24. class Thread
  25. {
  26. BX_CLASS(Thread
  27. , NO_COPY
  28. , NO_ASSIGNMENT
  29. );
  30. public:
  31. Thread()
  32. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT
  33. : m_handle(INVALID_HANDLE_VALUE)
  34. , m_threadId(UINT32_MAX)
  35. #elif BX_PLATFORM_POSIX
  36. : m_handle(0)
  37. #endif // BX_PLATFORM_
  38. , m_fn(NULL)
  39. , m_userData(NULL)
  40. , m_stackSize(0)
  41. , m_exitCode(0 /*EXIT_SUCCESS*/)
  42. , m_running(false)
  43. {
  44. }
  45. virtual ~Thread()
  46. {
  47. if (m_running)
  48. {
  49. shutdown();
  50. }
  51. }
  52. void init(ThreadFn _fn, void* _userData = NULL, uint32_t _stackSize = 0, const char* _name = NULL)
  53. {
  54. BX_CHECK(!m_running, "Already running!");
  55. m_fn = _fn;
  56. m_userData = _userData;
  57. m_stackSize = _stackSize;
  58. m_running = true;
  59. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360
  60. m_handle = ::CreateThread(NULL
  61. , m_stackSize
  62. , (LPTHREAD_START_ROUTINE)threadFunc
  63. , this
  64. , 0
  65. , NULL
  66. );
  67. #elif BX_PLATFORM_WINRT
  68. m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
  69. auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
  70. {
  71. m_exitCode = threadFunc(this);
  72. SetEvent(m_handle);
  73. }, CallbackContext::Any);
  74. ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
  75. #elif BX_PLATFORM_POSIX
  76. int result;
  77. BX_UNUSED(result);
  78. pthread_attr_t attr;
  79. result = pthread_attr_init(&attr);
  80. BX_CHECK(0 == result, "pthread_attr_init failed! %d", result);
  81. if (0 != m_stackSize)
  82. {
  83. result = pthread_attr_setstacksize(&attr, m_stackSize);
  84. BX_CHECK(0 == result, "pthread_attr_setstacksize failed! %d", result);
  85. }
  86. // sched_param sched;
  87. // sched.sched_priority = 0;
  88. // result = pthread_attr_setschedparam(&attr, &sched);
  89. // BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
  90. result = pthread_create(&m_handle, &attr, &threadFunc, this);
  91. BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
  92. #endif // BX_PLATFORM_
  93. m_sem.wait();
  94. if (NULL != _name)
  95. {
  96. setThreadName(_name);
  97. }
  98. }
  99. void shutdown()
  100. {
  101. BX_CHECK(m_running, "Not running!");
  102. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360
  103. WaitForSingleObject(m_handle, INFINITE);
  104. GetExitCodeThread(m_handle, (DWORD*)&m_exitCode);
  105. CloseHandle(m_handle);
  106. m_handle = INVALID_HANDLE_VALUE;
  107. #elif BX_PLATFORM_WINRT
  108. WaitForSingleObjectEx(m_handle, INFINITE, FALSE);
  109. CloseHandle(m_handle);
  110. m_handle = INVALID_HANDLE_VALUE;
  111. #elif BX_PLATFORM_POSIX
  112. union
  113. {
  114. void* ptr;
  115. int32_t i;
  116. } cast;
  117. pthread_join(m_handle, &cast.ptr);
  118. m_exitCode = cast.i;
  119. m_handle = 0;
  120. #endif // BX_PLATFORM_
  121. m_running = false;
  122. }
  123. bool isRunning() const
  124. {
  125. return m_running;
  126. }
  127. int32_t getExitCode() const
  128. {
  129. return m_exitCode;
  130. }
  131. void setThreadName(const char* _name)
  132. {
  133. #if BX_PLATFORM_OSX || BX_PLATFORM_IOS
  134. pthread_setname_np(_name);
  135. #elif (BX_PLATFORM_LINUX && defined(__GLIBC__))
  136. #if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12))
  137. pthread_setname_np(m_handle, _name);
  138. #else
  139. prctl(PR_SET_NAME,_name,0,0,0);
  140. #endif
  141. #elif BX_PLATFORM_BSD
  142. pthread_setname_np(m_handle, _name);
  143. #elif BX_PLATFORM_WINDOWS && BX_COMPILER_MSVC
  144. # pragma pack(push, 8)
  145. struct ThreadName
  146. {
  147. DWORD type;
  148. LPCSTR name;
  149. DWORD id;
  150. DWORD flags;
  151. };
  152. # pragma pack(pop)
  153. ThreadName tn;
  154. tn.type = 0x1000;
  155. tn.name = _name;
  156. tn.id = m_threadId;
  157. tn.flags = 0;
  158. __try
  159. {
  160. RaiseException(0x406d1388
  161. , 0
  162. , sizeof(tn)/4
  163. , reinterpret_cast<ULONG_PTR*>(&tn)
  164. );
  165. }
  166. __except(EXCEPTION_EXECUTE_HANDLER)
  167. {
  168. }
  169. #else
  170. BX_UNUSED(_name);
  171. #endif // BX_PLATFORM_
  172. }
  173. private:
  174. int32_t entry()
  175. {
  176. #if BX_PLATFORM_WINDOWS
  177. m_threadId = ::GetCurrentThreadId();
  178. #endif // BX_PLATFORM_WINDOWS
  179. m_sem.post();
  180. return m_fn(m_userData);
  181. }
  182. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT
  183. static DWORD WINAPI threadFunc(LPVOID _arg)
  184. {
  185. Thread* thread = (Thread*)_arg;
  186. int32_t result = thread->entry();
  187. return result;
  188. }
  189. #else
  190. static void* threadFunc(void* _arg)
  191. {
  192. Thread* thread = (Thread*)_arg;
  193. union
  194. {
  195. void* ptr;
  196. int32_t i;
  197. } cast;
  198. cast.i = thread->entry();
  199. return cast.ptr;
  200. }
  201. #endif // BX_PLATFORM_
  202. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT
  203. HANDLE m_handle;
  204. DWORD m_threadId;
  205. #elif BX_PLATFORM_POSIX
  206. pthread_t m_handle;
  207. #endif // BX_PLATFORM_
  208. ThreadFn m_fn;
  209. void* m_userData;
  210. Semaphore m_sem;
  211. uint32_t m_stackSize;
  212. int32_t m_exitCode;
  213. bool m_running;
  214. };
  215. #if BX_PLATFORM_WINDOWS
  216. class TlsData
  217. {
  218. public:
  219. TlsData()
  220. {
  221. m_id = TlsAlloc();
  222. BX_CHECK(TLS_OUT_OF_INDEXES != m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
  223. }
  224. ~TlsData()
  225. {
  226. BOOL result = TlsFree(m_id);
  227. BX_CHECK(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
  228. }
  229. void* get() const
  230. {
  231. return TlsGetValue(m_id);
  232. }
  233. void set(void* _ptr)
  234. {
  235. TlsSetValue(m_id, _ptr);
  236. }
  237. private:
  238. uint32_t m_id;
  239. };
  240. #elif !BX_PLATFORM_WINRT
  241. class TlsData
  242. {
  243. public:
  244. TlsData()
  245. {
  246. int result = pthread_key_create(&m_id, NULL);
  247. BX_CHECK(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
  248. }
  249. ~TlsData()
  250. {
  251. int result = pthread_key_delete(m_id);
  252. BX_CHECK(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
  253. }
  254. void* get() const
  255. {
  256. return pthread_getspecific(m_id);
  257. }
  258. void set(void* _ptr)
  259. {
  260. int result = pthread_setspecific(m_id, _ptr);
  261. BX_CHECK(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
  262. }
  263. private:
  264. pthread_key_t m_id;
  265. };
  266. #endif // BX_PLATFORM_*
  267. } // namespace bx
  268. #endif // BX_CONFIG_SUPPORTS_THREADING
  269. #endif // BX_THREAD_H_HEADER_GUARD