/* Copyright (C) 2009 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ /* ThreadUtil.h - Thread Utility Functions --Overview-- Contains three classes: CMutex, CRWLock and CLocker. CMutex is a Mutual Exclusion lock that can be locked and unlocked. The Lock function waits for the current lock holder (if any) to release the lock and then acquires it. CRWLock is a lock where any number of readers *or* one writer can hold the lock. CLocker is a generic wrapper class that can wrap any data class with any locker class. --Example-- CMutex usage: CMutex protectData; void function() { protectData.Lock(); .. do stuff with data .. protectData.Unlock(); } CLocker usage: class CDataClass {}; CLocker instance; void function() { instance.Lock(); .. do stuff with instance .. instance.Unlock(); } CLocker usage 2: class CDataClass {}; class CCustomLockerClass { void MyOwnLock(); void MyOwnUnlock(); }; CLocker instance; void function() { instance.MyOwnLock(); .. do stuff with instance .. instance.MyOwnUnlock(); } --More Info-- */ #ifndef _ThreadUtil_h #define _ThreadUtil_h //-------------------------------------------------------- // Includes / Compiler directives //-------------------------------------------------------- #include "lib/posix/posix_pthread.h" #ifdef DEBUG_LOCKS #define LOCK_MUTEX(_mutex) STMT( \ printf("pthread_mutex_lock: 1 %p [pid:%d]\n", _mutex, pthread_self()); \ pthread_mutex_lock(_mutex); \ printf("pthread_mutex_lock: 2 %p [pid:%d]\n", _mutex, pthread_self()) \ ) #define UNLOCK_MUTEX(_mutex) STMT( \ pthread_mutex_unlock(_mutex); \ printf("pthread_mutex_unlock: %p [pid:%d]\n", _mutex, pthread_self()) \ ) #else #define LOCK_MUTEX(_mutex) pthread_mutex_lock(_mutex) #define UNLOCK_MUTEX(_mutex) pthread_mutex_unlock(_mutex) #endif //------------------------------------------------- // Types //------------------------------------------------- //------------------------------------------------- // Declarations //------------------------------------------------- /** * A Mutual Exclusion lock. */ class CMutex { public: inline CMutex() { pthread_mutex_init(&m_Mutex, NULL); } inline ~CMutex() { if (pthread_mutex_destroy(&m_Mutex) != 0) { Unlock(); pthread_mutex_destroy(&m_Mutex); } } /** * Atomically wait for the mutex to become unlocked, then lock it. */ inline void Lock() { LOCK_MUTEX(&m_Mutex); } /** * Unlock the mutex. */ inline void Unlock() { UNLOCK_MUTEX(&m_Mutex); } pthread_mutex_t m_Mutex; }; // CScopeLock // ---------------------------------------------------------------------| Class // Locks a CMutex over the objects lifetime class CScopeLock { NONCOPYABLE(CScopeLock); public: inline CScopeLock(pthread_mutex_t &mutex): m_Mutex(mutex) { LOCK_MUTEX(&m_Mutex); } inline CScopeLock(CMutex &mutex): m_Mutex(mutex.m_Mutex) { LOCK_MUTEX(&m_Mutex); } inline ~CScopeLock() { UNLOCK_MUTEX(&m_Mutex); } private: pthread_mutex_t &m_Mutex; }; // CLocker // ---------------------------------------------------------------------| Class // This will not give access to the wrapped class constructors directly, // to use them you have to do CLocker(CWrappedClass(args)) template struct CLocker: public CMutex, public _T { public: inline CLocker() {} /* GCC doesn't take these... I don't understand what the problem is! // Simon inline CLocker(const _T &arg): _T(arg) {} inline CLocker(_T &arg): _T(arg) {}*/ }; #endif