00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #pragma once
00020
00021 #include "mutex.h"
00022 #include "../time_support.h"
00023
00024
00025
00026
00027
00028 #if !defined(MONGO_USE_SRW_ON_WINDOWS)
00029
00030 #if BOOST_VERSION >= 103500
00031 # define BOOST_RWLOCK
00032 #else
00033 # if defined(_WIN32)
00034 # error need boost >= 1.35 for windows
00035 # endif
00036 # include <pthread.h>
00037 #endif
00038
00039 #if defined(_WIN32)
00040 # include "shared_mutex_win.hpp"
00041 namespace mongo {
00042 typedef boost::modified_shared_mutex shared_mutex;
00043 }
00044 # undef assert
00045 # define assert MONGO_assert
00046 #elif defined(BOOST_RWLOCK)
00047 # include <boost/thread/shared_mutex.hpp>
00048 # undef assert
00049 # define assert MONGO_assert
00050 #endif
00051
00052 #endif
00053
00054 namespace mongo {
00055
00056 #if defined(MONGO_USE_SRW_ON_WINDOWS) && defined(_WIN32)
00057
00058 class RWLock {
00059 public:
00060 RWLock(const char *) { InitializeSRWLock(&_lock); }
00061 ~RWLock() { }
00062 void lock() { AcquireSRWLockExclusive(&_lock); }
00063 void unlock() { ReleaseSRWLockExclusive(&_lock); }
00064 void lock_shared() { AcquireSRWLockShared(&_lock); }
00065 void unlock_shared() { ReleaseSRWLockShared(&_lock); }
00066 bool lock_shared_try( int millis ) {
00067 unsigned long long end = curTimeMicros64() + millis*1000;
00068 while( 1 ) {
00069 if( TryAcquireSRWLockShared(&_lock) )
00070 return true;
00071 if( curTimeMicros64() >= end )
00072 break;
00073 Sleep(1);
00074 }
00075 return false;
00076 }
00077 bool lock_try( int millis = 0 ) {
00078 unsigned long long end = curTimeMicros64() + millis*1000;
00079 while( 1 ) {
00080 if( TryAcquireSRWLockExclusive(&_lock) )
00081 return true;
00082 if( curTimeMicros64() >= end )
00083 break;
00084 Sleep(1);
00085 }
00086 return false;
00087 }
00088 private:
00089 SRWLOCK _lock;
00090 };
00091
00092 #elif defined(BOOST_RWLOCK)
00093 class RWLock {
00094 shared_mutex _m;
00095 public:
00096 #if defined(_DEBUG)
00097 const char *_name;
00098 RWLock(const char *name) : _name(name) { }
00099 #else
00100 RWLock(const char *) { }
00101 #endif
00102 void lock() {
00103 _m.lock();
00104 #if defined(_DEBUG)
00105 mutexDebugger.entering(_name);
00106 #endif
00107 }
00108 void unlock() {
00109 #if defined(_DEBUG)
00110 mutexDebugger.leaving(_name);
00111 #endif
00112 _m.unlock();
00113 }
00114
00115 void lock_shared() {
00116 _m.lock_shared();
00117 }
00118
00119 void unlock_shared() {
00120 _m.unlock_shared();
00121 }
00122
00123 bool lock_shared_try( int millis ) {
00124 boost::system_time until = get_system_time();
00125 until += boost::posix_time::milliseconds(millis);
00126 if( _m.timed_lock_shared( until ) ) {
00127 return true;
00128 }
00129 return false;
00130 }
00131
00132 bool lock_try( int millis = 0 ) {
00133 boost::system_time until = get_system_time();
00134 until += boost::posix_time::milliseconds(millis);
00135 if( _m.timed_lock( until ) ) {
00136 #if defined(_DEBUG)
00137 mutexDebugger.entering(_name);
00138 #endif
00139 return true;
00140 }
00141 return false;
00142 }
00143
00144
00145 };
00146 #else
00147 class RWLock {
00148 pthread_rwlock_t _lock;
00149
00150 inline void check( int x ) {
00151 if( x == 0 )
00152 return;
00153 log() << "pthread rwlock failed: " << x << endl;
00154 assert( x == 0 );
00155 }
00156
00157 public:
00158 #if defined(_DEBUG)
00159 const char *_name;
00160 RWLock(const char *name) : _name(name) {
00161 #else
00162 RWLock(const char *) {
00163 #endif
00164 check( pthread_rwlock_init( &_lock , 0 ) );
00165 }
00166
00167 ~RWLock() {
00168 if ( ! StaticObserver::_destroyingStatics ) {
00169 check( pthread_rwlock_destroy( &_lock ) );
00170 }
00171 }
00172
00173 void lock() {
00174 check( pthread_rwlock_wrlock( &_lock ) );
00175 #if defined(_DEBUG)
00176 mutexDebugger.entering(_name);
00177 #endif
00178 }
00179 void unlock() {
00180 #if defined(_DEBUG)
00181 mutexDebugger.leaving(_name);
00182 #endif
00183 check( pthread_rwlock_unlock( &_lock ) );
00184 }
00185
00186 void lock_shared() {
00187 check( pthread_rwlock_rdlock( &_lock ) );
00188 }
00189
00190 void unlock_shared() {
00191 check( pthread_rwlock_unlock( &_lock ) );
00192 }
00193
00194 bool lock_shared_try( int millis ) {
00195 return _try( millis , false );
00196 }
00197
00198 bool lock_try( int millis = 0 ) {
00199 if( _try( millis , true ) ) {
00200 #if defined(_DEBUG)
00201 mutexDebugger.entering(_name);
00202 #endif
00203 return true;
00204 }
00205 return false;
00206 }
00207
00208 bool _try( int millis , bool write ) {
00209 while ( true ) {
00210 int x = write ?
00211 pthread_rwlock_trywrlock( &_lock ) :
00212 pthread_rwlock_tryrdlock( &_lock );
00213
00214 if ( x <= 0 ) {
00215 return true;
00216 }
00217
00218 if ( millis-- <= 0 )
00219 return false;
00220
00221 if ( x == EBUSY ) {
00222 sleepmillis(1);
00223 continue;
00224 }
00225 check(x);
00226 }
00227
00228 return false;
00229 }
00230
00231 };
00232
00233 #endif
00234
00236 class rwlock_try_write {
00237 public:
00238 struct exception { };
00239 rwlock_try_write(RWLock& l, int millis = 0) : _l(l) {
00240 if( !l.lock_try(millis) )
00241 throw exception();
00242 }
00243 ~rwlock_try_write() { _l.unlock(); }
00244 private:
00245 RWLock& _l;
00246 };
00247
00248
00249 class rwlock {
00250 public:
00251 rwlock( const RWLock& lock , bool write , bool alreadyHaveLock = false )
00252 : _lock( (RWLock&)lock ) , _write( write ) {
00253 if ( ! alreadyHaveLock ) {
00254 if ( _write )
00255 _lock.lock();
00256 else
00257 _lock.lock_shared();
00258 }
00259 }
00260 ~rwlock() {
00261 if ( _write )
00262 _lock.unlock();
00263 else
00264 _lock.unlock_shared();
00265 }
00266 private:
00267 RWLock& _lock;
00268 const bool _write;
00269 };
00270 }