summaryrefslogtreecommitdiff
path: root/util/concurrency/mutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'util/concurrency/mutex.h')
-rw-r--r--util/concurrency/mutex.h279
1 files changed, 0 insertions, 279 deletions
diff --git a/util/concurrency/mutex.h b/util/concurrency/mutex.h
deleted file mode 100644
index f17c3f0891d..00000000000
--- a/util/concurrency/mutex.h
+++ /dev/null
@@ -1,279 +0,0 @@
-// @file mutex.h
-
-/* Copyright 2009 10gen Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <map>
-#include <set>
-#include "../heapcheck.h"
-
-namespace mongo {
-
- void printStackTrace( ostream &o );
-
- class mutex;
-
- inline boost::xtime incxtimemillis( long long s ) {
- boost::xtime xt;
- boost::xtime_get(&xt, boost::TIME_UTC);
- xt.sec += (int)( s / 1000 );
- xt.nsec += (int)(( s % 1000 ) * 1000000);
- if ( xt.nsec >= 1000000000 ) {
- xt.nsec -= 1000000000;
- xt.sec++;
- }
- return xt;
- }
-
- /** only used on _DEBUG builds.
- MutexDebugger checks that we always acquire locks for multiple mutexes in a consistant (acyclic) order.
- If we were inconsistent we could deadlock.
- */
- class MutexDebugger {
- typedef const char * mid; // mid = mutex ID
- typedef map<mid,int> Preceeding;
- map< mid, int > maxNest;
- boost::thread_specific_ptr< Preceeding > us;
- map< mid, set<mid> > followers;
- boost::mutex &x;
- unsigned magic;
- void aBreakPoint() { } // for debugging
- public:
- // set these to create an assert that
- // b must never be locked before a
- // so
- // a.lock(); b.lock(); is fine
- // b.lock(); alone is fine too
- // only checked on _DEBUG builds.
- string a,b;
-
- /** outputs some diagnostic info on mutexes (on _DEBUG builds) */
- void programEnding();
-
- MutexDebugger();
-
- void entering(mid m) {
- if( this == 0 ) return;
- assert( magic == 0x12345678 );
-
- Preceeding *_preceeding = us.get();
- if( _preceeding == 0 )
- us.reset( _preceeding = new Preceeding() );
- Preceeding &preceeding = *_preceeding;
-
- if( a == m ) {
- aBreakPoint();
- if( preceeding[b.c_str()] ) {
- cout << "****** MutexDebugger error! warning " << b << " was locked before " << a << endl;
- assert(false);
- }
- }
-
- preceeding[m]++;
- if( preceeding[m] > 1 ) {
- // recursive re-locking.
- if( preceeding[m] > maxNest[m] )
- maxNest[m] = preceeding[m];
- return;
- }
-
- bool failed = false;
- string err;
- {
- boost::mutex::scoped_lock lk(x);
- followers[m];
- for( Preceeding::iterator i = preceeding.begin(); i != preceeding.end(); i++ ) {
- if( m != i->first && i->second > 0 ) {
- followers[i->first].insert(m);
- if( followers[m].count(i->first) != 0 ) {
- failed = true;
- stringstream ss;
- mid bad = i->first;
- ss << "mutex problem" <<
- "\n when locking " << m <<
- "\n " << bad << " was already locked and should not be."
- "\n set a and b above to debug.\n";
- stringstream q;
- for( Preceeding::iterator i = preceeding.begin(); i != preceeding.end(); i++ ) {
- if( i->first != m && i->first != bad && i->second > 0 )
- q << " " << i->first << '\n';
- }
- string also = q.str();
- if( !also.empty() )
- ss << "also locked before " << m << " in this thread (no particular order):\n" << also;
- err = ss.str();
- break;
- }
- }
- }
- }
- if( failed ) {
- cout << err << endl;
- assert( 0 );
- }
- }
- void leaving(mid m) {
- if( this == 0 ) return; // still in startup pre-main()
- Preceeding& preceeding = *us.get();
- preceeding[m]--;
- if( preceeding[m] < 0 ) {
- cout << "ERROR: lock count for " << m << " is " << preceeding[m] << endl;
- assert( preceeding[m] >= 0 );
- }
- }
- };
- extern MutexDebugger &mutexDebugger;
-
- // If you create a local static instance of this class, that instance will be destroyed
- // before all global static objects are destroyed, so _destroyingStatics will be set
- // to true before the global static variables are destroyed.
- class StaticObserver : boost::noncopyable {
- public:
- static bool _destroyingStatics;
- ~StaticObserver() { _destroyingStatics = true; }
- };
-
- /** On pthread systems, it is an error to destroy a mutex while held (boost mutex
- * may use pthread). Static global mutexes may be held upon shutdown in our
- * implementation, and this way we avoid destroying them.
- * NOT recursive.
- */
- class mutex : boost::noncopyable {
- public:
-#if defined(_DEBUG)
- const char * const _name;
- mutex(const char *name) : _name(name)
-#else
- mutex(const char *)
-#endif
- {
- _m = new boost::timed_mutex();
- IGNORE_OBJECT( _m ); // Turn-off heap checking on _m
- }
- ~mutex() {
- if( !StaticObserver::_destroyingStatics ) {
- UNIGNORE_OBJECT( _m );
- delete _m;
- }
- }
-
- class try_lock : boost::noncopyable {
- public:
- try_lock( mongo::mutex &m , int millis = 0 )
- : _l( m.boost() , incxtimemillis( millis ) ) ,
-#if BOOST_VERSION >= 103500
- ok( _l.owns_lock() )
-#else
- ok( _l.locked() )
-#endif
- { }
- private:
- boost::timed_mutex::scoped_timed_lock _l;
- public:
- const bool ok;
- };
-
- class scoped_lock : boost::noncopyable {
- public:
-#if defined(_DEBUG)
- struct PostStaticCheck {
- PostStaticCheck() {
- if ( StaticObserver::_destroyingStatics ) {
- cout << "trying to lock a mongo::mutex during static shutdown" << endl;
- printStackTrace( cout );
- }
- }
- };
-
- PostStaticCheck _check;
- mongo::mutex * const _mut;
-#endif
- scoped_lock( mongo::mutex &m ) :
-#if defined(_DEBUG)
- _mut(&m),
-#endif
- _l( m.boost() ) {
-#if defined(_DEBUG)
- mutexDebugger.entering(_mut->_name);
-#endif
- }
- ~scoped_lock() {
-#if defined(_DEBUG)
- mutexDebugger.leaving(_mut->_name);
-#endif
- }
- boost::timed_mutex::scoped_lock &boost() { return _l; }
- private:
- boost::timed_mutex::scoped_lock _l;
- };
- private:
- boost::timed_mutex &boost() { return *_m; }
- boost::timed_mutex *_m;
- };
-
- typedef mutex::scoped_lock scoped_lock;
- typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock;
-
- /** The concept with SimpleMutex is that it is a basic lock/unlock with no
- special functionality (such as try and try timeout). Thus it can be
- implemented using OS-specific facilities in all environments (if desired).
- On Windows, the implementation below is faster than boost mutex.
- */
-#if defined(_WIN32)
- class SimpleMutex : boost::noncopyable {
- CRITICAL_SECTION _cs;
- public:
- SimpleMutex(const char *name) { InitializeCriticalSection(&_cs); }
- ~SimpleMutex() { DeleteCriticalSection(&_cs); }
-
- void lock() { EnterCriticalSection(&_cs); }
- void unlock() { LeaveCriticalSection(&_cs); }
-
- class scoped_lock : boost::noncopyable {
- SimpleMutex& _m;
- public:
- scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
- ~scoped_lock() { _m.unlock(); }
- };
- };
-#else
- class SimpleMutex : boost::noncopyable {
- public:
- SimpleMutex(const char* name) { assert( pthread_mutex_init(&_lock,0) == 0 ); }
- ~SimpleMutex(){
- if ( ! StaticObserver::_destroyingStatics ) {
- assert( pthread_mutex_destroy(&_lock) == 0 );
- }
- }
-
- void lock() { assert( pthread_mutex_lock(&_lock) == 0 ); }
- void unlock() { assert( pthread_mutex_unlock(&_lock) == 0 ); }
-
- class scoped_lock : boost::noncopyable {
- SimpleMutex& _m;
- public:
- scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
- ~scoped_lock() { _m.unlock(); }
- };
-
- private:
- pthread_mutex_t _lock;
- };
-
-#endif
-
-}