semaphore.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright 2010-2021 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #include <bx/semaphore.h>
  6. #if BX_CONFIG_SUPPORTS_THREADING
  7. #if BX_CRT_NONE
  8. #elif BX_PLATFORM_OSX \
  9. || BX_PLATFORM_IOS
  10. # include <dispatch/dispatch.h>
  11. #elif BX_PLATFORM_POSIX
  12. # include <errno.h>
  13. # include <pthread.h>
  14. # include <semaphore.h>
  15. # include <time.h>
  16. #elif BX_PLATFORM_WINDOWS \
  17. || BX_PLATFORM_WINRT \
  18. || BX_PLATFORM_XBOXONE
  19. # ifndef WIN32_LEAN_AND_MEAN
  20. # define WIN32_LEAN_AND_MEAN
  21. # endif // WIN32_LEAN_AND_MEAN
  22. # include <windows.h>
  23. # include <limits.h>
  24. # if BX_PLATFORM_XBOXONE
  25. # include <synchapi.h>
  26. # endif // BX_PLATFORM_XBOXONE
  27. #endif // BX_PLATFORM_
  28. namespace bx
  29. {
  30. struct SemaphoreInternal
  31. {
  32. #if BX_CRT_NONE
  33. #elif BX_PLATFORM_OSX \
  34. || BX_PLATFORM_IOS
  35. dispatch_semaphore_t m_handle;
  36. #elif BX_PLATFORM_POSIX
  37. pthread_mutex_t m_mutex;
  38. pthread_cond_t m_cond;
  39. int32_t m_count;
  40. #elif BX_PLATFORM_WINDOWS \
  41. || BX_PLATFORM_WINRT \
  42. || BX_PLATFORM_XBOXONE
  43. HANDLE m_handle;
  44. #endif // BX_PLATFORM_
  45. };
  46. #if BX_CRT_NONE
  47. Semaphore::Semaphore()
  48. {
  49. BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) );
  50. }
  51. Semaphore::~Semaphore()
  52. {
  53. }
  54. void Semaphore::post(uint32_t _count)
  55. {
  56. BX_UNUSED(_count);
  57. }
  58. bool Semaphore::wait(int32_t _msecs)
  59. {
  60. BX_UNUSED(_msecs);
  61. return false;
  62. }
  63. #elif BX_PLATFORM_OSX \
  64. || BX_PLATFORM_IOS
  65. Semaphore::Semaphore()
  66. {
  67. BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) );
  68. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  69. si->m_handle = dispatch_semaphore_create(0);
  70. BX_ASSERT(NULL != si->m_handle, "dispatch_semaphore_create failed.");
  71. }
  72. Semaphore::~Semaphore()
  73. {
  74. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  75. dispatch_release(si->m_handle);
  76. }
  77. void Semaphore::post(uint32_t _count)
  78. {
  79. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  80. for (uint32_t ii = 0; ii < _count; ++ii)
  81. {
  82. dispatch_semaphore_signal(si->m_handle);
  83. }
  84. }
  85. bool Semaphore::wait(int32_t _msecs)
  86. {
  87. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  88. dispatch_time_t dt = 0 > _msecs
  89. ? DISPATCH_TIME_FOREVER
  90. : dispatch_time(DISPATCH_TIME_NOW, int64_t(_msecs)*1000000)
  91. ;
  92. return !dispatch_semaphore_wait(si->m_handle, dt);
  93. }
  94. #elif BX_PLATFORM_POSIX
  95. uint64_t toNs(const timespec& _ts)
  96. {
  97. return _ts.tv_sec*UINT64_C(1000000000) + _ts.tv_nsec;
  98. }
  99. void toTimespecNs(timespec& _ts, uint64_t _nsecs)
  100. {
  101. _ts.tv_sec = _nsecs/UINT64_C(1000000000);
  102. _ts.tv_nsec = _nsecs%UINT64_C(1000000000);
  103. }
  104. void toTimespecMs(timespec& _ts, int32_t _msecs)
  105. {
  106. toTimespecNs(_ts, uint64_t(_msecs)*1000000);
  107. }
  108. void add(timespec& _ts, int32_t _msecs)
  109. {
  110. uint64_t ns = toNs(_ts);
  111. toTimespecNs(_ts, ns + uint64_t(_msecs)*1000000);
  112. }
  113. Semaphore::Semaphore()
  114. {
  115. BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) );
  116. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  117. si->m_count = 0;
  118. int result;
  119. result = pthread_mutex_init(&si->m_mutex, NULL);
  120. BX_ASSERT(0 == result, "pthread_mutex_init %d", result);
  121. result = pthread_cond_init(&si->m_cond, NULL);
  122. BX_ASSERT(0 == result, "pthread_cond_init %d", result);
  123. BX_UNUSED(result);
  124. }
  125. Semaphore::~Semaphore()
  126. {
  127. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  128. int result;
  129. result = pthread_cond_destroy(&si->m_cond);
  130. BX_ASSERT(0 == result, "pthread_cond_destroy %d", result);
  131. result = pthread_mutex_destroy(&si->m_mutex);
  132. BX_ASSERT(0 == result, "pthread_mutex_destroy %d", result);
  133. BX_UNUSED(result);
  134. }
  135. void Semaphore::post(uint32_t _count)
  136. {
  137. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  138. int result = pthread_mutex_lock(&si->m_mutex);
  139. BX_ASSERT(0 == result, "pthread_mutex_lock %d", result);
  140. for (uint32_t ii = 0; ii < _count; ++ii)
  141. {
  142. result = pthread_cond_signal(&si->m_cond);
  143. BX_ASSERT(0 == result, "pthread_cond_signal %d", result);
  144. }
  145. si->m_count += _count;
  146. result = pthread_mutex_unlock(&si->m_mutex);
  147. BX_ASSERT(0 == result, "pthread_mutex_unlock %d", result);
  148. BX_UNUSED(result);
  149. }
  150. bool Semaphore::wait(int32_t _msecs)
  151. {
  152. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  153. int result = pthread_mutex_lock(&si->m_mutex);
  154. BX_ASSERT(0 == result, "pthread_mutex_lock %d", result);
  155. if (-1 == _msecs)
  156. {
  157. while (0 == result
  158. && 0 >= si->m_count)
  159. {
  160. result = pthread_cond_wait(&si->m_cond, &si->m_mutex);
  161. }
  162. }
  163. else
  164. {
  165. timespec ts;
  166. clock_gettime(CLOCK_REALTIME, &ts);
  167. add(ts, _msecs);
  168. while (0 == result
  169. && 0 >= si->m_count)
  170. {
  171. result = pthread_cond_timedwait(&si->m_cond, &si->m_mutex, &ts);
  172. }
  173. }
  174. bool ok = 0 == result;
  175. if (ok)
  176. {
  177. --si->m_count;
  178. }
  179. result = pthread_mutex_unlock(&si->m_mutex);
  180. BX_ASSERT(0 == result, "pthread_mutex_unlock %d", result);
  181. BX_UNUSED(result);
  182. return ok;
  183. }
  184. #elif BX_PLATFORM_WINDOWS \
  185. || BX_PLATFORM_WINRT \
  186. || BX_PLATFORM_XBOXONE
  187. Semaphore::Semaphore()
  188. {
  189. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  190. #if BX_PLATFORM_WINRT \
  191. || BX_PLATFORM_XBOXONE
  192. si->m_handle = CreateSemaphoreExW(NULL, 0, LONG_MAX, NULL, 0, SEMAPHORE_ALL_ACCESS);
  193. #else
  194. si->m_handle = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL);
  195. #endif
  196. BX_ASSERT(NULL != si->m_handle, "Failed to create Semaphore!");
  197. }
  198. Semaphore::~Semaphore()
  199. {
  200. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  201. CloseHandle(si->m_handle);
  202. }
  203. void Semaphore::post(uint32_t _count)
  204. {
  205. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  206. ReleaseSemaphore(si->m_handle, _count, NULL);
  207. }
  208. bool Semaphore::wait(int32_t _msecs)
  209. {
  210. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  211. DWORD milliseconds = (0 > _msecs) ? INFINITE : _msecs;
  212. #if BX_PLATFORM_WINRT \
  213. || BX_PLATFORM_XBOXONE
  214. return WAIT_OBJECT_0 == WaitForSingleObjectEx(si->m_handle, milliseconds, FALSE);
  215. #else
  216. return WAIT_OBJECT_0 == WaitForSingleObject(si->m_handle, milliseconds);
  217. #endif
  218. }
  219. #endif // BX_PLATFORM_
  220. } // namespace bx
  221. #endif // BX_CONFIG_SUPPORTS_THREADING