diff options
Diffstat (limited to 'src/mongo/util/concurrency/rwlock.h')
-rw-r--r-- | src/mongo/util/concurrency/rwlock.h | 408 |
1 files changed, 222 insertions, 186 deletions
diff --git a/src/mongo/util/concurrency/rwlock.h b/src/mongo/util/concurrency/rwlock.h index 22373efd421..b3988efa06b 100644 --- a/src/mongo/util/concurrency/rwlock.h +++ b/src/mongo/util/concurrency/rwlock.h @@ -39,217 +39,253 @@ namespace mongo { - class RWLock : public RWLockBase { - enum { NilState, UpgradableState, Exclusive } x; // only bother to set when doing upgradable related things - public: - const char * const _name; - RWLock(const char *name) : _name(name) { - x = NilState; - } - void lock() { - RWLockBase::lock(); - } - void unlock() { - RWLockBase::unlock(); - } +class RWLock : public RWLockBase { + enum { + NilState, + UpgradableState, + Exclusive + } x; // only bother to set when doing upgradable related things +public: + const char* const _name; + RWLock(const char* name) : _name(name) { + x = NilState; + } + void lock() { + RWLockBase::lock(); + } + void unlock() { + RWLockBase::unlock(); + } - void lock_shared() { RWLockBase::lock_shared(); } - void unlock_shared() { RWLockBase::unlock_shared(); } - private: - void lockAsUpgradable() { RWLockBase::lockAsUpgradable(); } - void unlockFromUpgradable() { // upgradable -> unlocked - RWLockBase::unlockFromUpgradable(); - } - public: - void upgrade() { // upgradable -> exclusive lock - verify( x == UpgradableState ); - RWLockBase::upgrade(); - x = Exclusive; - } + void lock_shared() { + RWLockBase::lock_shared(); + } + void unlock_shared() { + RWLockBase::unlock_shared(); + } - bool lock_shared_try( int millis ) { return RWLockBase::lock_shared_try(millis); } +private: + void lockAsUpgradable() { + RWLockBase::lockAsUpgradable(); + } + void unlockFromUpgradable() { // upgradable -> unlocked + RWLockBase::unlockFromUpgradable(); + } - bool lock_try( int millis = 0 ) { - return RWLockBase::lock_try(millis); - } +public: + void upgrade() { // upgradable -> exclusive lock + verify(x == UpgradableState); + RWLockBase::upgrade(); + x = Exclusive; + } - /** acquire upgradable state. You must be unlocked before creating. - unlocks on destruction, whether in upgradable state or upgraded to exclusive - in the interim. - */ - class Upgradable { - MONGO_DISALLOW_COPYING(Upgradable); - RWLock& _r; - public: - Upgradable(RWLock& r) : _r(r) { - r.lockAsUpgradable(); - verify( _r.x == NilState ); - _r.x = RWLock::UpgradableState; - } - ~Upgradable() { - if( _r.x == RWLock::UpgradableState ) { - _r.x = NilState; - _r.unlockFromUpgradable(); - } - else { - //TEMP verify( _r.x == Exclusive ); // has been upgraded - _r.x = NilState; - _r.unlock(); - } - } - }; - }; + bool lock_shared_try(int millis) { + return RWLockBase::lock_shared_try(millis); + } - /** throws on failure to acquire in the specified time period. */ - class rwlock_try_write { - MONGO_DISALLOW_COPYING(rwlock_try_write); - public: - struct exception { }; - rwlock_try_write(RWLock& l, int millis = 0) : _l(l) { - if( !l.lock_try(millis) ) - throw exception(); - } - ~rwlock_try_write() { _l.unlock(); } - private: - RWLock& _l; - }; + bool lock_try(int millis = 0) { + return RWLockBase::lock_try(millis); + } - class rwlock_shared { - MONGO_DISALLOW_COPYING(rwlock_shared); - public: - rwlock_shared(RWLock& rwlock) : _r(rwlock) {_r.lock_shared(); } - ~rwlock_shared() { _r.unlock_shared(); } - private: + /** acquire upgradable state. You must be unlocked before creating. + unlocks on destruction, whether in upgradable state or upgraded to exclusive + in the interim. + */ + class Upgradable { + MONGO_DISALLOW_COPYING(Upgradable); RWLock& _r; - }; - /* scoped lock for RWLock */ - class rwlock { - MONGO_DISALLOW_COPYING(rwlock); public: - /** - * @param write acquire write lock if true sharable if false - * @param lowPriority if > 0, will try to get the lock non-greedily for that many ms - */ - rwlock( const RWLock& lock , bool write, /* bool alreadyHaveLock = false , */int lowPriorityWaitMS = 0 ) - : _lock( (RWLock&)lock ) , _write( write ) { - { - if ( _write ) { - _lock.lock(); - } - else { - _lock.lock_shared(); - } - } + Upgradable(RWLock& r) : _r(r) { + r.lockAsUpgradable(); + verify(_r.x == NilState); + _r.x = RWLock::UpgradableState; } - ~rwlock() { - if ( _write ) - _lock.unlock(); - else - _lock.unlock_shared(); + ~Upgradable() { + if (_r.x == RWLock::UpgradableState) { + _r.x = NilState; + _r.unlockFromUpgradable(); + } else { + // TEMP verify( _r.x == Exclusive ); // has been upgraded + _r.x = NilState; + _r.unlock(); + } } - private: - RWLock& _lock; - const bool _write; }; +}; - // ---------------------------------------------------------------------------------------- +/** throws on failure to acquire in the specified time period. */ +class rwlock_try_write { + MONGO_DISALLOW_COPYING(rwlock_try_write); - /** recursive on shared locks is ok for this implementation */ - class RWLockRecursive : protected RWLockBase { - protected: - ThreadLocalValue<int> _state; - void lock(); // not implemented - Lock() should be used; didn't overload this name to avoid mistakes - virtual void Lock() { RWLockBase::lock(); } - public: - virtual ~RWLockRecursive() { } - const char * const _name; - RWLockRecursive(const char *name) : _name(name) { } +public: + struct exception {}; + rwlock_try_write(RWLock& l, int millis = 0) : _l(l) { + if (!l.lock_try(millis)) + throw exception(); + } + ~rwlock_try_write() { + _l.unlock(); + } + +private: + RWLock& _l; +}; + +class rwlock_shared { + MONGO_DISALLOW_COPYING(rwlock_shared); + +public: + rwlock_shared(RWLock& rwlock) : _r(rwlock) { + _r.lock_shared(); + } + ~rwlock_shared() { + _r.unlock_shared(); + } + +private: + RWLock& _r; +}; - void assertAtLeastReadLocked() { - verify( _state.get() != 0 ); +/* scoped lock for RWLock */ +class rwlock { + MONGO_DISALLOW_COPYING(rwlock); + +public: + /** + * @param write acquire write lock if true sharable if false + * @param lowPriority if > 0, will try to get the lock non-greedily for that many ms + */ + rwlock(const RWLock& lock, + bool write, + /* bool alreadyHaveLock = false , */ int lowPriorityWaitMS = 0) + : _lock((RWLock&)lock), _write(write) { + { + if (_write) { + _lock.lock(); + } else { + _lock.lock_shared(); + } + } + } + ~rwlock() { + if (_write) + _lock.unlock(); + else + _lock.unlock_shared(); + } + +private: + RWLock& _lock; + const bool _write; +}; + +// ---------------------------------------------------------------------------------------- + +/** recursive on shared locks is ok for this implementation */ +class RWLockRecursive : protected RWLockBase { +protected: + ThreadLocalValue<int> _state; + void + lock(); // not implemented - Lock() should be used; didn't overload this name to avoid mistakes + virtual void Lock() { + RWLockBase::lock(); + } + +public: + virtual ~RWLockRecursive() {} + const char* const _name; + RWLockRecursive(const char* name) : _name(name) {} + + void assertAtLeastReadLocked() { + verify(_state.get() != 0); + } + void assertExclusivelyLocked() { + verify(_state.get() < 0); + } + + class Exclusive { + MONGO_DISALLOW_COPYING(Exclusive); + RWLockRecursive& _r; + + public: + Exclusive(RWLockRecursive& r) : _r(r) { + int s = _r._state.get(); + dassert(s <= 0); + if (s == 0) + _r.Lock(); + _r._state.set(s - 1); } - void assertExclusivelyLocked() { - verify( _state.get() < 0 ); + ~Exclusive() { + int s = _r._state.get(); + DEV wassert(s < 0); // wassert: don't throw from destructors + ++s; + _r._state.set(s); + if (s == 0) + _r.unlock(); } + }; - class Exclusive { - MONGO_DISALLOW_COPYING(Exclusive); - RWLockRecursive& _r; - public: - Exclusive(RWLockRecursive& r) : _r(r) { - int s = _r._state.get(); - dassert( s <= 0 ); - if( s == 0 ) - _r.Lock(); - _r._state.set(s-1); + class Shared { + MONGO_DISALLOW_COPYING(Shared); + RWLockRecursive& _r; + bool _alreadyLockedExclusiveByUs; + + public: + Shared(RWLockRecursive& r) : _r(r) { + int s = _r._state.get(); + _alreadyLockedExclusiveByUs = s < 0; + if (!_alreadyLockedExclusiveByUs) { + dassert(s >= 0); // -1 would mean exclusive + if (s == 0) + _r.lock_shared(); + _r._state.set(s + 1); } - ~Exclusive() { - int s = _r._state.get(); - DEV wassert( s < 0 ); // wassert: don't throw from destructors - ++s; + } + ~Shared() { + if (_alreadyLockedExclusiveByUs) { + DEV wassert(_r._state.get() < 0); + } else { + int s = _r._state.get() - 1; + DEV wassert(s >= 0); _r._state.set(s); - if ( s == 0 ) - _r.unlock(); + if (s == 0) + _r.unlock_shared(); } - }; - - class Shared { - MONGO_DISALLOW_COPYING(Shared); - RWLockRecursive& _r; - bool _alreadyLockedExclusiveByUs; - public: - Shared(RWLockRecursive& r) : _r(r) { - int s = _r._state.get(); - _alreadyLockedExclusiveByUs = s < 0; - if( !_alreadyLockedExclusiveByUs ) { - dassert( s >= 0 ); // -1 would mean exclusive - if( s == 0 ) - _r.lock_shared(); - _r._state.set(s+1); - } - } - ~Shared() { - if( _alreadyLockedExclusiveByUs ) { - DEV wassert( _r._state.get() < 0 ); - } - else { - int s = _r._state.get() - 1; - DEV wassert( s >= 0 ); - _r._state.set(s); - if( s == 0 ) - _r.unlock_shared(); - } - } - }; + } }; +}; - class RWLockRecursiveNongreedy : public RWLockRecursive { - virtual void Lock() { - bool got = false; - for ( int i=0; i<lowPriorityWaitMS; i++ ) { - if ( lock_try(0) ) { - got = true; - break; - } - int sleep = 1; - if ( i > ( lowPriorityWaitMS / 20 ) ) - sleep = 10; - sleepmillis(sleep); - i += ( sleep - 1 ); - } - if ( ! got ) { - RWLockBase::lock(); +class RWLockRecursiveNongreedy : public RWLockRecursive { + virtual void Lock() { + bool got = false; + for (int i = 0; i < lowPriorityWaitMS; i++) { + if (lock_try(0)) { + got = true; + break; } + int sleep = 1; + if (i > (lowPriorityWaitMS / 20)) + sleep = 10; + sleepmillis(sleep); + i += (sleep - 1); } + if (!got) { + RWLockBase::lock(); + } + } - public: - const int lowPriorityWaitMS; - RWLockRecursiveNongreedy(const char *nm, int lpwaitms) : RWLockRecursive(nm), lowPriorityWaitMS(lpwaitms) { } - const char * implType() const { return RWLockRecursive::implType(); } - - //just for testing: - bool __lock_try( int millis ) { return RWLockRecursive::lock_try(millis); } - }; +public: + const int lowPriorityWaitMS; + RWLockRecursiveNongreedy(const char* nm, int lpwaitms) + : RWLockRecursive(nm), lowPriorityWaitMS(lpwaitms) {} + const char* implType() const { + return RWLockRecursive::implType(); + } + // just for testing: + bool __lock_try(int millis) { + return RWLockRecursive::lock_try(millis); + } +}; } |