/sparrowhawk/foundation/ESFReadWriteLock.cpp
C++ | 375 lines | 254 code | 105 blank | 16 comment | 83 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 18#ifndef ESF_READ_WRITE_LOCK_H 19#include <ESFReadWriteLock.h> 20#endif 21 22#ifndef ESF_ASSERT_H 23#include <ESFAssert.h> 24#endif 25 26#ifdef HAVE_ERRNO_H 27#include <errno.h> 28#endif 29 30ESFReadWriteLock::ESFReadWriteLock() : 31 _magic(0) { 32#ifdef HAVE_PTHREAD_RWLOCK_INIT 33 34 if (0 == pthread_rwlock_init(&_lock, 0)) { 35 _magic = ESF_MAGIC; 36 } 37 38#elif defined HAVE_PTHREAD_MUTEX_INIT && defined HAVE_PTHREAD_COND_INIT && \ 39 defined HAVE_PTHREAD_MUTEX_DESTROY && defined HAVE_PTHREAD_COND_DESTROY 40 41 if ( 0 != pthread_mutex_init( &_lock._mutex, 0 ) ) 42 { 43 return; 44 } 45 46 if ( 0 != pthread_cond_init( &_lock._readSignal, 0 ) ) 47 { 48 pthread_mutex_destroy( &_lock._mutex ); 49 return; 50 } 51 52 if ( 0 != pthread_cond_init( &_lock._writeSignal, 0 ) ) 53 { 54 pthread_mutex_destroy( &_lock._mutex ); 55 pthread_cond_destroy( &_lock._readSignal ); 56 return; 57 } 58 59 _lock._readersActive = 0; 60 _lock._readersWaiting = 0; 61 _lock._writersActive = 0; 62 _lock._writersWaiting = 0; 63 64 _magic = ESF_MAGIC; 65 66#else 67#error "Platform has no rw lock initializer" 68#endif 69} 70 71ESFReadWriteLock::~ESFReadWriteLock() { 72 if (ESF_MAGIC != _magic) { 73 return; 74 } 75 76#ifdef HAVE_PTHREAD_RWLOCK_DESTROY 77 78 pthread_rwlock_destroy(&_lock); 79 80#elif defined HAVE_PTHREAD_MUTEX_DESTROY && defined HAVE_PTHREAD_COND_DESTROY 81 82 pthread_mutex_destroy( &_lock._mutex ); 83 pthread_cond_destroy( &_lock._readSignal ); 84 pthread_cond_destroy( &_lock._writeSignal ); 85 86#else 87#error "Platform has no rw lock destructor." 88#endif 89} 90 91ESFError ESFReadWriteLock::writeAcquire() { 92 if (ESF_MAGIC != _magic) { 93 return ESF_NOT_INITIALIZED; 94 } 95 96#ifdef HAVE_PTHREAD_RWLOCK_WRLOCK 97 98 return ESFConvertError(pthread_rwlock_wrlock(&_lock)); 99 100#elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_COND_WAIT && \ 101 defined HAVE_PTHREAD_MUTEX_UNLOCK 102 103 ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) ); 104 105 if ( ESF_SUCCESS != error ) 106 { 107 return error; 108 } 109 110 while ( 0 < _lock._writersActive || 0 < _lock._readersActive ) 111 { 112 ++_lock._writersWaiting; 113 114 error = ESFConvertError( pthread_cond_wait( &_lock._writeSignal, 115 &_lock._mutex ) ); 116 117 --_lock._writersWaiting; 118 119 if ( ESF_SUCCESS != error ) 120 { 121 pthread_mutex_unlock( &_lock._mutex ); 122 123 return error; 124 } 125 } 126 127 ESF_ASSERT( 0 == _lock._writersActive && 0 == _lock._readersActive ); 128 129 _lock._writersActive = 1; 130 131 return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 132 133#else 134#error "Platform has no rw lock write lock function." 135#endif 136} 137 138ESFError ESFReadWriteLock::readAcquire() { 139 if (ESF_MAGIC != _magic) { 140 return ESF_NOT_INITIALIZED; 141 } 142 143#ifdef HAVE_PTHREAD_RWLOCK_RDLOCK 144 145 return ESFConvertError(pthread_rwlock_rdlock(&_lock)); 146 147#elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_COND_WAIT && \ 148 defined HAVE_PTHREAD_MUTEX_UNLOCK 149 150 ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) ); 151 152 if ( ESF_SUCCESS != error ) 153 { 154 return error; 155 } 156 157 while( 0 < _lock._writersActive || 0 < _lock._writersWaiting ) 158 { 159 ++_lock._readersWaiting; 160 161 error = ESFConvertError( pthread_cond_wait( &_lock._readSignal, 162 &_lock._mutex ) ); 163 164 --_lock._readersWaiting; 165 166 if ( ESF_SUCCESS != error ) 167 { 168 pthread_mutex_unlock( &_lock._mutex ); 169 170 return error; 171 } 172 } 173 174 ++_lock._readersActive; 175 176 return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 177 178#else 179#error "Platform has no rw lock read lock function." 180#endif 181} 182 183ESFError ESFReadWriteLock::writeAttempt() { 184 if (ESF_MAGIC != _magic) { 185 return ESF_NOT_INITIALIZED; 186 } 187 188#ifdef HAVE_PTHREAD_RWLOCK_TRYWRLOCK 189 190 int error = pthread_rwlock_trywrlock(&_lock); 191 192 switch (error) { 193 case 0: 194 return ESF_SUCCESS; 195 196 case EBUSY: 197 return ESF_AGAIN; 198 199 default: 200 return ESFConvertError(error); 201 } 202 203#elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK 204 205 ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) ); 206 207 if ( ESF_SUCCESS != error ) 208 { 209 return error; 210 } 211 212 if ( 0 < _lock._writersActive || 0 < _lock._readersActive ) 213 { 214 error = ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 215 216 return ESF_SUCCESS == error ? ESF_AGAIN : error; 217 } 218 219 _lock._writersActive = 1; 220 221 return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 222 223#else 224#error "Platform has no rw lock try write lock function." 225#endif 226} 227 228ESFError ESFReadWriteLock::readAttempt() { 229 if (ESF_MAGIC != _magic) { 230 return ESF_NOT_INITIALIZED; 231 } 232 233#ifdef HAVE_PTHREAD_RWLOCK_TRYRDLOCK 234 235 int error = pthread_rwlock_tryrdlock(&_lock); 236 237 switch (error) { 238 case 0: 239 return ESF_SUCCESS; 240 241 case EBUSY: 242 return ESF_AGAIN; 243 244 default: 245 return ESFConvertError(error); 246 } 247 248#elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK 249 250 ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) ); 251 252 if ( ESF_SUCCESS != error ) 253 { 254 return error; 255 } 256 257 if ( 0 < _lock._writersActive ) 258 { 259 error = ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 260 261 return ESF_SUCCESS == error ? ESF_AGAIN : error; 262 } 263 264 ++_lock._readersActive; 265 266 return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 267 268#else 269#error "Platform has no rw lock try read lock function." 270#endif 271} 272 273ESFError ESFReadWriteLock::writeRelease() { 274 if (ESF_MAGIC != _magic) { 275 return ESF_NOT_INITIALIZED; 276 } 277 278#ifdef HAVE_PTHREAD_RWLOCK_UNLOCK 279 280 return ESFConvertError(pthread_rwlock_unlock(&_lock)); 281 282#elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK && \ 283 defined HAVE_PTHREAD_COND_SIGNAL && defined HAVE_PTHREAD_COND_BROADCAST 284 285 ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) ); 286 287 if ( ESF_SUCCESS != error ) 288 { 289 return error; 290 } 291 292 ESF_ASSERT( 1 == _lock._writersActive ); 293 294 if ( 1 != _lock._writersActive ) 295 { 296 pthread_mutex_unlock( &_lock._mutex ); 297 298 return ESF_INVALID_STATE; 299 } 300 301 _lock._writersActive = 0; 302 303 error = ESF_SUCCESS; 304 305 if ( 0 < _lock._writersWaiting ) 306 { 307 error = ESFConvertError( pthread_cond_signal( &_lock._writeSignal ) ); 308 } 309 else if ( 0 < _lock._readersWaiting ) 310 { 311 error = ESFConvertError( pthread_cond_broadcast( &_lock._readSignal ) ); 312 } 313 314 if ( ESF_SUCCESS != error ) 315 { 316 pthread_mutex_unlock( &_lock._mutex ); 317 318 return error; 319 } 320 321 return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 322 323#else 324#error "Platform has no rw lock write unlock function." 325#endif 326} 327 328ESFError ESFReadWriteLock::readRelease() { 329 if (ESF_MAGIC != _magic) { 330 return ESF_NOT_INITIALIZED; 331 } 332 333#ifdef HAVE_PTHREAD_RWLOCK_UNLOCK 334 335 return ESFConvertError(pthread_rwlock_unlock(&_lock)); 336 337#elif defined HAVE_PTHREAD_MUTEX_LOCK && defined HAVE_PTHREAD_MUTEX_UNLOCK && \ 338 defined HAVE_PTHREAD_COND_SIGNAL && defined HAVE_PTHREAD_COND_BROADCAST 339 340 ESFError error = ESFConvertError( pthread_mutex_lock( &_lock._mutex ) ); 341 342 if ( ESF_SUCCESS != error ) 343 { 344 return error; 345 } 346 347 ESF_ASSERT( 0 == _lock._writersActive ); 348 ESF_ASSERT( 0 < _lock._readersActive ); 349 350 if ( 0 < _lock._writersActive || 1> _lock._readersActive ) 351 { 352 pthread_mutex_unlock( &_lock._mutex ); 353 354 return ESF_INVALID_STATE; 355 } 356 357 --_lock._readersActive; 358 359 if ( 0 == _lock._readersActive && 0 < _lock._writersWaiting ) 360 { 361 error = ESFConvertError( pthread_cond_signal( &_lock._writeSignal ) ); 362 363 if ( ESF_SUCCESS != error ) 364 { 365 pthread_mutex_unlock( &_lock._mutex ); 366 return error; 367 } 368 } 369 370 return ESFConvertError( pthread_mutex_unlock( &_lock._mutex ) ); 371 372#else 373#error "Platform has no rw lock read unlock function." 374#endif 375}