thread.h 6.5 KB

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