You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
4.8 KiB
212 lines
4.8 KiB
// 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 <boost/thread/mutex.hpp> |
|
#include <boost/thread/recursive_mutex.hpp> |
|
#include <boost/thread/locks.hpp> |
|
#include <boost/thread/condition_variable.hpp> |
|
|
|
|
|
|
|
|
|
/** 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::interprocess::scoped_lock */ |
|
template<typename Mutex> |
|
class CMutexLock |
|
{ |
|
private: |
|
boost::unique_lock<Mutex> 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<Mutex> &GetLock() |
|
{ |
|
return lock; |
|
} |
|
}; |
|
|
|
typedef CMutexLock<CCriticalSection> 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<boost::mutex> lock(mutex); |
|
while (value < 1) { |
|
condition.wait(lock); |
|
} |
|
value--; |
|
} |
|
|
|
bool try_wait() { |
|
boost::unique_lock<boost::mutex> lock(mutex); |
|
if (value < 1) |
|
return false; |
|
value--; |
|
return true; |
|
} |
|
|
|
void post() { |
|
{ |
|
boost::unique_lock<boost::mutex> 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 |
|
|
|
|