mutex.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #ifdef WIN32
  4. #include "winapi.hpp"
  5. #else
  6. #include <pthread.h>
  7. #endif
  8. #include "cbasetypes.h"
  9. #include "malloc.h"
  10. #include "showmsg.h"
  11. #include "timer.h"
  12. #include "mutex.h"
  13. struct ramutex{
  14. #ifdef WIN32
  15. CRITICAL_SECTION hMutex;
  16. #else
  17. pthread_mutex_t hMutex;
  18. #endif
  19. };
  20. struct racond{
  21. #ifdef WIN32
  22. HANDLE events[2];
  23. ra_align(8) volatile LONG nWaiters;
  24. CRITICAL_SECTION waiters_lock;
  25. #define EVENT_COND_SIGNAL 0
  26. #define EVENT_COND_BROADCAST 1
  27. #else
  28. pthread_cond_t hCond;
  29. #endif
  30. };
  31. ////////////////////
  32. // Mutex
  33. //
  34. // Implementation:
  35. //
  36. ramutex ramutex_create(){
  37. struct ramutex *m;
  38. m = (struct ramutex*)aMalloc( sizeof(struct ramutex) );
  39. if(m == NULL){
  40. ShowFatalError("ramutex_create: OOM while allocating %u bytes.\n", sizeof(struct ramutex));
  41. return NULL;
  42. }
  43. #ifdef WIN32
  44. InitializeCriticalSection(&m->hMutex);
  45. #else
  46. pthread_mutex_init(&m->hMutex, NULL);
  47. #endif
  48. return m;
  49. }//end: ramutex_create()
  50. void ramutex_destroy( ramutex m ){
  51. #ifdef WIN32
  52. DeleteCriticalSection(&m->hMutex);
  53. #else
  54. pthread_mutex_destroy(&m->hMutex);
  55. #endif
  56. aFree(m);
  57. }//end: ramutex_destroy()
  58. void ramutex_lock( ramutex m ){
  59. #ifdef WIN32
  60. EnterCriticalSection(&m->hMutex);
  61. #else
  62. pthread_mutex_lock(&m->hMutex);
  63. #endif
  64. }//end: ramutex_lock
  65. bool ramutex_trylock( ramutex m ){
  66. #ifdef WIN32
  67. if(TryEnterCriticalSection(&m->hMutex) == TRUE)
  68. return true;
  69. return false;
  70. #else
  71. if(pthread_mutex_trylock(&m->hMutex) == 0)
  72. return true;
  73. return false;
  74. #endif
  75. }//end: ramutex_trylock()
  76. void ramutex_unlock( ramutex m ){
  77. #ifdef WIN32
  78. LeaveCriticalSection(&m->hMutex);
  79. #else
  80. pthread_mutex_unlock(&m->hMutex);
  81. #endif
  82. }//end: ramutex_unlock()
  83. ///////////////
  84. // Condition Variables
  85. //
  86. // Implementation:
  87. //
  88. racond racond_create(){
  89. struct racond *c;
  90. c = (struct racond*)aMalloc( sizeof(struct racond) );
  91. if(c == NULL){
  92. ShowFatalError("racond_create: OOM while allocating %u bytes\n", sizeof(struct racond));
  93. return NULL;
  94. }
  95. #ifdef WIN32
  96. c->nWaiters = 0;
  97. c->events[ EVENT_COND_SIGNAL ] = CreateEvent( NULL, FALSE, FALSE, NULL );
  98. c->events[ EVENT_COND_BROADCAST ] = CreateEvent( NULL, TRUE, FALSE, NULL );
  99. InitializeCriticalSection( &c->waiters_lock );
  100. #else
  101. pthread_cond_init(&c->hCond, NULL);
  102. #endif
  103. return c;
  104. }//end: racond_create()
  105. void racond_destroy( racond c ){
  106. #ifdef WIN32
  107. CloseHandle( c->events[ EVENT_COND_SIGNAL ] );
  108. CloseHandle( c->events[ EVENT_COND_BROADCAST ] );
  109. DeleteCriticalSection( &c->waiters_lock );
  110. #else
  111. pthread_cond_destroy(&c->hCond);
  112. #endif
  113. aFree(c);
  114. }//end: racond_destroy()
  115. void racond_wait( racond c, ramutex m, sysint timeout_ticks){
  116. #ifdef WIN32
  117. register DWORD ms;
  118. int result;
  119. bool is_last = false;
  120. EnterCriticalSection(&c->waiters_lock);
  121. c->nWaiters++;
  122. LeaveCriticalSection(&c->waiters_lock);
  123. if(timeout_ticks < 0)
  124. ms = INFINITE;
  125. else
  126. ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks;
  127. // we can release the mutex (m) here, cause win's
  128. // manual reset events maintain state when used with
  129. // SetEvent()
  130. ramutex_unlock(m);
  131. result = WaitForMultipleObjects(2, c->events, FALSE, ms);
  132. EnterCriticalSection(&c->waiters_lock);
  133. c->nWaiters--;
  134. if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) )
  135. is_last = true; // Broadcast called!
  136. LeaveCriticalSection(&c->waiters_lock);
  137. // we are the last waiter that has to be notified, or to stop waiting
  138. // so we have to do a manual reset
  139. if(is_last == true)
  140. ResetEvent( c->events[EVENT_COND_BROADCAST] );
  141. ramutex_lock(m);
  142. #else
  143. if(timeout_ticks < 0){
  144. pthread_cond_wait( &c->hCond, &m->hMutex );
  145. }else{
  146. struct timespec wtime;
  147. int64 exact_timeout = gettick() + timeout_ticks;
  148. wtime.tv_sec = exact_timeout/1000;
  149. wtime.tv_nsec = (exact_timeout%1000)*1000000;
  150. pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime);
  151. }
  152. #endif
  153. }//end: racond_wait()
  154. void racond_signal( racond c ){
  155. #ifdef WIN32
  156. // bool has_waiters = false;
  157. // EnterCriticalSection(&c->waiters_lock);
  158. // if(c->nWaiters > 0)
  159. // has_waiters = true;
  160. // LeaveCriticalSection(&c->waiters_lock);
  161. // if(has_waiters == true)
  162. SetEvent( c->events[ EVENT_COND_SIGNAL ] );
  163. #else
  164. pthread_cond_signal(&c->hCond);
  165. #endif
  166. }//end: racond_signal()
  167. void racond_broadcast( racond c ){
  168. #ifdef WIN32
  169. // bool has_waiters = false;
  170. // EnterCriticalSection(&c->waiters_lock);
  171. // if(c->nWaiters > 0)
  172. // has_waiters = true;
  173. // LeaveCriticalSection(&c->waiters_lock);
  174. // if(has_waiters == true)
  175. SetEvent( c->events[ EVENT_COND_BROADCAST ] );
  176. #else
  177. pthread_cond_broadcast(&c->hCond);
  178. #endif
  179. }//end: racond_broadcast()