diff --git a/src/sync.h b/src/sync.h --- a/src/sync.h +++ b/src/sync.h @@ -270,16 +270,52 @@ using DebugLock = UniqueLock::type>::type>; +// When locking a Mutex, require negative capability to ensure the lock +// is not already held +inline Mutex &MaybeCheckNotHeld(Mutex &cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) + LOCK_RETURNED(cs) { + return cs; +} +inline Mutex *MaybeCheckNotHeld(Mutex *cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) + LOCK_RETURNED(cs) { + return cs; +} + +// When locking a GlobalMutex, just check it is not locked in the surrounding +// scope +inline GlobalMutex &MaybeCheckNotHeld(GlobalMutex &cs) LOCKS_EXCLUDED(cs) + LOCK_RETURNED(cs) { + return cs; +} +inline GlobalMutex *MaybeCheckNotHeld(GlobalMutex *cs) LOCKS_EXCLUDED(cs) + LOCK_RETURNED(cs) { + return cs; +} + +// When locking a RecursiveMutex, it's okay to already hold the lock +// but check that it is not known to be locked in the surrounding scope anyway +inline RecursiveMutex &MaybeCheckNotHeld(RecursiveMutex &cs) LOCKS_EXCLUDED(cs) + LOCK_RETURNED(cs) { + return cs; +} +inline RecursiveMutex *MaybeCheckNotHeld(RecursiveMutex *cs) LOCKS_EXCLUDED(cs) + LOCK_RETURNED(cs) { + return cs; +} + #define LOCK(cs) \ - DebugLock UNIQUE_NAME(criticalblock)(cs, #cs, __FILE__, \ - __LINE__) + DebugLock UNIQUE_NAME(criticalblock)( \ + MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) \ - DebugLock criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ - DebugLock criticalblock2(cs2, #cs2, __FILE__, __LINE__); + DebugLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, \ + __FILE__, __LINE__); \ + DebugLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, \ + __FILE__, __LINE__); #define TRY_LOCK(cs, name) \ - DebugLock name(cs, #cs, __FILE__, __LINE__, true) + DebugLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, \ + __LINE__, true) #define WAIT_LOCK(cs, name) \ - DebugLock name(cs, #cs, __FILE__, __LINE__) + DebugLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) #define ENTER_CRITICAL_SECTION(cs) \ { \ @@ -319,10 +355,10 @@ //! The above is detectable at compile-time with the -Wreturn-local-addr flag in //! gcc and the -Wreturn-stack-address flag in clang, both enabled by default. #define WITH_LOCK(cs, code) \ - [&]() -> decltype(auto) { \ + (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { \ LOCK(cs); \ code; \ - }() + }()) class CSemaphore { private: