Mutex.h

00001 /* This file is Copyright 2000-2008 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */
00002 
00003 #ifndef MuscleMutex_h
00004 #define MuscleMutex_h
00005 
00006 #ifndef MUSCLE_SINGLE_THREAD_ONLY
00007 
00008 #if defined(QT_CORE_LIB)  // is Qt4 available?
00009 # include <Qt>  // to bring in the proper value of QT_VERSION
00010 #endif
00011 
00012 #if defined(QT_THREAD_SUPPORT) || (QT_VERSION >= 0x040000)
00013 # define MUSCLE_QT_HAS_THREADS 1
00014 #endif
00015 
00016 # if defined(WIN32)
00017 #  if defined(MUSCLE_QT_HAS_THREADS) && defined(MUSCLE_PREFER_QT_OVER_WIN32)
00018     /* empty - we don't have to do anything for this case. */
00019 #  else
00020 #   define MUSCLE_PREFER_WIN32_OVER_QT
00021 #  endif
00022 # endif
00023 # if defined(MUSCLE_USE_PTHREADS)
00024 #  include <pthread.h>
00025 # elif defined(MUSCLE_PREFER_WIN32_OVER_QT)
00026 #  include <windows.h>
00027 # elif defined(MUSCLE_QT_HAS_THREADS)
00028 #  if (QT_VERSION >= 0x040000)
00029 #   include <QMutex>
00030 #  else
00031 #   include <qthread.h>
00032 #  endif
00033 # elif defined(__BEOS__)
00034 #  include <support/Locker.h>
00035 # elif defined(__ATHEOS__)
00036 #  include <util/locker.h>
00037 # else
00038 #  error "Mutex:  threading support not implemented for this platform.  You'll need to add code to the MUSCLE Mutex class for your platform, or add -DMUSCLE_SINGLE_THREAD_ONLY to your build line if your program is single-threaded or for some other reason doesn't need to worry about locking"
00039 # endif
00040 #endif
00041 
00042 #include "support/MuscleSupport.h"
00043 
00044 BEGIN_NAMESPACE(muscle);
00045 
00046 // If false, then we must not assume that we are running in single-threaded mode.
00047 // This variable should be set by the ThreadSetupSystem constructor ONLY!
00048 extern bool _muscleSingleThreadOnly;
00049 
00055 class Mutex
00056 {
00057 public:
00059    Mutex()
00060 #ifndef MUSCLE_SINGLE_THREAD_ONLY
00061       : _isEnabled(_muscleSingleThreadOnly == false)
00062 # if defined(MUSCLE_USE_PTHREADS)
00063       // empty
00064 # elif defined(MUSCLE_PREFER_WIN32_OVER_QT)
00065       , _locker(_isEnabled ? CreateMutex(NULL, false, NULL) : NULL)
00066 # elif defined(MUSCLE_QT_HAS_THREADS)
00067 #  if (QT_VERSION >= 0x040000)
00068       , _locker(QMutex::Recursive)
00069 #  else
00070       , _locker(true)
00071 #  endif
00072 # elif defined(__ATHEOS__)
00073       , _locker(NULL) 
00074 # endif
00075 #endif
00076    {
00077 #ifndef MUSCLE_SINGLE_THREAD_ONLY
00078       if (_isEnabled)
00079       {
00080 # if defined(MUSCLE_USE_PTHREADS)
00081          pthread_mutexattr_t mutexattr;
00082          pthread_mutexattr_init(&mutexattr);                              // Note:  If this code doesn't compile, then
00083          pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);  // you may need to add -D_GNU_SOURCE to your
00084          pthread_mutex_init(&_locker, &mutexattr);                        // Linux Makefile to enable it properly.
00085 # endif
00086       }
00087 #endif
00088    }
00089  
00093    ~Mutex() {Cleanup();}
00094 
00102    status_t Lock() const
00103    {
00104 #ifdef MUSCLE_SINGLE_THREAD_ONLY
00105       return B_NO_ERROR;
00106 #else
00107       if (_isEnabled == false) return B_NO_ERROR;
00108 # if defined(MUSCLE_USE_PTHREADS)
00109       return (pthread_mutex_lock(&_locker) == 0) ? B_NO_ERROR : B_ERROR;
00110 # elif defined(MUSCLE_PREFER_WIN32_OVER_QT)
00111       return ((_locker)&&(WaitForSingleObject(_locker, INFINITE) == WAIT_FAILED)) ? B_ERROR : B_NO_ERROR;
00112 # elif defined(MUSCLE_QT_HAS_THREADS)
00113       _locker.lock();
00114       return B_NO_ERROR;
00115 # elif defined(__BEOS__)
00116       return _locker.Lock() ? B_NO_ERROR : B_ERROR;
00117 # elif defined(__ATHEOS__)
00118       return _locker.Lock() ? B_ERROR : B_NO_ERROR;  // Is this correct?  Kurt's documentation sucks
00119 # endif
00120 #endif
00121    }
00122 
00128    status_t Unlock() const
00129    {
00130 #ifdef MUSCLE_SINGLE_THREAD_ONLY
00131       return B_NO_ERROR;
00132 #else
00133       if (_isEnabled == false) return B_NO_ERROR;
00134 # if defined(MUSCLE_USE_PTHREADS)
00135       return (pthread_mutex_unlock(&_locker) == 0) ? B_NO_ERROR : B_ERROR;
00136 # elif defined(MUSCLE_PREFER_WIN32_OVER_QT)
00137       return ((_locker)&&(ReleaseMutex(_locker))) ? B_NO_ERROR : B_ERROR;
00138 # elif defined(MUSCLE_QT_HAS_THREADS)
00139       _locker.unlock();
00140       return B_NO_ERROR;
00141 # elif defined(__BEOS__)
00142       _locker.Unlock();
00143       return B_NO_ERROR;
00144 # elif defined(__ATHEOS__)
00145       return _locker.Unlock() ? B_ERROR : B_NO_ERROR;  // Is this correct?  Kurt's documentation sucks
00146 # endif
00147 #endif
00148    }
00149 
00151    void Neuter() {Cleanup();}
00152 
00153 private:
00154    void Cleanup()
00155    {
00156 #ifndef MUSCLE_SINGLE_THREAD_ONLY
00157       if (_isEnabled)
00158       {
00159 # if defined(MUSCLE_USE_PTHREADS)
00160          pthread_mutex_destroy(&_locker);
00161 # elif defined(MUSCLE_PREFER_WIN32_OVER_QT)
00162          CloseHandle(_locker);
00163 # elif defined(MUSCLE_QT_HAS_THREADS)
00164          // do nothing
00165 # endif
00166 
00167          _isEnabled = false;
00168       }
00169 #endif
00170    }
00171 
00172 #ifndef MUSCLE_SINGLE_THREAD_ONLY
00173    bool _isEnabled;  // if false, this Mutex is a no-op
00174 # if defined(MUSCLE_USE_PTHREADS)
00175    mutable pthread_mutex_t _locker;
00176 # elif defined(MUSCLE_PREFER_WIN32_OVER_QT)
00177    mutable ::HANDLE _locker;
00178 # elif defined(MUSCLE_QT_HAS_THREADS)
00179    mutable QMutex _locker;
00180 # elif defined(__BEOS__)
00181    mutable BLocker _locker;
00182 # elif defined(__ATHEOS__)
00183    mutable os::Locker _locker;
00184 # endif
00185 #endif
00186 };
00187 
00189 class MutexGuard
00190 {
00191 public:
00195    MutexGuard(Mutex & m) : _mutex(m)
00196    {
00197       if (_mutex.Lock() == B_NO_ERROR) _isMutexLocked = true;
00198       else
00199       {
00200          _isMutexLocked = false;
00201          printf("MutexGuard %p:  couldn't lock mutex %p!\n", this, &_mutex);
00202       }
00203    }
00204 
00206    ~MutexGuard()
00207    {
00208       if ((_isMutexLocked)&&(_mutex.Unlock() != B_NO_ERROR)) printf("MutexGuard %p:  couldn't unlock mutex %p!\n", this, &_mutex);
00209    }
00210 
00212    bool IsMutexLocked() const {return _isMutexLocked;}
00213 
00214 private:
00215    MutexGuard(const Mutex &);  // copy ctor, deliberately inaccessible
00216 
00217    Mutex & _mutex;
00218    bool _isMutexLocked;
00219 };
00220 
00221 #ifdef MUSCLE_USE_PTHREADS
00222 // These calls are useful in conjunction with tests/deadlockfinder.cpp, for tracking
00223 // down potential synchronization deadlocks in multithreaded code.  Note that they only
00224 // work when using a pThreads environment, however.
00225 #define PLOCK(  name,pointer) _PLOCKimp(  name,pointer,__FILE__,__LINE__)
00226 #define PUNLOCK(name,pointer) _PUNLOCKimp(name,pointer,__FILE__,__LINE__)
00227 
00228 // don't call these directly -- call the PLOCK() and PUNLOCK() macros instead!
00229 static inline void _PLOCKimp(const char * n, const void * p, const char * f, int ln) {printf(INT32_FORMAT_SPEC" plock p=%p [%s] %s:%i\n", (int32)pthread_self(), p, n, f, ln);}
00230 static inline void _PUNLOCKimp(const char * n, const void * p, const char * f, int ln) {printf(INT32_FORMAT_SPEC" punlock p=%p [%s] %s:%i\n", (int32)pthread_self(), p, n, f, ln);}
00231 #endif
00232 
00233 END_NAMESPACE(muscle);
00234 
00235 #endif

Generated on Thu Jun 5 17:47:53 2008 for MUSCLE by  doxygen 1.5.1