cannam@3: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@3: cannam@3: /* cannam@3: Basic cross-platform mutex abstraction class. cannam@3: This file copyright 2007 Chris Cannam. cannam@3: */ cannam@3: cannam@3: #include "Mutex.h" cannam@3: #include cannam@3: cannam@3: #ifndef _WIN32 cannam@3: #include cannam@3: #include cannam@3: #endif cannam@3: cannam@3: using std::cerr; cannam@3: using std::endl; cannam@3: using std::string; cannam@3: cannam@3: #ifdef _WIN32 cannam@3: cannam@3: Mutex::Mutex() cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: : cannam@3: m_lockedBy(-1) cannam@3: #endif cannam@3: { cannam@3: m_mutex = CreateMutex(NULL, FALSE, NULL); cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: } cannam@3: cannam@3: Mutex::~Mutex() cannam@3: { cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: CloseHandle(m_mutex); cannam@3: } cannam@3: cannam@3: void cannam@3: Mutex::lock() cannam@3: { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: DWORD tid = GetCurrentThreadId(); cannam@3: if (m_lockedBy == tid) { cannam@3: cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; cannam@3: } cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: WaitForSingleObject(m_mutex, INFINITE); cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: m_lockedBy = tid; cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: } cannam@3: cannam@3: void cannam@3: Mutex::unlock() cannam@3: { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: DWORD tid = GetCurrentThreadId(); cannam@3: if (m_lockedBy != tid) { cannam@3: cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl; cannam@3: return; cannam@3: } cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: m_lockedBy = -1; cannam@3: #endif cannam@3: ReleaseMutex(m_mutex); cannam@3: } cannam@3: cannam@3: bool cannam@3: Mutex::trylock() cannam@3: { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: DWORD tid = GetCurrentThreadId(); cannam@3: #endif cannam@3: DWORD result = WaitForSingleObject(m_mutex, 0); cannam@3: if (result == WAIT_TIMEOUT || result == WAIT_FAILED) { cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl; cannam@3: #endif cannam@3: return false; cannam@3: } else { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: m_lockedBy = tid; cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; cannam@3: #endif cannam@3: return true; cannam@3: } cannam@3: } cannam@3: cannam@3: #else /* !_WIN32 */ cannam@3: cannam@3: Mutex::Mutex() cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: : cannam@3: m_lockedBy(0), cannam@3: m_locked(false) cannam@3: #endif cannam@3: { cannam@3: pthread_mutex_init(&m_mutex, 0); cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: } cannam@3: cannam@3: Mutex::~Mutex() cannam@3: { cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: pthread_mutex_destroy(&m_mutex); cannam@3: } cannam@3: cannam@3: void cannam@3: Mutex::lock() cannam@3: { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: pthread_t tid = pthread_self(); cannam@3: if (m_locked && m_lockedBy == tid) { cannam@3: cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; cannam@3: } cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: pthread_mutex_lock(&m_mutex); cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: m_lockedBy = tid; cannam@3: m_locked = true; cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: } cannam@3: cannam@3: void cannam@3: Mutex::unlock() cannam@3: { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: pthread_t tid = pthread_self(); cannam@3: if (!m_locked) { cannam@3: cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl; cannam@3: return; cannam@3: } else if (m_lockedBy != tid) { cannam@3: cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl; cannam@3: return; cannam@3: } cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl; cannam@3: #endif cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: m_locked = false; cannam@3: #endif cannam@3: pthread_mutex_unlock(&m_mutex); cannam@3: } cannam@3: cannam@3: bool cannam@3: Mutex::trylock() cannam@3: { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: pthread_t tid = pthread_self(); cannam@3: #endif cannam@3: if (pthread_mutex_trylock(&m_mutex)) { cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl; cannam@3: #endif cannam@3: return false; cannam@3: } else { cannam@3: #ifndef NO_THREAD_CHECKS cannam@3: m_lockedBy = tid; cannam@3: m_locked = true; cannam@3: #endif cannam@3: #ifdef DEBUG_MUTEX cannam@3: cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; cannam@3: #endif cannam@3: return true; cannam@3: } cannam@3: } cannam@3: cannam@3: #endif cannam@5: cannam@5: MutexLocker::MutexLocker(Mutex *mutex) : cannam@5: m_mutex(mutex) cannam@5: { cannam@5: if (m_mutex) { cannam@5: m_mutex->lock(); cannam@5: } cannam@5: } cannam@5: cannam@5: MutexLocker::~MutexLocker() cannam@5: { cannam@5: if (m_mutex) { cannam@5: m_mutex->unlock(); cannam@5: } cannam@5: } cannam@5: