Bitcoin Core 32.1.0
P2P Digital Currency
Loading...
Searching...
No Matches
sync_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2012-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <sync.h>
6#include <test/util/common.h>
7
8#include <boost/test/unit_test.hpp>
9
10#include <mutex>
11#include <stdexcept>
12
13namespace {
14template <typename MutexType>
15void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2)
16{
17 {
18 LOCK2(mutex1, mutex2);
19 }
21 {
22#ifdef DEBUG_LOCKORDER
23 BOOST_CHECK_EXCEPTION(LOCK2(mutex2, mutex1), std::logic_error, HasReason{"potential deadlock detected: mutex1 -> mutex2 -> mutex1"});
24#else
25 LOCK2(mutex2, mutex1);
26#endif
27 }
29}
30
31#ifdef DEBUG_LOCKORDER
32template <typename MutexType>
33void TestDoubleLock2(MutexType& m)
34{
35 LOCK(m);
36}
37
38template <typename MutexType>
39void TestDoubleLock(bool should_throw)
40{
41 const bool prev = g_debug_lockorder_abort;
42 g_debug_lockorder_abort = false;
43
44 MutexType m;
45 {
46 LOCK(m);
47 if (should_throw) {
48 BOOST_CHECK_EXCEPTION(TestDoubleLock2(m), std::logic_error,
49 HasReason("double lock detected"));
50 } else {
51 BOOST_CHECK_NO_THROW(TestDoubleLock2(m));
52 }
53 }
55
56 g_debug_lockorder_abort = prev;
57}
58#endif /* DEBUG_LOCKORDER */
59
60template <typename MutexType>
61void TestInconsistentLockOrderDetected(MutexType& mutex1, MutexType& mutex2)
62{
63 {
64 WAIT_LOCK(mutex1, lock1);
65 LOCK(mutex2);
66#ifdef DEBUG_LOCKORDER
67 BOOST_CHECK_EXCEPTION(REVERSE_LOCK(lock1, mutex1), std::logic_error, HasReason("mutex1 was not most recent critical section locked"));
68#endif // DEBUG_LOCKORDER
69 }
71}
72} // namespace
73
74BOOST_AUTO_TEST_SUITE(sync_tests)
75
76BOOST_AUTO_TEST_CASE(potential_deadlock_detected)
77{
78 #ifdef DEBUG_LOCKORDER
79 bool prev = g_debug_lockorder_abort;
80 g_debug_lockorder_abort = false;
81 #endif
82
83 RecursiveMutex rmutex1, rmutex2;
84 TestPotentialDeadLockDetected(rmutex1, rmutex2);
85 // The second test ensures that lock tracking data have not been broken by exception.
86 TestPotentialDeadLockDetected(rmutex1, rmutex2);
87
88 Mutex mutex1, mutex2;
89 TestPotentialDeadLockDetected(mutex1, mutex2);
90 // The second test ensures that lock tracking data have not been broken by exception.
91 TestPotentialDeadLockDetected(mutex1, mutex2);
92
93 #ifdef DEBUG_LOCKORDER
94 g_debug_lockorder_abort = prev;
95 #endif
96}
97
98/* Double lock would produce an undefined behavior. Thus, we only do that if
99 * DEBUG_LOCKORDER is activated to detect it. We don't want non-DEBUG_LOCKORDER
100 * build to produce tests that exhibit known undefined behavior. */
101#ifdef DEBUG_LOCKORDER
102BOOST_AUTO_TEST_CASE(double_lock_mutex)
103{
104 TestDoubleLock<Mutex>(/*should_throw=*/true);
105}
106
107BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
108{
109 TestDoubleLock<RecursiveMutex>(/*should_throw=*/false);
110}
111#endif /* DEBUG_LOCKORDER */
112
113BOOST_AUTO_TEST_CASE(inconsistent_lock_order_detected)
114{
115#ifdef DEBUG_LOCKORDER
116 bool prev = g_debug_lockorder_abort;
117 g_debug_lockorder_abort = false;
118#endif // DEBUG_LOCKORDER
119
120 RecursiveMutex rmutex1, rmutex2;
121 TestInconsistentLockOrderDetected(rmutex1, rmutex2);
122 // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical)
123 // the lock tracking data must not have been broken by exception.
124 TestInconsistentLockOrderDetected(rmutex1, rmutex2);
125
126 Mutex mutex1, mutex2;
127 TestInconsistentLockOrderDetected(mutex1, mutex2);
128 // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical)
129 // the lock tracking data must not have been broken by exception.
130 TestInconsistentLockOrderDetected(mutex1, mutex2);
131
132#ifdef DEBUG_LOCKORDER
133 g_debug_lockorder_abort = prev;
134#endif // DEBUG_LOCKORDER
135}
136
BOOST_CHECK_EXCEPTION predicates to check the specific validation error.
Definition common.h:19
HasReason(std::string_view reason)
Definition common.h:21
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EXCEPTION(req.LoadBody(reader), std::runtime_error, HasReason{"Cannot parse Content-Length value"})
BOOST_AUTO_TEST_CASE(ipc_tests)
#define BOOST_CHECK_NO_THROW(stmt)
Definition object.cpp:27
#define BOOST_CHECK(expr)
Definition object.cpp:16
#define WAIT_LOCK(cs, name)
Definition sync.h:274
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition sync.h:131
#define LOCK2(cs1, cs2)
Definition sync.h:269
AnnotatedMixin< std::recursive_mutex > RecursiveMutex
Wrapped mutex: supports recursive locking, but no waiting TODO: We should move away from using the re...
Definition sync.h:128
#define REVERSE_LOCK(g, cs)
Definition sync.h:254
#define LOCK(cs)
Definition sync.h:268
bool LockStackEmpty()
Definition sync.h:75