@@ -62,6 +62,19 @@ void TestDoubleLock(bool should_throw)
6262 g_debug_lockorder_abort = prev;
6363}
6464#endif /* DEBUG_LOCKORDER */
65+
66+ template <typename MutexType>
67+ void TestInconsistentLockOrderDetected (MutexType& mutex1, MutexType& mutex2) NO_THREAD_SAFETY_ANALYSIS
68+ {
69+ ENTER_CRITICAL_SECTION (mutex1);
70+ ENTER_CRITICAL_SECTION (mutex2);
71+ #ifdef DEBUG_LOCKORDER
72+ BOOST_CHECK_EXCEPTION (LEAVE_CRITICAL_SECTION (mutex1), std::logic_error, HasReason (" mutex1 was not most recent critical section locked" ));
73+ #endif // DEBUG_LOCKORDER
74+ LEAVE_CRITICAL_SECTION (mutex2);
75+ LEAVE_CRITICAL_SECTION (mutex1);
76+ BOOST_CHECK (LockStackEmpty ());
77+ }
6578} // namespace
6679
6780BOOST_FIXTURE_TEST_SUITE (sync_tests, BasicTestingSetup)
@@ -108,4 +121,28 @@ BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
108121}
109122#endif /* DEBUG_LOCKORDER */
110123
124+ BOOST_AUTO_TEST_CASE (inconsistent_lock_order_detected)
125+ {
126+ #ifdef DEBUG_LOCKORDER
127+ bool prev = g_debug_lockorder_abort;
128+ g_debug_lockorder_abort = false ;
129+ #endif // DEBUG_LOCKORDER
130+
131+ RecursiveMutex rmutex1, rmutex2;
132+ TestInconsistentLockOrderDetected (rmutex1, rmutex2);
133+ // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical)
134+ // the lock tracking data must not have been broken by exception.
135+ TestInconsistentLockOrderDetected (rmutex1, rmutex2);
136+
137+ Mutex mutex1, mutex2;
138+ TestInconsistentLockOrderDetected (mutex1, mutex2);
139+ // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical)
140+ // the lock tracking data must not have been broken by exception.
141+ TestInconsistentLockOrderDetected (mutex1, mutex2);
142+
143+ #ifdef DEBUG_LOCKORDER
144+ g_debug_lockorder_abort = prev;
145+ #endif // DEBUG_LOCKORDER
146+ }
147+
111148BOOST_AUTO_TEST_SUITE_END ()
0 commit comments