diff --git a/src/sync.h b/src/sync.h --- a/src/sync.h +++ b/src/sync.h @@ -67,6 +67,8 @@ std::string LocksHeld(); void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs); +void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, + int nLine, void *cs); void DeleteLock(void *cs); #else static inline void EnterCritical(const char *pszName, const char *pszFile, @@ -75,9 +77,14 @@ static inline void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs) {} +static inline void AssertLockNotHeldInternal(const char *pszName, + const char *pszFile, int nLine, + void *cs) {} static inline void DeleteLock(void *cs) {} #endif #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) +#define AssertLockNotHeld(cs) \ + AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) /** * Wrapped mutex: supports recursive locking, but no waiting diff --git a/src/sync.cpp b/src/sync.cpp --- a/src/sync.cpp +++ b/src/sync.cpp @@ -158,6 +158,18 @@ abort(); } +void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, + int nLine, void *cs) { + for (const std::pair &i : *lockstack) { + if (i.first == cs) { + fprintf(stderr, + "Assertion failed: lock %s held in %s:%i; locks held:\n%s", + pszName, pszFile, nLine, LocksHeld().c_str()); + abort(); + } + } +} + void DeleteLock(void *cs) { if (!lockdata.available) { // We're already shutting down.