// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SYNC_H #define BITCOIN_SYNC_H #include #include #include #include /** Wrapped boost mutex: supports recursive locking, but no waiting */ typedef boost::recursive_mutex CCriticalSection; /** Wrapped boost mutex: supports waiting but not recursive locking */ typedef boost::mutex CWaitableCriticalSection; #ifdef DEBUG_LOCKORDER void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void LeaveCritical(); #else void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline LeaveCritical() {} #endif #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char* pszName, const char* pszFile, int nLine); #endif /** Wrapper around boost::unique_lock */ template class CMutexLock { private: boost::unique_lock lock; public: void Enter(const char* pszName, const char* pszFile, int nLine) { if (!lock.owns_lock()) { EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); #ifdef DEBUG_LOCKCONTENTION if (!lock.try_lock()) { PrintLockContention(pszName, pszFile, nLine); #endif lock.lock(); #ifdef DEBUG_LOCKCONTENTION } #endif } } void Leave() { if (lock.owns_lock()) { lock.unlock(); LeaveCritical(); } } bool TryEnter(const char* pszName, const char* pszFile, int nLine) { if (!lock.owns_lock()) { EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); lock.try_lock(); if (!lock.owns_lock()) LeaveCritical(); } return lock.owns_lock(); } CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } ~CMutexLock() { if (lock.owns_lock()) LeaveCritical(); } operator bool() { return lock.owns_lock(); } boost::unique_lock &GetLock() { return lock; } }; typedef CMutexLock CCriticalBlock; #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__) #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) #define ENTER_CRITICAL_SECTION(cs) \ { \ EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \ (cs).lock(); \ } #define LEAVE_CRITICAL_SECTION(cs) \ { \ (cs).unlock(); \ LeaveCritical(); \ } class CSemaphore { private: boost::condition_variable condition; boost::mutex mutex; int value; public: CSemaphore(int init) : value(init) {} void wait() { boost::unique_lock lock(mutex); while (value < 1) { condition.wait(lock); } value--; } bool try_wait() { boost::unique_lock lock(mutex); if (value < 1) return false; value--; return true; } void post() { { boost::unique_lock lock(mutex); value++; } condition.notify_one(); } }; /** RAII-style semaphore lock */ class CSemaphoreGrant { private: CSemaphore *sem; bool fHaveGrant; public: void Acquire() { if (fHaveGrant) return; sem->wait(); fHaveGrant = true; } void Release() { if (!fHaveGrant) return; sem->post(); fHaveGrant = false; } bool TryAcquire() { if (!fHaveGrant && sem->try_wait()) fHaveGrant = true; return fHaveGrant; } void MoveTo(CSemaphoreGrant &grant) { grant.Release(); grant.sem = sem; grant.fHaveGrant = fHaveGrant; sem = NULL; fHaveGrant = false; } CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {} CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) { if (fTry) TryAcquire(); else Acquire(); } ~CSemaphoreGrant() { Release(); } operator bool() { return fHaveGrant; } }; #endif