Changeset View
Changeset View
Standalone View
Standalone View
src/sync.h
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
// THE ACTUAL IMPLEMENTATION // | // THE ACTUAL IMPLEMENTATION // | ||||
// // | // // | ||||
/////////////////////////////// | /////////////////////////////// | ||||
#ifdef DEBUG_LOCKORDER | #ifdef DEBUG_LOCKORDER | ||||
void EnterCritical(const char *pszName, const char *pszFile, int nLine, | void EnterCritical(const char *pszName, const char *pszFile, int nLine, | ||||
void *cs, bool fTry = false); | void *cs, bool fTry = false); | ||||
void LeaveCritical(); | void LeaveCritical(); | ||||
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, | |||||
const char *file, int line); | |||||
std::string LocksHeld(); | std::string LocksHeld(); | ||||
void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, | void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, | ||||
void *cs) ASSERT_EXCLUSIVE_LOCK(cs); | void *cs) ASSERT_EXCLUSIVE_LOCK(cs); | ||||
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, | void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, | ||||
int nLine, void *cs); | int nLine, void *cs); | ||||
void DeleteLock(void *cs); | void DeleteLock(void *cs); | ||||
/** | /** | ||||
* Call abort() if a potential lock order deadlock bug is detected, instead of | * Call abort() if a potential lock order deadlock bug is detected, instead of | ||||
* just logging information and throwing a logic_error. Defaults to true, and | * just logging information and throwing a logic_error. Defaults to true, and | ||||
* set to false in DEBUG_LOCKORDER unit tests. | * set to false in DEBUG_LOCKORDER unit tests. | ||||
*/ | */ | ||||
extern bool g_debug_lockorder_abort; | extern bool g_debug_lockorder_abort; | ||||
#else | #else | ||||
static inline void EnterCritical(const char *pszName, const char *pszFile, | static inline void EnterCritical(const char *pszName, const char *pszFile, | ||||
int nLine, void *cs, bool fTry = false) {} | int nLine, void *cs, bool fTry = false) {} | ||||
static inline void LeaveCritical() {} | static inline void LeaveCritical() {} | ||||
static inline void CheckLastCritical(void *cs, std::string &lockname, | |||||
const char *guardname, const char *file, | |||||
int line) {} | |||||
static inline void AssertLockHeldInternal(const char *pszName, | static inline void AssertLockHeldInternal(const char *pszName, | ||||
const char *pszFile, int nLine, | const char *pszFile, int nLine, | ||||
void *cs) ASSERT_EXCLUSIVE_LOCK(cs) {} | void *cs) ASSERT_EXCLUSIVE_LOCK(cs) {} | ||||
static inline void AssertLockNotHeldInternal(const char *pszName, | static inline void AssertLockNotHeldInternal(const char *pszName, | ||||
const char *pszFile, int nLine, | const char *pszFile, int nLine, | ||||
void *cs) {} | void *cs) {} | ||||
static inline void DeleteLock(void *cs) {} | static inline void DeleteLock(void *cs) {} | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | public: | ||||
~UniqueLock() UNLOCK_FUNCTION() { | ~UniqueLock() UNLOCK_FUNCTION() { | ||||
if (Base::owns_lock()) { | if (Base::owns_lock()) { | ||||
LeaveCritical(); | LeaveCritical(); | ||||
} | } | ||||
} | } | ||||
operator bool() { return Base::owns_lock(); } | operator bool() { return Base::owns_lock(); } | ||||
protected: | |||||
// needed for reverse_lock | |||||
UniqueLock() {} | |||||
public: | |||||
/** | |||||
* An RAII-style reverse lock. Unlocks on construction and locks on | |||||
* destruction. | |||||
*/ | |||||
class reverse_lock { | |||||
public: | |||||
explicit reverse_lock(UniqueLock &_lock, const char *_guardname, | |||||
const char *_file, int _line) | |||||
: lock(_lock), file(_file), line(_line) { | |||||
CheckLastCritical((void *)lock.mutex(), lockname, _guardname, _file, | |||||
_line); | |||||
lock.unlock(); | |||||
LeaveCritical(); | |||||
lock.swap(templock); | |||||
} | |||||
~reverse_lock() { | |||||
templock.swap(lock); | |||||
EnterCritical(lockname.c_str(), file.c_str(), line, | |||||
(void *)lock.mutex()); | |||||
lock.lock(); | |||||
} | |||||
private: | |||||
reverse_lock(reverse_lock const &); | |||||
reverse_lock &operator=(reverse_lock const &); | |||||
UniqueLock &lock; | |||||
UniqueLock templock; | |||||
std::string lockname; | |||||
const std::string file; | |||||
const int line; | |||||
}; | |||||
friend class reverse_lock; | |||||
}; | }; | ||||
#define REVERSE_LOCK(g) \ | |||||
decltype(g)::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, \ | |||||
__LINE__) | |||||
template <typename MutexArg> | template <typename MutexArg> | ||||
using DebugLock = UniqueLock<typename std::remove_reference< | using DebugLock = UniqueLock<typename std::remove_reference< | ||||
typename std::remove_pointer<MutexArg>::type>::type>; | typename std::remove_pointer<MutexArg>::type>::type>; | ||||
#define LOCK(cs) \ | #define LOCK(cs) \ | ||||
DebugLock<decltype(cs)> PASTE2(criticalblock, \ | DebugLock<decltype(cs)> PASTE2(criticalblock, \ | ||||
__COUNTER__)(cs, #cs, __FILE__, __LINE__) | __COUNTER__)(cs, #cs, __FILE__, __LINE__) | ||||
#define LOCK2(cs1, cs2) \ | #define LOCK2(cs1, cs2) \ | ||||
▲ Show 20 Lines • Show All 132 Lines • Show Last 20 Lines |