Bitcoin ABC 0.34.2
P2P Digital Currency
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,
65 MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
66template <typename MutexType>
67void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
68 int nLine, MutexType *cs) LOCKS_EXCLUDED(cs);
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,
92 int nLine, MutexType *cs) LOCKS_EXCLUDED(cs) {}
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 unique_lock = 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 MutexType>
168class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock {
169private:
170 using Base = typename MutexType::unique_lock;
171
172 void Enter(const char *pszName, const char *pszFile, int nLine) {
173 EnterCritical(pszName, pszFile, nLine, Base::mutex());
174#ifdef DEBUG_LOCKCONTENTION
175 if (Base::try_lock()) {
176 return;
177 }
179 strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine),
181#endif
182 Base::lock();
183 }
184
185 bool TryEnter(const char *pszName, const char *pszFile, int nLine) {
186 EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
187 if (Base::try_lock()) {
188 return true;
189 }
191 return false;
192 }
193
194public:
195 UniqueLock(MutexType &mutexIn, const char *pszName, const char *pszFile,
196 int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
197 : Base(mutexIn, std::defer_lock) {
198 if (fTry) {
199 TryEnter(pszName, pszFile, nLine);
200 } else {
201 Enter(pszName, pszFile, nLine);
202 }
203 }
204
205 UniqueLock(MutexType *pmutexIn, const char *pszName, const char *pszFile,
206 int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) {
207 if (!pmutexIn) {
208 return;
209 }
210
211 *static_cast<Base *>(this) = Base(*pmutexIn, std::defer_lock);
212 if (fTry) {
213 TryEnter(pszName, pszFile, nLine);
214 } else {
215 Enter(pszName, pszFile, nLine);
216 }
217 }
218
220 if (Base::owns_lock()) {
222 }
223 }
224
225 operator bool() { return Base::owns_lock(); }
226
227protected:
228 // needed for reverse_lock
229 UniqueLock() = default;
230
231public:
237 public:
238 explicit reverse_lock(UniqueLock &_lock, const char *_guardname,
239 const char *_file, int _line)
240 : lock(_lock), file(_file), line(_line) {
241 CheckLastCritical((void *)lock.mutex(), lockname, _guardname, _file,
242 _line);
243 lock.unlock();
245 lock.swap(templock);
246 }
247
249 templock.swap(lock);
250 EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
251 lock.lock();
252 }
253
254 private:
257
260 std::string lockname;
261 const std::string file;
262 const int line;
263 };
264 friend class reverse_lock;
265};
266
267#define REVERSE_LOCK(g) \
268 typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_LOG_NAME( \
269 revlock)(g, #g, __FILE__, __LINE__)
270
271// When locking a Mutex, require negative capability to ensure the lock
272// is not already held
275 return cs;
276}
279 return cs;
280}
281
282// When locking a GlobalMutex or RecursiveMutex, just check it is not
283// locked in the surrounding scope.
284template <typename MutexType>
285inline MutexType &MaybeCheckNotHeld(MutexType &m) LOCKS_EXCLUDED(m)
286 LOCK_RETURNED(m) {
287 return m;
288}
289template <typename MutexType>
290inline MutexType *MaybeCheckNotHeld(MutexType *m) LOCKS_EXCLUDED(m)
291 LOCK_RETURNED(m) {
292 return m;
293}
294
295#define LOCK(cs) \
296 UniqueLock UNIQUE_LOG_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, \
297 __FILE__, __LINE__)
298#define LOCK2(cs1, cs2) \
299 UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, \
300 __LINE__); \
301 UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
302#define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__
303#define TRY_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs), true)
304#define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs))
305
306#define ENTER_CRITICAL_SECTION(cs) \
307 { \
308 EnterCritical(#cs, __FILE__, __LINE__, &cs); \
309 (cs).lock(); \
310 }
311
312#define LEAVE_CRITICAL_SECTION(cs) \
313 { \
314 std::string lockname; \
315 CheckLastCritical((void *)(&cs), lockname, #cs, __FILE__, __LINE__); \
316 (cs).unlock(); \
317 LeaveCritical(); \
318 }
319
343#define WITH_LOCK(cs, code) \
344 (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { \
345 LOCK(cs); \
346 code; \
347 }())
348
350private:
351 std::condition_variable condition;
352 std::mutex mutex;
353 int value;
354
355public:
356 explicit CSemaphore(int init) : value(init) {}
357
358 void wait() {
359 std::unique_lock<std::mutex> lock(mutex);
360 condition.wait(lock, [&]() { return value >= 1; });
361 value--;
362 }
363
364 bool try_wait() {
365 std::lock_guard<std::mutex> lock(mutex);
366 if (value < 1) {
367 return false;
368 }
369 value--;
370 return true;
371 }
372
373 void post() {
374 {
375 std::lock_guard<std::mutex> lock(mutex);
376 value++;
377 }
378 condition.notify_one();
379 }
380};
381
384private:
387
388public:
389 void Acquire() {
390 if (fHaveGrant) {
391 return;
392 }
393 sem->wait();
394 fHaveGrant = true;
395 }
396
397 void Release() {
398 if (!fHaveGrant) {
399 return;
400 }
401 sem->post();
402 fHaveGrant = false;
403 }
404
405 bool TryAcquire() {
406 if (!fHaveGrant && sem->try_wait()) {
407 fHaveGrant = true;
408 }
409 return fHaveGrant;
410 }
411
412 void MoveTo(CSemaphoreGrant &grant) {
413 grant.Release();
414 grant.sem = sem;
415 grant.fHaveGrant = fHaveGrant;
416 fHaveGrant = false;
417 }
418
419 CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
420
421 explicit CSemaphoreGrant(CSemaphore &sema, bool fTry = false)
422 : sem(&sema), fHaveGrant(false) {
423 if (fTry) {
424 TryAcquire();
425 } else {
426 Acquire();
427 }
428 }
429
431
432 operator bool() const { return fHaveGrant; }
433};
434
435#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
std::unique_lock< PARENT > unique_lock
Definition: sync.h:115
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:383
bool fHaveGrant
Definition: sync.h:386
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:421
CSemaphoreGrant()
Definition: sync.h:419
void Release()
Definition: sync.h:397
bool TryAcquire()
Definition: sync.h:405
~CSemaphoreGrant()
Definition: sync.h:430
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:412
void Acquire()
Definition: sync.h:389
CSemaphore * sem
Definition: sync.h:385
void wait()
Definition: sync.h:358
int value
Definition: sync.h:353
std::mutex mutex
Definition: sync.h:352
bool try_wait()
Definition: sync.h:364
CSemaphore(int init)
Definition: sync.h:356
std::condition_variable condition
Definition: sync.h:351
void post()
Definition: sync.h:373
Different type to mark Mutex at global scope.
Definition: sync.h:144
An RAII-style reverse lock.
Definition: sync.h:236
UniqueLock & lock
Definition: sync.h:258
const std::string file
Definition: sync.h:261
std::string lockname
Definition: sync.h:260
reverse_lock(reverse_lock const &)
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition: sync.h:238
reverse_lock & operator=(reverse_lock const &)
UniqueLock templock
Definition: sync.h:259
Wrapper around std::unique_lock style lock for MutexType.
Definition: sync.h:168
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:219
typename MutexType::unique_lock Base
Definition: sync.h:170
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:185
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:172
UniqueLock()=default
UniqueLock(MutexType &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:195
UniqueLock(MutexType *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:205
static void pool cs
Definition: common.cpp:26
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
const char * name
Definition: rest.cpp:46
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
#define LOCK(cs)
Definition: sync.h:295
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:273
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) LOCKS_EXCLUDED(cs)
Definition: sync.h:91
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:51
#define LOCKS_EXCLUDED(...)
Definition: threadsafety.h:55
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:49
#define SCOPED_LOCKABLE
Definition: threadsafety.h:44
#define LOCKABLE
Definition: threadsafety.h:43
#define LOCK_RETURNED(x)
Definition: threadsafety.h:54
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:53
#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...
Definition: tinyformat.h:1203