thread.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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__)) || BX_PLATFORM_BSD
  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_WINDOWS && BX_COMPILER_MSVC
  142. # pragma pack(push, 8)
  143. struct ThreadName
  144. {
  145. DWORD type;
  146. LPCSTR name;
  147. DWORD id;
  148. DWORD flags;
  149. };
  150. # pragma pack(pop)
  151. ThreadName tn;
  152. tn.type = 0x1000;
  153. tn.name = _name;
  154. tn.id = m_threadId;
  155. tn.flags = 0;
  156. __try
  157. {
  158. RaiseException(0x406d1388
  159. , 0
  160. , sizeof(tn)/4
  161. , reinterpret_cast<ULONG_PTR*>(&tn)
  162. );
  163. }
  164. __except(EXCEPTION_EXECUTE_HANDLER)
  165. {
  166. }
  167. #else
  168. BX_UNUSED(_name);
  169. #endif // BX_PLATFORM_
  170. }
  171. private:
  172. int32_t entry()
  173. {
  174. #if BX_PLATFORM_WINDOWS
  175. m_threadId = ::GetCurrentThreadId();
  176. #endif // BX_PLATFORM_WINDOWS
  177. m_sem.post();
  178. return m_fn(m_userData);
  179. }
  180. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT
  181. static DWORD WINAPI threadFunc(LPVOID _arg)
  182. {
  183. Thread* thread = (Thread*)_arg;
  184. int32_t result = thread->entry();
  185. return result;
  186. }
  187. #else
  188. static void* threadFunc(void* _arg)
  189. {
  190. Thread* thread = (Thread*)_arg;
  191. union
  192. {
  193. void* ptr;
  194. int32_t i;
  195. } cast;
  196. cast.i = thread->entry();
  197. return cast.ptr;
  198. }
  199. #endif // BX_PLATFORM_
  200. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT
  201. HANDLE m_handle;
  202. DWORD m_threadId;
  203. #elif BX_PLATFORM_POSIX
  204. pthread_t m_handle;
  205. #endif // BX_PLATFORM_
  206. ThreadFn m_fn;
  207. void* m_userData;
  208. Semaphore m_sem;
  209. uint32_t m_stackSize;
  210. int32_t m_exitCode;
  211. bool m_running;
  212. };
  213. #if BX_PLATFORM_WINDOWS
  214. class TlsData
  215. {
  216. public:
  217. TlsData()
  218. {
  219. m_id = TlsAlloc();
  220. BX_CHECK(TLS_OUT_OF_INDEXES != m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
  221. }
  222. ~TlsData()
  223. {
  224. BOOL result = TlsFree(m_id);
  225. BX_CHECK(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
  226. }
  227. void* get() const
  228. {
  229. return TlsGetValue(m_id);
  230. }
  231. void set(void* _ptr)
  232. {
  233. TlsSetValue(m_id, _ptr);
  234. }
  235. private:
  236. uint32_t m_id;
  237. };
  238. #elif !BX_PLATFORM_WINRT
  239. class TlsData
  240. {
  241. public:
  242. TlsData()
  243. {
  244. int result = pthread_key_create(&m_id, NULL);
  245. BX_CHECK(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
  246. }
  247. ~TlsData()
  248. {
  249. int result = pthread_key_delete(m_id);
  250. BX_CHECK(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
  251. }
  252. void* get() const
  253. {
  254. return pthread_getspecific(m_id);
  255. }
  256. void set(void* _ptr)
  257. {
  258. int result = pthread_setspecific(m_id, _ptr);
  259. BX_CHECK(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
  260. }
  261. private:
  262. pthread_key_t m_id;
  263. };
  264. #endif // BX_PLATFORM_*
  265. } // namespace bx
  266. #endif // BX_CONFIG_SUPPORTS_THREADING
  267. #endif // BX_THREAD_H_HEADER_GUARD