@@ -244,12 +244,26 @@ class SCOPED_LOCKABLE UniqueLock : public Base
244244template<typename MutexArg>
245245using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
246246
247- #define LOCK (cs ) DebugLock<decltype (cs)> UNIQUE_NAME (criticalblock)(cs, #cs, __FILE__, __LINE__)
247+ // When locking a Mutex, require negative capability to ensure the lock
248+ // is not already held
249+ inline Mutex& MaybeCheckNotHeld (Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
250+ inline Mutex* MaybeCheckNotHeld (Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
251+
252+ // When locking a GlobalMutex, just check it is not locked in the surrounding scope
253+ inline GlobalMutex& MaybeCheckNotHeld (GlobalMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
254+ inline GlobalMutex* MaybeCheckNotHeld (GlobalMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
255+
256+ // When locking a RecursiveMutex, it's okay to already hold the lock
257+ // but check that it is not known to be locked in the surrounding scope anyway
258+ inline RecursiveMutex& MaybeCheckNotHeld (RecursiveMutex& cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
259+ inline RecursiveMutex* MaybeCheckNotHeld (RecursiveMutex* cs) LOCKS_EXCLUDED(cs) LOCK_RETURNED(cs) { return cs; }
260+
261+ #define LOCK (cs ) DebugLock<decltype (cs)> UNIQUE_NAME (criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
248262#define LOCK2 (cs1, cs2 ) \
249- DebugLock<decltype (cs1)> criticalblock1 (cs1, #cs1, __FILE__, __LINE__); \
250- DebugLock<decltype (cs2)> criticalblock2 (cs2, #cs2, __FILE__, __LINE__);
251- #define TRY_LOCK (cs, name ) DebugLock<decltype (cs)> name (cs , #cs, __FILE__, __LINE__, true )
252- #define WAIT_LOCK (cs, name ) DebugLock<decltype (cs)> name (cs , #cs, __FILE__, __LINE__)
263+ DebugLock<decltype (cs1)> criticalblock1 (MaybeCheckNotHeld( cs1) , #cs1, __FILE__, __LINE__); \
264+ DebugLock<decltype (cs2)> criticalblock2 (MaybeCheckNotHeld( cs2) , #cs2, __FILE__, __LINE__);
265+ #define TRY_LOCK (cs, name ) DebugLock<decltype (cs)> name (MaybeCheckNotHeld(cs) , #cs, __FILE__, __LINE__, true )
266+ #define WAIT_LOCK (cs, name ) DebugLock<decltype (cs)> name (MaybeCheckNotHeld(cs) , #cs, __FILE__, __LINE__)
253267
254268#define ENTER_CRITICAL_SECTION (cs ) \
255269 { \
@@ -288,7 +302,7 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove
288302// !
289303// ! The above is detectable at compile-time with the -Wreturn-local-addr flag in
290304// ! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.
291- #define WITH_LOCK (cs, code ) [&]() -> decltype (auto ) { LOCK (cs); code; }()
305+ #define WITH_LOCK (cs, code ) (MaybeCheckNotHeld(cs), [&]() -> decltype (auto ) { LOCK (cs); code; }() )
292306
293307class CSemaphore
294308{
0 commit comments