PageRenderTime 76ms CodeModel.GetById 56ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/sparrowhawk/foundation/ESFReadWriteLock.cpp

http://github.com/jtblatt/duderino
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}