thread.h 4.4 KB

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