/sparrowhawk/foundation/ESFReadWriteLock.cpp

http://github.com/jtblatt/duderino · C++ · 375 lines · 254 code · 105 blank · 16 comment · 84 complexity · 4e1a70031862a8ab610c8b3629bbeb05 MD5 · raw file

  1. /** @file ESFReadWriteLock.cpp
  2. * @brief A multiple readers, single writer implementation of the ESFLockable
  3. * interface
  4. *
  5. * Copyright (c) 2009 Yahoo! Inc.
  6. * The copyrights embodied in the content of this file are licensed by Yahoo! Inc.
  7. * under the BSD (revised) open source license.
  8. *
  9. * Derived from code that is Copyright (c) 2009 Joshua Blatt and offered under both
  10. * BSD and Apache 2.0 licenses (http://sourceforge.net/projects/sparrowhawk/).
  11. *
  12. * $Author: blattj $
  13. * $Date: 2009/05/25 21:51:08 $
  14. * $Name: $
  15. * $Revision: 1.3 $
  16. */
  17. #ifndef ESF_READ_WRITE_LOCK_H
  18. #include <ESFReadWriteLock.h>
  19. #endif
  20. #ifndef ESF_ASSERT_H
  21. #include <ESFAssert.h>
  22. #endif
  23. #ifdef HAVE_ERRNO_H
  24. #include <errno.h>
  25. #endif
  26. ESFReadWriteLock::ESFReadWriteLock() :
  27. _magic(0) {
  28. #ifdef HAVE_PTHREAD_RWLOCK_INIT
  29. if (0 == pthread_rwlock_init(&_lock, 0)) {
  30. _magic = ESF_MAGIC;
  31. }
  32. #elif defined HAVE_PTHREAD_MUTEX_INIT && defined HAVE_PTHREAD_COND_INIT && \
  33. defined HAVE_PTHREAD_MUTEX_DESTROY && defined HAVE_PTHREAD_COND_DESTROY
  34. if ( 0 != pthread_mutex_init( &_lock._mutex, 0 ) )
  35. {
  36. return;
  37. }
  38. if ( 0 != pthread_cond_init( &_lock._readSignal, 0 ) )
  39. {
  40. pthread_mutex_destroy( &_lock._mutex );
  41. return;
  42. }
  43. if ( 0 != pthread_cond_init( &_lock._writeSignal, 0 ) )
  44. {
  45. pthread_mutex_destroy( &_lock._mutex );
  46. pthread_cond_destroy( &_lock._readSignal );
  47. return;
  48. }
  49. _lock._readersActive = 0;
  50. _lock._readersWaiting = 0;
  51. _lock._writersActive = 0;
  52. _lock._writersWaiting = 0;
  53. _magic = ESF_MAGIC;
  54. #else
  55. #error "Platform has no rw lock initializer"
  56. #endif
  57. }
  58. ESFReadWriteLock::~ESFReadWriteLock() {
  59. if (ESF_MAGIC != _magic) {
  60. return;
  61. }
  62. #ifdef HAVE_PTHREAD_RWLOCK_DESTROY
  63. pthread_rwlock_destroy(&_lock);
  64. #elif defined HAVE_PTHREAD_MUTEX_DESTROY && defined HAVE_PTHREAD_COND_DESTROY
  65. pthread_mutex_destroy( &_lock._mutex );
  66. pthread_cond_destroy( &_lock._readSignal );
  67. pthread_cond_destroy( &_lock._writeSignal );
  68. #else
  69. #error "Platform has no rw lock destructor."
  70. #endif
  71. }
  72. ESFError ESFReadWriteLock::writeAcquire() {
  73. if (ESF_MAGIC != _magic) {
  74. return ESF_NOT_INITIALIZED;
  75. }
  76. #ifdef HAVE_PTHREAD_RWLOCK_WRLOCK
  77. return ESFConvertError(pthread_rwlock_wrlock(&_lock));
  78. #elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_COND_WAIT && \
  79. defined HAVE_PTHREAD_MUTEX_UNLOCK
  80. ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) );
  81. if ( ESF_SUCCESS != error )
  82. {
  83. return error;
  84. }
  85. while ( 0 < _lock._writersActive || 0 < _lock._readersActive )
  86. {
  87. ++_lock._writersWaiting;
  88. error = ESFConvertError( pthread_cond_wait( &_lock._writeSignal,
  89. &_lock._mutex ) );
  90. --_lock._writersWaiting;
  91. if ( ESF_SUCCESS != error )
  92. {
  93. pthread_mutex_unlock( &_lock._mutex );
  94. return error;
  95. }
  96. }
  97. ESF_ASSERT( 0 == _lock._writersActive && 0 == _lock._readersActive );
  98. _lock._writersActive = 1;
  99. return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  100. #else
  101. #error "Platform has no rw lock write lock function."
  102. #endif
  103. }
  104. ESFError ESFReadWriteLock::readAcquire() {
  105. if (ESF_MAGIC != _magic) {
  106. return ESF_NOT_INITIALIZED;
  107. }
  108. #ifdef HAVE_PTHREAD_RWLOCK_RDLOCK
  109. return ESFConvertError(pthread_rwlock_rdlock(&_lock));
  110. #elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_COND_WAIT && \
  111. defined HAVE_PTHREAD_MUTEX_UNLOCK
  112. ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) );
  113. if ( ESF_SUCCESS != error )
  114. {
  115. return error;
  116. }
  117. while( 0 < _lock._writersActive || 0 < _lock._writersWaiting )
  118. {
  119. ++_lock._readersWaiting;
  120. error = ESFConvertError( pthread_cond_wait( &_lock._readSignal,
  121. &_lock._mutex ) );
  122. --_lock._readersWaiting;
  123. if ( ESF_SUCCESS != error )
  124. {
  125. pthread_mutex_unlock( &_lock._mutex );
  126. return error;
  127. }
  128. }
  129. ++_lock._readersActive;
  130. return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  131. #else
  132. #error "Platform has no rw lock read lock function."
  133. #endif
  134. }
  135. ESFError ESFReadWriteLock::writeAttempt() {
  136. if (ESF_MAGIC != _magic) {
  137. return ESF_NOT_INITIALIZED;
  138. }
  139. #ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK
  140. int error = pthread_rwlock_trywrlock(&_lock);
  141. switch (error) {
  142. case 0:
  143. return ESF_SUCCESS;
  144. case EBUSY:
  145. return ESF_AGAIN;
  146. default:
  147. return ESFConvertError(error);
  148. }
  149. #elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK
  150. ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) );
  151. if ( ESF_SUCCESS != error )
  152. {
  153. return error;
  154. }
  155. if ( 0 < _lock._writersActive || 0 < _lock._readersActive )
  156. {
  157. error = ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  158. return ESF_SUCCESS == error ? ESF_AGAIN : error;
  159. }
  160. _lock._writersActive = 1;
  161. return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  162. #else
  163. #error "Platform has no rw lock try write lock function."
  164. #endif
  165. }
  166. ESFError ESFReadWriteLock::readAttempt() {
  167. if (ESF_MAGIC != _magic) {
  168. return ESF_NOT_INITIALIZED;
  169. }
  170. #ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK
  171. int error = pthread_rwlock_tryrdlock(&_lock);
  172. switch (error) {
  173. case 0:
  174. return ESF_SUCCESS;
  175. case EBUSY:
  176. return ESF_AGAIN;
  177. default:
  178. return ESFConvertError(error);
  179. }
  180. #elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK
  181. ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) );
  182. if ( ESF_SUCCESS != error )
  183. {
  184. return error;
  185. }
  186. if ( 0 < _lock._writersActive )
  187. {
  188. error = ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  189. return ESF_SUCCESS == error ? ESF_AGAIN : error;
  190. }
  191. ++_lock._readersActive;
  192. return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  193. #else
  194. #error "Platform has no rw lock try read lock function."
  195. #endif
  196. }
  197. ESFError ESFReadWriteLock::writeRelease() {
  198. if (ESF_MAGIC != _magic) {
  199. return ESF_NOT_INITIALIZED;
  200. }
  201. #ifdef HAVE_PTHREAD_RWLOCK_UNLOCK
  202. return ESFConvertError(pthread_rwlock_unlock(&_lock));
  203. #elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK && \
  204. defined HAVE_PTHREAD_COND_SIGNAL && defined HAVE_PTHREAD_COND_BROADCAST
  205. ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) );
  206. if ( ESF_SUCCESS != error )
  207. {
  208. return error;
  209. }
  210. ESF_ASSERT( 1 == _lock._writersActive );
  211. if ( 1 != _lock._writersActive )
  212. {
  213. pthread_mutex_unlock( &_lock._mutex );
  214. return ESF_INVALID_STATE;
  215. }
  216. _lock._writersActive = 0;
  217. error = ESF_SUCCESS;
  218. if ( 0 < _lock._writersWaiting )
  219. {
  220. error = ESFConvertError( pthread_cond_signal( &_lock._writeSignal ) );
  221. }
  222. else if ( 0 < _lock._readersWaiting )
  223. {
  224. error = ESFConvertError( pthread_cond_broadcast( &_lock._readSignal ) );
  225. }
  226. if ( ESF_SUCCESS != error )
  227. {
  228. pthread_mutex_unlock( &_lock._mutex );
  229. return error;
  230. }
  231. return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  232. #else
  233. #error "Platform has no rw lock write unlock function."
  234. #endif
  235. }
  236. ESFError ESFReadWriteLock::readRelease() {
  237. if (ESF_MAGIC != _magic) {
  238. return ESF_NOT_INITIALIZED;
  239. }
  240. #ifdef HAVE_PTHREAD_RWLOCK_UNLOCK
  241. return ESFConvertError(pthread_rwlock_unlock(&_lock));
  242. #elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK && \
  243. defined HAVE_PTHREAD_COND_SIGNAL && defined HAVE_PTHREAD_COND_BROADCAST
  244. ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) );
  245. if ( ESF_SUCCESS != error )
  246. {
  247. return error;
  248. }
  249. ESF_ASSERT( 0 == _lock._writersActive );
  250. ESF_ASSERT( 0 < _lock._readersActive );
  251. if ( 0 < _lock._writersActive || 1> _lock._readersActive )
  252. {
  253. pthread_mutex_unlock( &_lock._mutex );
  254. return ESF_INVALID_STATE;
  255. }
  256. --_lock._readersActive;
  257. if ( 0 == _lock._readersActive && 0 < _lock._writersWaiting )
  258. {
  259. error = ESFConvertError( pthread_cond_signal( &_lock._writeSignal ) );
  260. if ( ESF_SUCCESS != error )
  261. {
  262. pthread_mutex_unlock( &_lock._mutex );
  263. return error;
  264. }
  265. }
  266. return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) );
  267. #else
  268. #error "Platform has no rw lock read unlock function."
  269. #endif
  270. }