thread.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * Copyright 2010-2013 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/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. #elif BX_PLATFORM_WINRT
  10. using namespace Platform;
  11. using namespace Windows::Foundation;
  12. using namespace Windows::System::Threading;
  13. #endif
  14. #include "sem.h"
  15. #if BX_CONFIG_SUPPORTS_THREADING
  16. namespace bx
  17. {
  18. typedef int32_t (*ThreadFn)(void* _userData);
  19. class Thread
  20. {
  21. BX_CLASS(Thread
  22. , NO_COPY
  23. , NO_ASSIGNMENT
  24. );
  25. public:
  26. Thread()
  27. #if BX_PLATFORM_WINDOWS|BX_PLATFORM_XBOX360|BX_PLATFORM_WINRT
  28. : m_handle(INVALID_HANDLE_VALUE)
  29. #elif BX_PLATFORM_POSIX
  30. : m_handle(0)
  31. #endif // BX_PLATFORM_
  32. , m_fn(NULL)
  33. , m_userData(NULL)
  34. , m_stackSize(0)
  35. , m_exitCode(0 /*EXIT_SUCCESS*/)
  36. , m_running(false)
  37. {
  38. }
  39. virtual ~Thread()
  40. {
  41. if (m_running)
  42. {
  43. shutdown();
  44. }
  45. }
  46. void init(ThreadFn _fn, void* _userData = NULL, uint32_t _stackSize = 0)
  47. {
  48. BX_CHECK(!m_running, "Already running!");
  49. m_fn = _fn;
  50. m_userData = _userData;
  51. m_stackSize = _stackSize;
  52. m_running = true;
  53. #if BX_PLATFORM_WINDOWS|BX_PLATFORM_XBOX360
  54. m_handle = CreateThread(NULL
  55. , m_stackSize
  56. , threadFunc
  57. , this
  58. , 0
  59. , NULL
  60. );
  61. #elif BX_PLATFORM_WINRT
  62. m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
  63. auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
  64. {
  65. m_exitCode = threadFunc(this);
  66. SetEvent(m_handle);
  67. }, CallbackContext::Any);
  68. ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
  69. #elif BX_PLATFORM_POSIX
  70. int result;
  71. BX_UNUSED(result);
  72. pthread_attr_t attr;
  73. result = pthread_attr_init(&attr);
  74. BX_CHECK(0 == result, "pthread_attr_init failed! %d", result);
  75. if (0 != m_stackSize)
  76. {
  77. result = pthread_attr_setstacksize(&attr, m_stackSize);
  78. BX_CHECK(0 == result, "pthread_attr_setstacksize failed! %d", result);
  79. }
  80. // sched_param sched;
  81. // sched.sched_priority = 0;
  82. // result = pthread_attr_setschedparam(&attr, &sched);
  83. // BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
  84. result = pthread_create(&m_handle, &attr, &threadFunc, this);
  85. BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
  86. #endif // BX_PLATFORM_
  87. m_sem.wait();
  88. }
  89. void shutdown()
  90. {
  91. BX_CHECK(m_running, "Not running!");
  92. #if BX_PLATFORM_WINDOWS|BX_PLATFORM_XBOX360
  93. WaitForSingleObject(m_handle, INFINITE);
  94. GetExitCodeThread(m_handle, (DWORD*)&m_exitCode);
  95. CloseHandle(m_handle);
  96. m_handle = INVALID_HANDLE_VALUE;
  97. #elif BX_PLATFORM_WINRT
  98. WaitForSingleObjectEx(m_handle, INFINITE, FALSE);
  99. CloseHandle(m_handle);
  100. m_handle = INVALID_HANDLE_VALUE;
  101. #elif BX_PLATFORM_POSIX
  102. union
  103. {
  104. void* ptr;
  105. int32_t i;
  106. } cast;
  107. pthread_join(m_handle, &cast.ptr);
  108. m_exitCode = cast.i;
  109. m_handle = 0;
  110. #endif // BX_PLATFORM_
  111. m_running = false;
  112. }
  113. bool isRunning() const
  114. {
  115. return m_running;
  116. }
  117. int32_t getExitCode() const
  118. {
  119. return m_exitCode;
  120. }
  121. private:
  122. int32_t entry()
  123. {
  124. m_sem.post();
  125. return m_fn(m_userData);
  126. }
  127. #if BX_PLATFORM_WINDOWS|BX_PLATFORM_XBOX360|BX_PLATFORM_WINRT
  128. static DWORD WINAPI threadFunc(LPVOID _arg)
  129. {
  130. Thread* thread = (Thread*)_arg;
  131. int32_t result = thread->entry();
  132. return result;
  133. }
  134. #else
  135. static void* threadFunc(void* _arg)
  136. {
  137. Thread* thread = (Thread*)_arg;
  138. union
  139. {
  140. void* ptr;
  141. int32_t i;
  142. } cast;
  143. cast.i = thread->entry();
  144. return cast.ptr;
  145. }
  146. #endif // BX_PLATFORM_
  147. #if BX_PLATFORM_WINDOWS|BX_PLATFORM_XBOX360|BX_PLATFORM_WINRT
  148. HANDLE m_handle;
  149. #elif BX_PLATFORM_POSIX
  150. pthread_t m_handle;
  151. #endif // BX_PLATFORM_
  152. ThreadFn m_fn;
  153. void* m_userData;
  154. Semaphore m_sem;
  155. uint32_t m_stackSize;
  156. int32_t m_exitCode;
  157. bool m_running;
  158. };
  159. #if BX_PLATFORM_WINDOWS
  160. class TlsData
  161. {
  162. public:
  163. TlsData()
  164. {
  165. m_id = TlsAlloc();
  166. BX_CHECK(TLS_OUT_OF_INDEXES != m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
  167. }
  168. ~TlsData()
  169. {
  170. BOOL result = TlsFree(m_id);
  171. BX_CHECK(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
  172. }
  173. void* get() const
  174. {
  175. return TlsGetValue(m_id);
  176. }
  177. void set(void* _ptr)
  178. {
  179. TlsSetValue(m_id, _ptr);
  180. }
  181. private:
  182. uint32_t m_id;
  183. };
  184. #elif !(BX_PLATFORM_WINRT)
  185. class TlsData
  186. {
  187. public:
  188. TlsData()
  189. {
  190. int result = pthread_key_create(&m_id, NULL);
  191. BX_CHECK(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
  192. }
  193. ~TlsData()
  194. {
  195. int result = pthread_key_delete(m_id);
  196. BX_CHECK(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
  197. }
  198. void* get() const
  199. {
  200. return pthread_getspecific(m_id);
  201. }
  202. void set(void* _ptr)
  203. {
  204. int result = pthread_setspecific(m_id, _ptr);
  205. BX_CHECK(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
  206. }
  207. private:
  208. pthread_key_t m_id;
  209. };
  210. #endif // BX_PLATFORM_WINDOWS
  211. } // namespace bx
  212. #endif // BX_CONFIG_SUPPORTS_THREADING
  213. #endif // BX_THREAD_H_HEADER_GUARD