sync.h raw
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-present The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #ifndef BITCOIN_SYNC_H
7 #define BITCOIN_SYNC_H
8
9 // This header declares threading primitives compatible with Clang
10 // Thread Safety Analysis and provides appropriate annotation macros.
11 #include <threadsafety.h> // IWYU pragma: export
12 #include <util/macros.h>
13
14 #include <cassert>
15 #include <condition_variable>
16 #include <mutex>
17 #include <string>
18 #include <thread>
19
20 ////////////////////////////////////////////////
21 // //
22 // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
23 // //
24 ////////////////////////////////////////////////
25
26 /*
27 RecursiveMutex mutex;
28 std::recursive_mutex mutex;
29
30 LOCK(mutex);
31 std::unique_lock<std::recursive_mutex> criticalblock(mutex);
32
33 LOCK2(mutex1, mutex2);
34 std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
35 std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
36
37 TRY_LOCK(mutex, name);
38 std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
39 */
40
41 ///////////////////////////////
42 // //
43 // THE ACTUAL IMPLEMENTATION //
44 // //
45 ///////////////////////////////
46
47 #ifdef DEBUG_LOCKORDER
48 template <typename MutexType>
49 void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false);
50 void LeaveCritical();
51 void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
52 template <typename MutexType>
53 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
54 template <typename MutexType>
55 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs);
56 void DeleteLock(void* cs);
57 bool LockStackEmpty();
58
59 /**
60 * Call abort() if a potential lock order deadlock bug is detected, instead of
61 * just logging information and throwing a logic_error. Defaults to true, and
62 * set to false in DEBUG_LOCKORDER unit tests.
63 */
64 extern bool g_debug_lockorder_abort;
65 #else
66 template <typename MutexType>
67 inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {}
68 inline void LeaveCritical() {}
69 inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
70 template <typename MutexType>
71 inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
72 template <typename MutexType>
73 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {}
74 inline void DeleteLock(void* cs) {}
75 inline bool LockStackEmpty() { return true; }
76 #endif
77
78 /*
79 * Called when a mutex fails to lock immediately because it is held by another
80 * thread, or spuriously. Responsible for locking the lock before returning.
81 */
82 #ifdef DEBUG_LOCKCONTENTION
83
84 template <typename LockType>
85 void ContendedLock(std::string_view name, std::string_view file, int nLine, LockType& lock);
86 #endif
87
88 /**
89 * Template mixin that adds -Wthread-safety locking annotations and lock order
90 * checking to a subset of the mutex API.
91 */
92 template <typename PARENT>
93 class LOCKABLE AnnotatedMixin : public PARENT
94 {
95 public:
96 ~AnnotatedMixin() {
97 DeleteLock((void*)this);
98 }
99
100 void lock() EXCLUSIVE_LOCK_FUNCTION()
101 {
102 PARENT::lock();
103 }
104
105 void unlock() UNLOCK_FUNCTION()
106 {
107 PARENT::unlock();
108 }
109
110 bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
111 {
112 return PARENT::try_lock();
113 }
114
115 using unique_lock = std::unique_lock<PARENT>;
116 #ifdef __clang__
117 //! For negative capabilities in the Clang Thread Safety Analysis.
118 //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction
119 //! with the ! operator, to indicate that a mutex should not be held.
120 const AnnotatedMixin& operator!() const { return *this; }
121 #endif // __clang__
122 };
123
124 /**
125 * Wrapped mutex: supports recursive locking, but no waiting
126 * TODO: We should move away from using the recursive lock by default.
127 */
128 using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;
129
130 /** Wrapped mutex: supports waiting but not recursive locking */
131 using Mutex = AnnotatedMixin<std::mutex>;
132
133 /** Different type to mark Mutex at global scope
134 *
135 * Thread safety analysis can't handle negative assertions about mutexes
136 * with global scope well, so mark them with a separate type, and
137 * eventually move all the mutexes into classes so they are not globally
138 * visible.
139 *
140 * See: https://github.com/bitcoin/bitcoin/pull/20272#issuecomment-720755781
141 */
142 class GlobalMutex : public Mutex { };
143
144 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
145
146 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); }
147 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
148 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
149 #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
150
151 /** Wrapper around std::unique_lock style lock for MutexType. */
152 template <typename MutexType>
153 class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock
154 {
155 private:
156 using Base = typename MutexType::unique_lock;
157
158 void Enter(const char* pszName, const char* pszFile, int nLine)
159 {
160 EnterCritical(pszName, pszFile, nLine, Base::mutex());
161 #ifdef DEBUG_LOCKCONTENTION
162 if (!Base::try_lock()) {
163 ContendedLock(pszName, pszFile, nLine, static_cast<Base&>(*this));
164 }
165 #else
166 Base::lock();
167 #endif
168 }
169
170 bool TryEnter(const char* pszName, const char* pszFile, int nLine)
171 {
172 EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
173 if (Base::try_lock()) {
174 return true;
175 }
176 LeaveCritical();
177 return false;
178 }
179
180 public:
181 UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
182 {
183 if (fTry)
184 TryEnter(pszName, pszFile, nLine);
185 else
186 Enter(pszName, pszFile, nLine);
187 }
188
189 UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
190 {
191 if (!pmutexIn) return;
192
193 *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
194 if (fTry)
195 TryEnter(pszName, pszFile, nLine);
196 else
197 Enter(pszName, pszFile, nLine);
198 }
199
200 ~UniqueLock() UNLOCK_FUNCTION()
201 {
202 if (Base::owns_lock())
203 LeaveCritical();
204 }
205
206 operator bool()
207 {
208 return Base::owns_lock();
209 }
210
211 protected:
212 // needed for reverse_lock
213 UniqueLock() = default;
214
215 public:
216 /**
217 * An RAII-style reverse lock. Unlocks on construction and locks on destruction.
218 */
219 class SCOPED_LOCKABLE reverse_lock {
220 public:
221 explicit reverse_lock(UniqueLock& _lock, const MutexType& mutex, const char* _guardname, const char* _file, int _line) UNLOCK_FUNCTION(mutex) : lock(_lock), file(_file), line(_line) {
222 // Ensure that mutex passed back for thread-safety analysis is indeed the original
223 assert(std::addressof(mutex) == lock.mutex());
224
225 CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
226 lock.unlock();
227 LeaveCritical();
228 lock.swap(templock);
229 }
230
231 ~reverse_lock() UNLOCK_FUNCTION() {
232 templock.swap(lock);
233 EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
234 lock.lock();
235 }
236
237 private:
238 reverse_lock(reverse_lock const&);
239 reverse_lock& operator=(reverse_lock const&);
240
241 UniqueLock& lock;
242 UniqueLock templock;
243 std::string lockname;
244 const std::string file;
245 const int line;
246 };
247 friend class reverse_lock;
248 };
249
250 // clang's thread-safety analyzer is unable to deal with aliases of mutexes, so
251 // it is not possible to use the lock's copy of the mutex for that purpose.
252 // Instead, the original mutex needs to be passed back to the reverse_lock for
253 // the sake of thread-safety analysis, but it is not actually used otherwise.
254 #define REVERSE_LOCK(g, cs) typename std::decay<decltype(g)>::type::reverse_lock BITCOIN_UNIQUE_NAME(revlock)(g, cs, #cs, __FILE__, __LINE__)
255
256 // When locking a Mutex, require negative capability to ensure the lock
257 // is not already held
258 inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
259 inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
260
261 // When locking a GlobalMutex or RecursiveMutex, just check it is not
262 // locked in the surrounding scope.
263 template <typename MutexType>
264 inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
265 template <typename MutexType>
266 inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
267
268 #define LOCK(cs) UniqueLock BITCOIN_UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
269 #define LOCK2(cs1, cs2) \
270 UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
271 UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
272 #define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
273 #define TRY_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs), true)
274 #define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
275
276 //! Run code while locking a mutex.
277 //!
278 //! Examples:
279 //!
280 //! WITH_LOCK(cs, shared_val = shared_val + 1);
281 //!
282 //! int val = WITH_LOCK(cs, return shared_val);
283 //!
284 //! Note:
285 //!
286 //! Since the return type deduction follows that of decltype(auto), while the
287 //! deduced type of:
288 //!
289 //! WITH_LOCK(cs, int i = 1; return i);
290 //!
291 //! is int, the deduced type of:
292 //!
293 //! WITH_LOCK(cs, int j = 1; return (j));
294 //!
295 //! is &int, a reference to a local variable
296 //!
297 //! The above is detectable at compile-time with the -Wreturn-local-addr flag in
298 //! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.
299 #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
300
301 #endif // BITCOIN_SYNC_H
302