thread.h 6.7 KB

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