00001
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>
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
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
00047
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
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);
00083 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
00084 pthread_mutex_init(&_locker, &mutexattr);
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;
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;
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
00165 # endif
00166
00167 _isEnabled = false;
00168 }
00169 #endif
00170 }
00171
00172 #ifndef MUSCLE_SINGLE_THREAD_ONLY
00173 bool _isEnabled;
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 &);
00216
00217 Mutex & _mutex;
00218 bool _isMutexLocked;
00219 };
00220
00221 #ifdef MUSCLE_USE_PTHREADS
00222
00223
00224
00225 #define PLOCK( name,pointer) _PLOCKimp( name,pointer,__FILE__,__LINE__)
00226 #define PUNLOCK(name,pointer) _PUNLOCKimp(name,pointer,__FILE__,__LINE__)
00227
00228
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