thread.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright 2010-2017 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #include <bx/thread.h>
  6. #if BX_CONFIG_SUPPORTS_THREADING
  7. namespace bx
  8. {
  9. Thread::Thread()
  10. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT
  11. : m_handle(INVALID_HANDLE_VALUE)
  12. , m_threadId(UINT32_MAX)
  13. #elif BX_PLATFORM_POSIX
  14. : m_handle(0)
  15. #endif // BX_PLATFORM_
  16. , m_fn(NULL)
  17. , m_userData(NULL)
  18. , m_stackSize(0)
  19. , m_exitCode(0 /*EXIT_SUCCESS*/)
  20. , m_running(false)
  21. {
  22. }
  23. Thread::~Thread()
  24. {
  25. if (m_running)
  26. {
  27. shutdown();
  28. }
  29. }
  30. void Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
  31. {
  32. BX_CHECK(!m_running, "Already running!");
  33. m_fn = _fn;
  34. m_userData = _userData;
  35. m_stackSize = _stackSize;
  36. m_running = true;
  37. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE
  38. m_handle = ::CreateThread(NULL
  39. , m_stackSize
  40. , (LPTHREAD_START_ROUTINE)threadFunc
  41. , this
  42. , 0
  43. , NULL
  44. );
  45. #elif BX_PLATFORM_WINRT
  46. m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
  47. auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
  48. {
  49. m_exitCode = threadFunc(this);
  50. SetEvent(m_handle);
  51. }, CallbackContext::Any);
  52. ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
  53. #elif BX_PLATFORM_POSIX
  54. int result;
  55. BX_UNUSED(result);
  56. pthread_attr_t attr;
  57. result = pthread_attr_init(&attr);
  58. BX_CHECK(0 == result, "pthread_attr_init failed! %d", result);
  59. if (0 != m_stackSize)
  60. {
  61. result = pthread_attr_setstacksize(&attr, m_stackSize);
  62. BX_CHECK(0 == result, "pthread_attr_setstacksize failed! %d", result);
  63. }
  64. // sched_param sched;
  65. // sched.sched_priority = 0;
  66. // result = pthread_attr_setschedparam(&attr, &sched);
  67. // BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
  68. result = pthread_create(&m_handle, &attr, &threadFunc, this);
  69. BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result);
  70. #else
  71. # error "Not implemented!"
  72. #endif // BX_PLATFORM_
  73. m_sem.wait();
  74. if (NULL != _name)
  75. {
  76. setThreadName(_name);
  77. }
  78. }
  79. void Thread::shutdown()
  80. {
  81. BX_CHECK(m_running, "Not running!");
  82. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360
  83. WaitForSingleObject(m_handle, INFINITE);
  84. GetExitCodeThread(m_handle, (DWORD*)&m_exitCode);
  85. CloseHandle(m_handle);
  86. m_handle = INVALID_HANDLE_VALUE;
  87. #elif BX_PLATFORM_WINRT
  88. WaitForSingleObjectEx(m_handle, INFINITE, FALSE);
  89. CloseHandle(m_handle);
  90. m_handle = INVALID_HANDLE_VALUE;
  91. #elif BX_PLATFORM_POSIX
  92. union
  93. {
  94. void* ptr;
  95. int32_t i;
  96. } cast;
  97. pthread_join(m_handle, &cast.ptr);
  98. m_exitCode = cast.i;
  99. m_handle = 0;
  100. #endif // BX_PLATFORM_
  101. m_running = false;
  102. }
  103. bool Thread::isRunning() const
  104. {
  105. return m_running;
  106. }
  107. int32_t Thread::getExitCode() const
  108. {
  109. return m_exitCode;
  110. }
  111. void Thread::setThreadName(const char* _name)
  112. {
  113. #if BX_PLATFORM_OSX || BX_PLATFORM_IOS
  114. pthread_setname_np(_name);
  115. #elif (BX_CRT_GLIBC >= 21200) && ! BX_PLATFORM_HURD
  116. pthread_setname_np(m_handle, _name);
  117. #elif BX_PLATFORM_LINUX
  118. prctl(PR_SET_NAME,_name, 0, 0, 0);
  119. #elif BX_PLATFORM_BSD
  120. # ifdef __NetBSD__
  121. pthread_setname_np(m_handle, "%s", (void*)_name);
  122. # else
  123. pthread_set_name_np(m_handle, _name);
  124. # endif // __NetBSD__
  125. #elif BX_PLATFORM_WINDOWS && BX_COMPILER_MSVC
  126. # pragma pack(push, 8)
  127. struct ThreadName
  128. {
  129. DWORD type;
  130. LPCSTR name;
  131. DWORD id;
  132. DWORD flags;
  133. };
  134. # pragma pack(pop)
  135. ThreadName tn;
  136. tn.type = 0x1000;
  137. tn.name = _name;
  138. tn.id = m_threadId;
  139. tn.flags = 0;
  140. __try
  141. {
  142. RaiseException(0x406d1388
  143. , 0
  144. , sizeof(tn)/4
  145. , reinterpret_cast<ULONG_PTR*>(&tn)
  146. );
  147. }
  148. __except(EXCEPTION_EXECUTE_HANDLER)
  149. {
  150. }
  151. #else
  152. BX_UNUSED(_name);
  153. #endif // BX_PLATFORM_
  154. }
  155. int32_t Thread::entry()
  156. {
  157. #if BX_PLATFORM_WINDOWS
  158. m_threadId = ::GetCurrentThreadId();
  159. #endif // BX_PLATFORM_WINDOWS
  160. m_sem.post();
  161. return m_fn(m_userData);
  162. }
  163. #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT
  164. DWORD WINAPI Thread::threadFunc(LPVOID _arg)
  165. {
  166. Thread* thread = (Thread*)_arg;
  167. int32_t result = thread->entry();
  168. return result;
  169. }
  170. #else
  171. void* Thread::threadFunc(void* _arg)
  172. {
  173. Thread* thread = (Thread*)_arg;
  174. union
  175. {
  176. void* ptr;
  177. int32_t i;
  178. } cast;
  179. cast.i = thread->entry();
  180. return cast.ptr;
  181. }
  182. #endif // BX_PLATFORM_
  183. } // namespace bx
  184. #endif // BX_CONFIG_SUPPORTS_THREADING