1
0

hmutex.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #ifndef HV_MUTEX_H_
  2. #define HV_MUTEX_H_
  3. #include "hexport.h"
  4. #include "hplatform.h"
  5. #include "htime.h"
  6. BEGIN_EXTERN_C
  7. #ifdef _MSC_VER
  8. #define hmutex_t CRITICAL_SECTION
  9. #define hmutex_init InitializeCriticalSection
  10. #define hmutex_destroy DeleteCriticalSection
  11. #define hmutex_lock EnterCriticalSection
  12. #define hmutex_unlock LeaveCriticalSection
  13. #define HSPINLOCK_COUNT -1
  14. #define hspinlock_t CRITICAL_SECTION
  15. #define hspinlock_init(pspin) InitializeCriticalSectionAndSpinCount(pspin, HSPINLOCK_COUNT)
  16. #define hspinlock_destroy DeleteCriticalSection
  17. #define hspinlock_lock EnterCriticalSection
  18. #define hspinlock_unlock LeaveCriticalSection
  19. #define hrwlock_t SRWLOCK
  20. #define hrwlock_init InitializeSRWLock
  21. #define hrwlock_destroy(plock)
  22. #define hrwlock_rdlock AcquireSRWLockShared
  23. #define hrwlock_rdunlock ReleaseSRWLockShared
  24. #define hrwlock_wrlock AcquireSRWLockExclusive
  25. #define hrwlock_wrunlock ReleaseSRWLockExclusive
  26. #define htimed_mutex_t HANDLE
  27. #define htimed_mutex_init(pmutex) *(pmutex) = CreateMutex(NULL, FALSE, NULL)
  28. #define htimed_mutex_destroy(pmutex) CloseHandle(*(pmutex))
  29. #define htimed_mutex_lock(pmutex) WaitForSingleObject(*(pmutex), INFINITE)
  30. #define htimed_mutex_unlock(pmutex) ReleaseMutex(*(pmutex))
  31. // true: WAIT_OBJECT_0
  32. // false: WAIT_OBJECT_TIMEOUT
  33. #define htimed_mutex_lock_for(pmutex, ms) ( WaitForSingleObject(*(pmutex), ms) == WAIT_OBJECT_0 )
  34. #define hcondvar_t CONDITION_VARIABLE
  35. #define hcondvar_init InitializeConditionVariable
  36. #define hcondvar_destroy(pcond)
  37. #define hcondvar_wait(pcond, pmutex) SleepConditionVariableCS(pcond, pmutex, INFINITE)
  38. #define hcondvar_wait_for(pcond, pmutex, ms) SleepConditionVariableCS(pcond, pmutex, ms)
  39. #define hcondvar_signal WakeConditionVariable
  40. #define hcondvar_broadcast WakeAllConditionVariable
  41. #define honce_t INIT_ONCE
  42. #define HONCE_INIT INIT_ONCE_STATIC_INIT
  43. typedef void (*honce_fn)();
  44. static inline BOOL WINAPI s_once_func(INIT_ONCE* once, PVOID arg, PVOID* _) {
  45. honce_fn fn = (honce_fn)arg;
  46. fn();
  47. return TRUE;
  48. }
  49. static inline void honce(honce_t* once, honce_fn fn) {
  50. PVOID dummy = NULL;
  51. InitOnceExecuteOnce(once, s_once_func, (PVOID)fn, &dummy);
  52. }
  53. #define hsem_t HANDLE
  54. #define hsem_init(psem, value) *(psem) = CreateSemaphore(NULL, value, value+100000, NULL)
  55. #define hsem_destroy(psem) CloseHandle(*(psem))
  56. #define hsem_wait(psem) WaitForSingleObject(*(psem), INFINITE)
  57. #define hsem_post(psem) ReleaseSemaphore(*(psem), 1, NULL)
  58. // true: WAIT_OBJECT_0
  59. // false: WAIT_OBJECT_TIMEOUT
  60. #define hsem_wait_for(psem, ms) ( WaitForSingleObject(*(psem), ms) == WAIT_OBJECT_0 )
  61. #else
  62. #define hmutex_t pthread_mutex_t
  63. #define hmutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
  64. #define hmutex_destroy pthread_mutex_destroy
  65. #define hmutex_lock pthread_mutex_lock
  66. #define hmutex_unlock pthread_mutex_unlock
  67. #if HAVE_PTHREAD_SPIN_LOCK
  68. #define hspinlock_t pthread_spinlock_t
  69. #define hspinlock_init(pspin) pthread_spin_init(pspin, PTHREAD_PROCESS_PRIVATE)
  70. #define hspinlock_destroy pthread_spin_destroy
  71. #define hspinlock_lock pthread_spin_lock
  72. #define hspinlock_unlock pthread_spin_unlock
  73. #else
  74. #define hspinlock_t pthread_mutex_t
  75. #define hspinlock_init(pmutex) pthread_mutex_init(pmutex, NULL)
  76. #define hspinlock_destroy pthread_mutex_destroy
  77. #define hspinlock_lock pthread_mutex_lock
  78. #define hspinlock_unlock pthread_mutex_unlock
  79. #endif
  80. #define hrwlock_t pthread_rwlock_t
  81. #define hrwlock_init(prwlock) pthread_rwlock_init(prwlock, NULL)
  82. #define hrwlock_destroy pthread_rwlock_destroy
  83. #define hrwlock_rdlock pthread_rwlock_rdlock
  84. #define hrwlock_rdunlock pthread_rwlock_unlock
  85. #define hrwlock_wrlock pthread_rwlock_wrlock
  86. #define hrwlock_wrunlock pthread_rwlock_unlock
  87. #define htimed_mutex_t pthread_mutex_t
  88. #define htimed_mutex_init(pmutex) pthread_mutex_init(pmutex, NULL)
  89. #define htimed_mutex_destroy pthread_mutex_destroy
  90. #define htimed_mutex_lock pthread_mutex_lock
  91. #define htimed_mutex_unlock pthread_mutex_unlock
  92. // true: OK
  93. // false: ETIMEDOUT
  94. static inline int htimed_mutex_lock_for(htimed_mutex_t* mutex, unsigned int ms) {
  95. #if HAVE_PTHREAD_MUTEX_TIMEDLOCK
  96. struct timespec ts;
  97. struct timeval tv;
  98. gettimeofday(&tv, NULL);
  99. ts.tv_sec = tv.tv_sec + ms / 1000;
  100. ts.tv_nsec = tv.tv_usec * 1000 + ms % 1000 * 1000000;
  101. if (ts.tv_nsec >= 1000000000) {
  102. ts.tv_nsec -= 1000000000;
  103. ts.tv_sec += 1;
  104. }
  105. return pthread_mutex_timedlock(mutex, &ts) != ETIMEDOUT;
  106. #else
  107. int ret = 0;
  108. unsigned int end = gettick() + ms;
  109. while ((ret = pthread_mutex_trylock(mutex)) != 0) {
  110. if (gettick() >= end) {
  111. break;
  112. }
  113. msleep(1);
  114. }
  115. return ret == 0;
  116. #endif
  117. }
  118. #define hcondvar_t pthread_cond_t
  119. #define hcondvar_init(pcond) pthread_cond_init(pcond, NULL)
  120. #define hcondvar_destroy pthread_cond_destroy
  121. #define hcondvar_wait pthread_cond_wait
  122. #define hcondvar_signal pthread_cond_signal
  123. #define hcondvar_broadcast pthread_cond_broadcast
  124. // true: OK
  125. // false: ETIMEDOUT
  126. static inline int hcondvar_wait_for(hcondvar_t* cond, hmutex_t* mutex, unsigned int ms) {
  127. struct timespec ts;
  128. struct timeval tv;
  129. gettimeofday(&tv, NULL);
  130. ts.tv_sec = tv.tv_sec + ms / 1000;
  131. ts.tv_nsec = tv.tv_usec * 1000 + ms % 1000 * 1000000;
  132. if (ts.tv_nsec >= 1000000000) {
  133. ts.tv_nsec -= 1000000000;
  134. ts.tv_sec += 1;
  135. }
  136. return pthread_cond_timedwait(cond, mutex, &ts) != ETIMEDOUT;
  137. }
  138. #define honce_t pthread_once_t
  139. #define HONCE_INIT PTHREAD_ONCE_INIT
  140. #define honce pthread_once
  141. #include <semaphore.h>
  142. #define hsem_t sem_t
  143. #define hsem_init(psem, value) sem_init(psem, 0, value)
  144. #define hsem_destroy sem_destroy
  145. #define hsem_wait sem_wait
  146. #define hsem_post sem_post
  147. // true: OK
  148. // false: ETIMEDOUT
  149. static inline int hsem_wait_for(hsem_t* sem, unsigned int ms) {
  150. #if HAVE_SEM_TIMEDWAIT
  151. struct timespec ts;
  152. struct timeval tv;
  153. gettimeofday(&tv, NULL);
  154. ts.tv_sec = tv.tv_sec + ms / 1000;
  155. ts.tv_nsec = tv.tv_usec * 1000 + ms % 1000 * 1000000;
  156. if (ts.tv_nsec >= 1000000000) {
  157. ts.tv_nsec -= 1000000000;
  158. ts.tv_sec += 1;
  159. }
  160. return sem_timedwait(sem, &ts) != ETIMEDOUT;
  161. #else
  162. int ret = 0;
  163. unsigned int end = gettick() + ms;
  164. while ((ret = sem_trywait(sem)) != 0) {
  165. if (gettick() >= end) {
  166. break;
  167. }
  168. msleep(1);
  169. }
  170. return ret == 0;
  171. #endif
  172. }
  173. #endif
  174. END_EXTERN_C
  175. #ifdef __cplusplus
  176. #include <mutex>
  177. #include <condition_variable>
  178. // using std::mutex;
  179. // NOTE: test std::timed_mutex incorrect in some platforms, use htimed_mutex_t
  180. // using std::timed_mutex;
  181. using std::condition_variable;
  182. using std::lock_guard;
  183. using std::unique_lock;
  184. BEGIN_NAMESPACE_HV
  185. class MutexLock {
  186. public:
  187. MutexLock() { hmutex_init(&_mutex); }
  188. ~MutexLock() { hmutex_destroy(&_mutex); }
  189. void lock() { hmutex_lock(&_mutex); }
  190. void unlock() { hmutex_unlock(&_mutex); }
  191. protected:
  192. hmutex_t _mutex;
  193. };
  194. class SpinLock {
  195. public:
  196. SpinLock() { hspinlock_init(&_spin); }
  197. ~SpinLock() { hspinlock_destroy(&_spin); }
  198. void lock() { hspinlock_lock(&_spin); }
  199. void unlock() { hspinlock_unlock(&_spin); }
  200. protected:
  201. hspinlock_t _spin;
  202. };
  203. class RWLock {
  204. public:
  205. RWLock() { hrwlock_init(&_rwlock); }
  206. ~RWLock() { hrwlock_destroy(&_rwlock); }
  207. void rdlock() { hrwlock_rdlock(&_rwlock); }
  208. void rdunlock() { hrwlock_rdunlock(&_rwlock); }
  209. void wrlock() { hrwlock_wrlock(&_rwlock); }
  210. void wrunlock() { hrwlock_wrunlock(&_rwlock); }
  211. protected:
  212. hrwlock_t _rwlock;
  213. };
  214. END_NAMESPACE_HV
  215. #endif // __cplusplus
  216. #endif // HV_MUTEX_H_