Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
sync.h
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2016 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#ifdef DEBUG_LOCKCONTENTION
10#include <logging.h>
11#include <logging/timer.h>
12#endif
13
14#include <threadsafety.h>
15#include <util/macros.h>
16
17#include <condition_variable>
18#include <mutex>
19#include <string>
20#include <thread>
21
23// //
24// THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
25// //
27
28/*
29RecursiveMutex mutex;
30 std::recursive_mutex mutex;
31
32LOCK(mutex);
33 std::unique_lock<std::recursive_mutex> criticalblock(mutex);
34
35LOCK2(mutex1, mutex2);
36 std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
37 std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
38
39TRY_LOCK(mutex, name);
40 std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
41
42ENTER_CRITICAL_SECTION(mutex); // no RAII
43 mutex.lock();
44
45LEAVE_CRITICAL_SECTION(mutex); // no RAII
46 mutex.unlock();
47 */
48
50// //
51// THE ACTUAL IMPLEMENTATION //
52// //
54
55#ifdef DEBUG_LOCKORDER
56template <typename MutexType>
57void EnterCritical(const char *pszName, const char *pszFile, int nLine,
58 MutexType *cs, bool fTry = false);
59void LeaveCritical();
60void CheckLastCritical(void *cs, std::string &lockname, const char *guardname,
61 const char *file, int line);
62std::string LocksHeld();
63template <typename MutexType>
64void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine,
66template <typename MutexType>
67void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
69void DeleteLock(void *cs);
70bool LockStackEmpty();
71
77extern bool g_debug_lockorder_abort;
78#else
79template <typename MutexType>
80inline void EnterCritical(const char *pszName, const char *pszFile, int nLine,
81 MutexType *cs, bool fTry = false) {}
82inline void LeaveCritical() {}
83inline void CheckLastCritical(void *cs, std::string &lockname,
84 const char *guardname, const char *file,
85 int line) {}
86template <typename MutexType>
87inline void AssertLockHeldInternal(const char *pszName, const char *pszFile,
88 int nLine, MutexType *cs)
90template <typename MutexType>
91void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
93inline void DeleteLock(void *cs) {}
94inline bool LockStackEmpty() {
95 return true;
96}
97#endif
98
103template <typename PARENT> class LOCKABLE AnnotatedMixin : public PARENT {
104public:
105 ~AnnotatedMixin() { DeleteLock((void *)this); }
106
107 void lock() EXCLUSIVE_LOCK_FUNCTION() { PARENT::lock(); }
108
109 void unlock() UNLOCK_FUNCTION() { PARENT::unlock(); }
110
112 return PARENT::try_lock();
113 }
114
115 using UniqueLock = std::unique_lock<PARENT>;
116#ifdef __clang__
121 const AnnotatedMixin &operator!() const { return *this; }
122#endif // __clang__
123};
124
130
133
144class GlobalMutex : public Mutex {};
145
146#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
147
148inline void AssertLockNotHeldInline(const char *name, const char *file,
149 int line, Mutex *cs)
151 AssertLockNotHeldInternal(name, file, line, cs);
152}
153inline void AssertLockNotHeldInline(const char *name, const char *file,
154 int line, RecursiveMutex *cs)
156 AssertLockNotHeldInternal(name, file, line, cs);
157}
158inline void AssertLockNotHeldInline(const char *name, const char *file,
159 int line, GlobalMutex *cs)
161 AssertLockNotHeldInternal(name, file, line, cs);
162}
163#define AssertLockNotHeld(cs) \
164 AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
165
167template <typename Mutex, typename Base = typename Mutex::UniqueLock>
169private:
170 void Enter(const char *pszName, const char *pszFile, int nLine) {
171 EnterCritical(pszName, pszFile, nLine, Base::mutex());
172#ifdef DEBUG_LOCKCONTENTION
173 if (Base::try_lock()) {
174 return;
175 }
177 strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine),
178 BCLog::LOCK);
179#endif
180 Base::lock();
181 }
182
183 bool TryEnter(const char *pszName, const char *pszFile, int nLine) {
184 EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
185 if (Base::try_lock()) {
186 return true;
187 }
189 return false;
190 }
191
192public:
193 UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile,
194 int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
196 if (fTry) {
197 TryEnter(pszName, pszFile, nLine);
198 } else {
199 Enter(pszName, pszFile, nLine);
200 }
201 }
202
203 UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile,
204 int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) {
205 if (!pmutexIn) {
206 return;
207 }
208
209 *static_cast<Base *>(this) = Base(*pmutexIn, std::defer_lock);
210 if (fTry) {
211 TryEnter(pszName, pszFile, nLine);
212 } else {
213 Enter(pszName, pszFile, nLine);
214 }
215 }
216
218 if (Base::owns_lock()) {
220 }
221 }
222
223 operator bool() { return Base::owns_lock(); }
224
225protected:
226 // needed for reverse_lock
228
229public:
235 public:
236 explicit reverse_lock(UniqueLock &_lock, const char *_guardname,
237 const char *_file, int _line)
238 : lock(_lock), file(_file), line(_line) {
239 CheckLastCritical((void *)lock.mutex(), lockname, _guardname, _file,
240 _line);
241 lock.unlock();
243 lock.swap(templock);
244 }
245
247 templock.swap(lock);
248 EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
249 lock.lock();
250 }
251
252 private:
255
258 std::string lockname;
259 const std::string file;
260 const int line;
261 };
262 friend class reverse_lock;
263};
264
265#define REVERSE_LOCK(g) \
266 typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_LOG_NAME( \
267 revlock)(g, #g, __FILE__, __LINE__)
268
269template <typename MutexArg>
270using DebugLock = UniqueLock<typename std::remove_reference<
271 typename std::remove_pointer<MutexArg>::type>::type>;
272
273// When locking a Mutex, require negative capability to ensure the lock
274// is not already held
283
284// When locking a GlobalMutex, just check it is not locked in the surrounding
285// scope
294
295// When locking a RecursiveMutex, it's okay to already hold the lock
296// but check that it is not known to be locked in the surrounding scope anyway
299 return cs;
300}
303 return cs;
304}
305
306#define LOCK(cs) \
307 DebugLock<decltype(cs)> UNIQUE_LOG_NAME(criticalblock)( \
308 MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
309#define LOCK2(cs1, cs2) \
310 DebugLock<decltype(cs1)> criticalblock1(MaybeCheckNotHeld(cs1), #cs1, \
311 __FILE__, __LINE__); \
312 DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, \
313 __FILE__, __LINE__);
314#define TRY_LOCK(cs, name) \
315 DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, \
316 __LINE__, true)
317#define WAIT_LOCK(cs, name) \
318 DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
319
320#define ENTER_CRITICAL_SECTION(cs) \
321 { \
322 EnterCritical(#cs, __FILE__, __LINE__, &cs); \
323 (cs).lock(); \
324 }
325
326#define LEAVE_CRITICAL_SECTION(cs) \
327 { \
328 std::string lockname; \
329 CheckLastCritical((void *)(&cs), lockname, #cs, __FILE__, __LINE__); \
330 (cs).unlock(); \
331 LeaveCritical(); \
332 }
333
357#define WITH_LOCK(cs, code) \
358 (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { \
359 LOCK(cs); \
360 code; \
361 }())
362
364private:
365 std::condition_variable condition;
366 std::mutex mutex;
367 int value;
368
369public:
370 explicit CSemaphore(int init) : value(init) {}
371
372 void wait() {
373 std::unique_lock<std::mutex> lock(mutex);
374 condition.wait(lock, [&]() { return value >= 1; });
375 value--;
376 }
377
378 bool try_wait() {
379 std::lock_guard<std::mutex> lock(mutex);
380 if (value < 1) {
381 return false;
382 }
383 value--;
384 return true;
385 }
386
387 void post() {
388 {
389 std::lock_guard<std::mutex> lock(mutex);
390 value++;
391 }
392 condition.notify_one();
393 }
394};
395
398private:
401
402public:
403 void Acquire() {
404 if (fHaveGrant) {
405 return;
406 }
407 sem->wait();
408 fHaveGrant = true;
409 }
410
411 void Release() {
412 if (!fHaveGrant) {
413 return;
414 }
415 sem->post();
416 fHaveGrant = false;
417 }
418
419 bool TryAcquire() {
420 if (!fHaveGrant && sem->try_wait()) {
421 fHaveGrant = true;
422 }
423 return fHaveGrant;
424 }
425
427 grant.Release();
428 grant.sem = sem;
429 grant.fHaveGrant = fHaveGrant;
430 fHaveGrant = false;
431 }
432
434
435 explicit CSemaphoreGrant(CSemaphore &sema, bool fTry = false)
436 : sem(&sema), fHaveGrant(false) {
437 if (fTry) {
438 TryAcquire();
439 } else {
440 Acquire();
441 }
442 }
443
445
446 operator bool() const { return fHaveGrant; }
447};
448
449#endif // BITCOIN_SYNC_H
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition sync.h:103
~AnnotatedMixin()
Definition sync.h:105
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition sync.h:111
void unlock() UNLOCK_FUNCTION()
Definition sync.h:109
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition sync.h:107
RAII-style semaphore lock.
Definition sync.h:397
bool fHaveGrant
Definition sync.h:400
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition sync.h:435
CSemaphoreGrant()
Definition sync.h:433
void Release()
Definition sync.h:411
bool TryAcquire()
Definition sync.h:419
~CSemaphoreGrant()
Definition sync.h:444
void MoveTo(CSemaphoreGrant &grant)
Definition sync.h:426
void Acquire()
Definition sync.h:403
CSemaphore * sem
Definition sync.h:399
void wait()
Definition sync.h:372
int value
Definition sync.h:367
std::mutex mutex
Definition sync.h:366
bool try_wait()
Definition sync.h:378
CSemaphore(int init)
Definition sync.h:370
std::condition_variable condition
Definition sync.h:365
void post()
Definition sync.h:387
Different type to mark Mutex at global scope.
Definition sync.h:144
An RAII-style reverse lock.
Definition sync.h:234
reverse_lock(reverse_lock const &)
std::string lockname
Definition sync.h:258
reverse_lock & operator=(reverse_lock const &)
const std::string file
Definition sync.h:259
UniqueLock templock
Definition sync.h:257
UniqueLock & lock
Definition sync.h:256
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition sync.h:236
Wrapper around std::unique_lock style lock for Mutex.
Definition sync.h:168
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition sync.h:183
~UniqueLock() UNLOCK_FUNCTION()
Definition sync.h:217
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition sync.h:193
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition sync.h:170
UniqueLock()
Definition sync.h:227
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition sync.h:203
static void pool cs
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition rcu.h:259
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
const char * name
Definition rest.cpp:47
void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition sync.h:87
void AssertLockNotHeldInline(const char *name, const char *file, int line, Mutex *cs) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition sync.h:148
void EnterCritical(const char *pszName, const char *pszFile, int nLine, MutexType *cs, bool fTry=false)
Definition sync.h:80
void DeleteLock(void *cs)
Definition sync.h:93
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, const char *file, int line)
Definition sync.h:83
void LeaveCritical()
Definition sync.h:82
bool LockStackEmpty()
Definition sync.h:94
Mutex & MaybeCheckNotHeld(Mutex &cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs)
Definition sync.h:275
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) LOCKS_EXCLUDED(cs)
Definition sync.h:91
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
#define LOCKS_EXCLUDED(...)
#define EXCLUSIVE_LOCK_FUNCTION(...)
#define SCOPED_LOCKABLE
#define LOCKABLE
#define LOCK_RETURNED(x)
#define UNLOCK_FUNCTION(...)
#define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category)
Definition timer.h:94
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...