thread.h 4.3 KB

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