semaphore.cpp 5.5 KB

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