// 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 /** Wrapped boost mutex: supports recursive locking, but no waiting */ typedef std::recursive_mutex CCriticalSection; /** Wrapped boost mutex: supports waiting but not recursive locking */ typedef std::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 std::unique_lock */ template class CMutexLock { private: std::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); if (lock.try_lock()) return true; LeaveCritical(); } return false; } CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } ~CMutexLock() { if (lock.owns_lock()) LeaveCritical(); } operator bool() const { return lock.owns_lock(); } std::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: std::condition_variable condition; std::mutex mutex; int value; public: explicit CSemaphore(int init) : value(init) {} void wait() { //std::unique_lock lock(mutex); //while (value < 1) { // condition.wait(lock); //} //value--; std::unique_lock lock(mutex); condition.wait(lock, [&]() { return value >= 1; }); value--; } bool try_wait() { std::unique_lock lock(mutex); if (value < 1) return false; value--; return true; } void post() { { std::unique_lock lock(mutex); value++; } condition.notify_one(); } }; /** RAII-style semaphore lock */ class CSemaphoreGrant { private: CSemaphore *sem; bool fHaveGrant; public: void Acquire() { if (!fHaveGrant) { sem->wait(); fHaveGrant = true; } } void Release() { if (fHaveGrant) { 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 = nullptr; fHaveGrant = false; } CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {} CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) { if (fTry) TryAcquire(); else Acquire(); } ~CSemaphoreGrant() { Release(); } operator bool() const { return fHaveGrant; } }; #endif