Bitcoin Core  27.99.0
P2P Digital Currency
sync.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 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> // IWYU pragma: export
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 /*
29 RecursiveMutex mutex;
30  std::recursive_mutex mutex;
31 
32 LOCK(mutex);
33  std::unique_lock<std::recursive_mutex> criticalblock(mutex);
34 
35 LOCK2(mutex1, mutex2);
36  std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
37  std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
38 
39 TRY_LOCK(mutex, name);
40  std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
41 
42 ENTER_CRITICAL_SECTION(mutex); // no RAII
43  mutex.lock();
44 
45 LEAVE_CRITICAL_SECTION(mutex); // no RAII
46  mutex.unlock();
47  */
48 
50 // //
51 // THE ACTUAL IMPLEMENTATION //
52 // //
54 
55 #ifdef DEBUG_LOCKORDER
56 template <typename MutexType>
57 void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false);
58 void LeaveCritical();
59 void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
60 template <typename MutexType>
61 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
62 template <typename MutexType>
63 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs);
64 void DeleteLock(void* cs);
65 bool LockStackEmpty();
66 
72 extern bool g_debug_lockorder_abort;
73 #else
74 template <typename MutexType>
75 inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {}
76 inline void LeaveCritical() {}
77 inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
78 template <typename MutexType>
79 inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
80 template <typename MutexType>
81 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {}
82 inline void DeleteLock(void* cs) {}
83 inline bool LockStackEmpty() { return true; }
84 #endif
85 
90 template <typename PARENT>
91 class LOCKABLE AnnotatedMixin : public PARENT
92 {
93 public:
95  DeleteLock((void*)this);
96  }
97 
99  {
100  PARENT::lock();
101  }
102 
104  {
105  PARENT::unlock();
106  }
107 
109  {
110  return PARENT::try_lock();
111  }
112 
113  using unique_lock = std::unique_lock<PARENT>;
114 #ifdef __clang__
118  const AnnotatedMixin& operator!() const { return *this; }
119 #endif // __clang__
120 };
121 
127 
130 
140 class GlobalMutex : public Mutex { };
141 
142 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
143 
144 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); }
145 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
146 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
147 #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
148 
150 template <typename MutexType>
151 class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock
152 {
153 private:
154  using Base = typename MutexType::unique_lock;
155 
156  void Enter(const char* pszName, const char* pszFile, int nLine)
157  {
158  EnterCritical(pszName, pszFile, nLine, Base::mutex());
159 #ifdef DEBUG_LOCKCONTENTION
160  if (Base::try_lock()) return;
161  LOG_TIME_MICROS_WITH_CATEGORY(strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK);
162 #endif
163  Base::lock();
164  }
165 
166  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
167  {
168  EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
169  if (Base::try_lock()) {
170  return true;
171  }
172  LeaveCritical();
173  return false;
174  }
175 
176 public:
177  UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
178  {
179  if (fTry)
180  TryEnter(pszName, pszFile, nLine);
181  else
182  Enter(pszName, pszFile, nLine);
183  }
184 
185  UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
186  {
187  if (!pmutexIn) return;
188 
189  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
190  if (fTry)
191  TryEnter(pszName, pszFile, nLine);
192  else
193  Enter(pszName, pszFile, nLine);
194  }
195 
197  {
198  if (Base::owns_lock())
199  LeaveCritical();
200  }
201 
202  operator bool()
203  {
204  return Base::owns_lock();
205  }
206 
207 protected:
208  // needed for reverse_lock
210 
211 public:
215  class reverse_lock {
216  public:
217  explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {
218  CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
219  lock.unlock();
220  LeaveCritical();
221  lock.swap(templock);
222  }
223 
225  templock.swap(lock);
226  EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
227  lock.lock();
228  }
229 
230  private:
233 
236  std::string lockname;
237  const std::string file;
238  const int line;
239  };
240  friend class reverse_lock;
241 };
242 
243 #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__)
244 
245 // When locking a Mutex, require negative capability to ensure the lock
246 // is not already held
249 
250 // When locking a GlobalMutex or RecursiveMutex, just check it is not
251 // locked in the surrounding scope.
252 template <typename MutexType>
253 inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
254 template <typename MutexType>
255 inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; }
256 
257 #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
258 #define LOCK2(cs1, cs2) \
259  UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \
260  UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__)
261 #define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true)
262 #define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
263 
264 #define ENTER_CRITICAL_SECTION(cs) \
265  { \
266  EnterCritical(#cs, __FILE__, __LINE__, &cs); \
267  (cs).lock(); \
268  }
269 
270 #define LEAVE_CRITICAL_SECTION(cs) \
271  { \
272  std::string lockname; \
273  CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \
274  (cs).unlock(); \
275  LeaveCritical(); \
276  }
277 
301 #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
302 
308 {
309 private:
310  std::condition_variable condition;
311  std::mutex mutex;
312  int value;
313 
314 public:
315  explicit CSemaphore(int init) noexcept : value(init) {}
316 
317  // Disallow default construct, copy, move.
318  CSemaphore() = delete;
319  CSemaphore(const CSemaphore&) = delete;
320  CSemaphore(CSemaphore&&) = delete;
321  CSemaphore& operator=(const CSemaphore&) = delete;
323 
324  void wait() noexcept
325  {
326  std::unique_lock<std::mutex> lock(mutex);
327  condition.wait(lock, [&]() { return value >= 1; });
328  value--;
329  }
330 
331  bool try_wait() noexcept
332  {
333  std::lock_guard<std::mutex> lock(mutex);
334  if (value < 1) {
335  return false;
336  }
337  value--;
338  return true;
339  }
340 
341  void post() noexcept
342  {
343  {
344  std::lock_guard<std::mutex> lock(mutex);
345  value++;
346  }
347  condition.notify_one();
348  }
349 };
350 
353 {
354 private:
357 
358 public:
359  void Acquire() noexcept
360  {
361  if (fHaveGrant) {
362  return;
363  }
364  sem->wait();
365  fHaveGrant = true;
366  }
367 
368  void Release() noexcept
369  {
370  if (!fHaveGrant) {
371  return;
372  }
373  sem->post();
374  fHaveGrant = false;
375  }
376 
377  bool TryAcquire() noexcept
378  {
379  if (!fHaveGrant && sem->try_wait()) {
380  fHaveGrant = true;
381  }
382  return fHaveGrant;
383  }
384 
385  // Disallow copy.
388 
389  // Allow move.
391  {
392  sem = other.sem;
393  fHaveGrant = other.fHaveGrant;
394  other.fHaveGrant = false;
395  other.sem = nullptr;
396  }
397 
399  {
400  Release();
401  sem = other.sem;
402  fHaveGrant = other.fHaveGrant;
403  other.fHaveGrant = false;
404  other.sem = nullptr;
405  return *this;
406  }
407 
408  CSemaphoreGrant() noexcept : sem(nullptr), fHaveGrant(false) {}
409 
410  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) noexcept : sem(&sema), fHaveGrant(false)
411  {
412  if (fTry) {
413  TryAcquire();
414  } else {
415  Acquire();
416  }
417  }
418 
420  {
421  Release();
422  }
423 
424  explicit operator bool() const noexcept
425  {
426  return fHaveGrant;
427  }
428 };
429 
430 #endif // BITCOIN_SYNC_H
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:92
~AnnotatedMixin()
Definition: sync.h:94
std::unique_lock< PARENT > unique_lock
Definition: sync.h:113
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:108
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:103
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:98
(Un)serialize a number as raw byte or 2 hexadecimal chars.
RAII-style semaphore lock.
Definition: sync.h:353
bool fHaveGrant
Definition: sync.h:356
CSemaphoreGrant(const CSemaphoreGrant &)=delete
void Acquire() noexcept
Definition: sync.h:359
CSemaphoreGrant(CSemaphore &sema, bool fTry=false) noexcept
Definition: sync.h:410
CSemaphoreGrant & operator=(const CSemaphoreGrant &)=delete
void Release() noexcept
Definition: sync.h:368
CSemaphoreGrant & operator=(CSemaphoreGrant &&other) noexcept
Definition: sync.h:398
~CSemaphoreGrant()
Definition: sync.h:419
CSemaphoreGrant() noexcept
Definition: sync.h:408
bool TryAcquire() noexcept
Definition: sync.h:377
CSemaphoreGrant(CSemaphoreGrant &&other) noexcept
Definition: sync.h:390
CSemaphore * sem
Definition: sync.h:355
An implementation of a semaphore.
Definition: sync.h:308
int value
Definition: sync.h:312
CSemaphore(CSemaphore &&)=delete
CSemaphore & operator=(const CSemaphore &)=delete
CSemaphore & operator=(CSemaphore &&)=delete
CSemaphore(int init) noexcept
Definition: sync.h:315
void wait() noexcept
Definition: sync.h:324
bool try_wait() noexcept
Definition: sync.h:331
std::mutex mutex
Definition: sync.h:311
CSemaphore(const CSemaphore &)=delete
void post() noexcept
Definition: sync.h:341
CSemaphore()=delete
std::condition_variable condition
Definition: sync.h:310
Different type to mark Mutex at global scope.
Definition: sync.h:140
An RAII-style reverse lock.
Definition: sync.h:215
UniqueLock & lock
Definition: sync.h:234
const std::string file
Definition: sync.h:237
std::string lockname
Definition: sync.h:236
reverse_lock(reverse_lock const &)
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition: sync.h:217
reverse_lock & operator=(reverse_lock const &)
UniqueLock templock
Definition: sync.h:235
Wrapper around std::unique_lock style lock for MutexType.
Definition: sync.h:152
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:196
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:166
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:156
UniqueLock()
Definition: sync.h:209
UniqueLock(MutexType &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:177
UniqueLock(MutexType *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:185
static void pool cs
const char * name
Definition: rest.cpp:50
void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: sync.h:79
void AssertLockNotHeldInline(const char *name, const char *file, int line, Mutex *cs) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: sync.h:144
void EnterCritical(const char *pszName, const char *pszFile, int nLine, MutexType *cs, bool fTry=false)
Definition: sync.h:75
void DeleteLock(void *cs)
Definition: sync.h:82
Mutex & MaybeCheckNotHeld(Mutex &cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs)
Definition: sync.h:247
#define LOCK(cs)
Definition: sync.h:257
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, const char *file, int line)
Definition: sync.h:77
void LeaveCritical()
Definition: sync.h:76
bool LockStackEmpty()
Definition: sync.h:83
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) LOCKS_EXCLUDED(cs)
Definition: sync.h:81
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:44
#define LOCKS_EXCLUDED(...)
Definition: threadsafety.h:48
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:42
#define SCOPED_LOCKABLE
Definition: threadsafety.h:37
#define LOCKABLE
Definition: threadsafety.h:36
#define LOCK_RETURNED(x)
Definition: threadsafety.h:47
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:46
#define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category)
Definition: timer.h:101
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162