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