What about checking, inside LOCK(), whether the mutex being locked is instance of Mutex (and not RecursiveMutex) and only asserting that we don't own it in that case:
diff --git i/src/sync.h w/src/sync.h
index 60e5a87ae..36c348898 100644
--- i/src/sync.h
+++ w/src/sync.h
@@ -10,12 +10,13 @@
#include <util/macros.h>
#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
+#include <type_traits>
////////////////////////////////////////////////
// //
// THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
// //
////////////////////////////////////////////////
@@ -145,12 +146,15 @@ private:
return Base::owns_lock();
}
public:
UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
{
+ if (std::is_base_of<::Mutex, Mutex>::value) {
+ AssertLockNotHeldInternal(pszName, pszFile, nLine, &mutexIn);
+ }
if (fTry)
TryEnter(pszName, pszFile, nLine);
else
Enter(pszName, pszFile, nLine);
}
diff --git i/src/test/sync_tests.cpp w/src/test/sync_tests.cpp
index 5c6c2ee38..a66d55519 100644
--- i/src/test/sync_tests.cpp
+++ w/src/test/sync_tests.cpp
@@ -46,7 +46,27 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
#ifdef DEBUG_LOCKORDER
g_debug_lockorder_abort = prev;
#endif
}
+template <typename M>
+void lock(M& m)
+{
+ LOCK(m);
+}
+
+BOOST_AUTO_TEST_CASE(double_lock_mutex)
+{
+ Mutex m;
+ LOCK(m);
+ lock(m);
+}
+
+BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
+{
+ RecursiveMutex m;
+ LOCK(m);
+ lock(m);
+}
+
BOOST_AUTO_TEST_SUITE_END()
It works - the test double_lock_mutex fails because of the newly added check while the double_lock_recursive_mutex succeeds.
The double colon in ::Mutex is required because the class template type template <typename Mutex, ...> UniqueLock ... shadows the global typedef ... Mutex;.