sem.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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/sem.h>
  6. #if BX_CONFIG_SUPPORTS_THREADING
  7. #if BX_PLATFORM_POSIX
  8. # include <errno.h>
  9. # include <pthread.h>
  10. # include <semaphore.h>
  11. # include <time.h>
  12. #elif BX_PLATFORM_WINDOWS \
  13. || BX_PLATFORM_WINRT \
  14. || BX_PLATFORM_XBOX360 \
  15. || BX_PLATFORM_XBOXONE
  16. # include <windows.h>
  17. # include <limits.h>
  18. # if BX_PLATFORM_XBOXONE
  19. # include <synchapi.h>
  20. # endif // BX_PLATFORM_XBOXONE
  21. #endif // BX_PLATFORM_
  22. namespace bx
  23. {
  24. struct SemaphoreInternal
  25. {
  26. #if BX_PLATFORM_POSIX
  27. # if BX_CONFIG_SEMAPHORE_PTHREAD
  28. pthread_mutex_t m_mutex;
  29. pthread_cond_t m_cond;
  30. int32_t m_count;
  31. # else
  32. sem_t m_handle;
  33. # endif // BX_CONFIG_SEMAPHORE_PTHREAD
  34. #elif BX_PLATFORM_WINDOWS \
  35. || BX_PLATFORM_WINRT \
  36. || BX_PLATFORM_XBOX360 \
  37. || BX_PLATFORM_XBOXONE
  38. HANDLE m_handle;
  39. #endif // BX_PLATFORM_
  40. };
  41. #if BX_PLATFORM_POSIX
  42. # if BX_CONFIG_SEMAPHORE_PTHREAD
  43. Semaphore::Semaphore()
  44. : m_count(0)
  45. {
  46. BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) );
  47. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  48. int result;
  49. result = pthread_mutex_init(&si->m_mutex, NULL);
  50. BX_CHECK(0 == result, "pthread_mutex_init %d", result);
  51. result = pthread_cond_init(&si->m_cond, NULL);
  52. BX_CHECK(0 == result, "pthread_cond_init %d", result);
  53. BX_UNUSED(result);
  54. }
  55. Semaphore::~Semaphore()
  56. {
  57. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  58. int result;
  59. result = pthread_cond_destroy(&si->m_cond);
  60. BX_CHECK(0 == result, "pthread_cond_destroy %d", result);
  61. result = pthread_mutex_destroy(&si->m_mutex);
  62. BX_CHECK(0 == result, "pthread_mutex_destroy %d", result);
  63. BX_UNUSED(result);
  64. }
  65. void Semaphore::post(uint32_t _count)
  66. {
  67. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  68. int result = pthread_mutex_lock(&si->m_mutex);
  69. BX_CHECK(0 == result, "pthread_mutex_lock %d", result);
  70. for (uint32_t ii = 0; ii < _count; ++ii)
  71. {
  72. result = pthread_cond_signal(&si->m_cond);
  73. BX_CHECK(0 == result, "pthread_cond_signal %d", result);
  74. }
  75. m_count += _count;
  76. result = pthread_mutex_unlock(&si->m_mutex);
  77. BX_CHECK(0 == result, "pthread_mutex_unlock %d", result);
  78. BX_UNUSED(result);
  79. }
  80. bool Semaphore::wait(int32_t _msecs)
  81. {
  82. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  83. int result = pthread_mutex_lock(&si->m_mutex);
  84. BX_CHECK(0 == result, "pthread_mutex_lock %d", result);
  85. # if BX_PLATFORM_NACL || BX_PLATFORM_OSX
  86. BX_UNUSED(_msecs);
  87. BX_CHECK(-1 == _msecs, "NaCl and OSX don't support pthread_cond_timedwait at this moment.");
  88. while (0 == result
  89. && 0 >= m_count)
  90. {
  91. result = pthread_cond_wait(&si->m_cond, &si->m_mutex);
  92. }
  93. # elif BX_PLATFORM_IOS
  94. if (-1 == _msecs)
  95. {
  96. while (0 == result
  97. && 0 >= m_count)
  98. {
  99. result = pthread_cond_wait(&si->m_cond, &si->m_mutex);
  100. }
  101. }
  102. else
  103. {
  104. timespec ts;
  105. ts.tv_sec = _msecs/1000;
  106. ts.tv_nsec = (_msecs%1000)*1000;
  107. while (0 == result
  108. && 0 >= m_count)
  109. {
  110. result = pthread_cond_timedwait_relative_np(&si->m_cond, &si->m_mutex, &ts);
  111. }
  112. }
  113. # else
  114. timespec ts;
  115. clock_gettime(CLOCK_REALTIME, &ts);
  116. ts.tv_sec += _msecs/1000;
  117. ts.tv_nsec += (_msecs%1000)*1000;
  118. while (0 == result
  119. && 0 >= m_count)
  120. {
  121. result = pthread_cond_timedwait(&si->m_cond, &si->m_mutex, &ts);
  122. }
  123. # endif // BX_PLATFORM_NACL || BX_PLATFORM_OSX
  124. bool ok = 0 == result;
  125. if (ok)
  126. {
  127. --m_count;
  128. }
  129. result = pthread_mutex_unlock(&si->m_mutex);
  130. BX_CHECK(0 == result, "pthread_mutex_unlock %d", result);
  131. BX_UNUSED(result);
  132. return ok;
  133. }
  134. # else
  135. Semaphore::Semaphore()
  136. {
  137. BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) );
  138. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  139. int32_t result = sem_init(&si->m_handle, 0, 0);
  140. BX_CHECK(0 == result, "sem_init failed. errno %d", errno);
  141. BX_UNUSED(result);
  142. }
  143. Semaphore::~Semaphore()
  144. {
  145. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  146. int32_t result = sem_destroy(&si->m_handle);
  147. BX_CHECK(0 == result, "sem_destroy failed. errno %d", errno);
  148. BX_UNUSED(result);
  149. }
  150. void Semaphore::post(uint32_t _count)
  151. {
  152. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  153. int32_t result;
  154. for (uint32_t ii = 0; ii < _count; ++ii)
  155. {
  156. result = sem_post(&si->m_handle);
  157. BX_CHECK(0 == result, "sem_post failed. errno %d", errno);
  158. }
  159. BX_UNUSED(result);
  160. }
  161. bool Semaphore::wait(int32_t _msecs)
  162. {
  163. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  164. # if BX_PLATFORM_NACL || BX_PLATFORM_OSX
  165. BX_CHECK(-1 == _msecs, "NaCl and OSX don't support sem_timedwait at this moment."); BX_UNUSED(_msecs);
  166. return 0 == sem_wait(&si->m_handle);
  167. # else
  168. if (0 > _msecs)
  169. {
  170. int32_t result;
  171. do
  172. {
  173. result = sem_wait(&si->m_handle);
  174. } // keep waiting when interrupted by a signal handler...
  175. while (-1 == result && EINTR == errno);
  176. BX_CHECK(0 == result, "sem_wait failed. errno %d", errno);
  177. return 0 == result;
  178. }
  179. timespec ts;
  180. clock_gettime(CLOCK_REALTIME, &ts);
  181. ts.tv_sec += _msecs/1000;
  182. ts.tv_nsec += (_msecs%1000)*1000;
  183. return 0 == sem_timedwait(&si->m_handle, &ts);
  184. # endif // BX_PLATFORM_
  185. }
  186. # endif // BX_CONFIG_SEMAPHORE_PTHREAD
  187. #elif BX_PLATFORM_WINDOWS \
  188. || BX_PLATFORM_WINRT \
  189. || BX_PLATFORM_XBOX360 \
  190. || BX_PLATFORM_XBOXONE
  191. Semaphore::Semaphore()
  192. {
  193. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  194. #if BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT
  195. si->m_handle = CreateSemaphoreExW(NULL, 0, LONG_MAX, NULL, 0, SEMAPHORE_ALL_ACCESS);
  196. #else
  197. si->m_handle = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL);
  198. #endif
  199. BX_CHECK(NULL != si->m_handle, "Failed to create Semaphore!");
  200. }
  201. Semaphore::~Semaphore()
  202. {
  203. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  204. CloseHandle(si->m_handle);
  205. }
  206. void Semaphore::post(uint32_t _count)
  207. {
  208. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  209. ReleaseSemaphore(si->m_handle, _count, NULL);
  210. }
  211. bool Semaphore::wait(int32_t _msecs)
  212. {
  213. SemaphoreInternal* si = (SemaphoreInternal*)m_internal;
  214. DWORD milliseconds = (0 > _msecs) ? INFINITE : _msecs;
  215. #if BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT
  216. return WAIT_OBJECT_0 == WaitForSingleObjectEx(si->m_handle, milliseconds, FALSE);
  217. #else
  218. return WAIT_OBJECT_0 == WaitForSingleObject(si->m_handle, milliseconds);
  219. #endif
  220. }
  221. #endif // BX_PLATFORM_
  222. } // namespace bx
  223. #endif // BX_CONFIG_SUPPORTS_THREADING