Bitcoin Core  23.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-2021 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 /*
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 UniqueLock = std::unique_lock<PARENT>;
115 #ifdef __clang__
116  const AnnotatedMixin& operator!() const { return *this; }
120 #endif // __clang__
121 };
122 
128 
131 
132 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
133 
134 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); }
135 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); }
136 #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
137 
139 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
140 class SCOPED_LOCKABLE UniqueLock : public Base
141 {
142 private:
143  void Enter(const char* pszName, const char* pszFile, int nLine)
144  {
145  EnterCritical(pszName, pszFile, nLine, Base::mutex());
146 #ifdef DEBUG_LOCKCONTENTION
147  if (Base::try_lock()) return;
148  LOG_TIME_MICROS_WITH_CATEGORY(strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK);
149 #endif
150  Base::lock();
151  }
152 
153  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
154  {
155  EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
156  Base::try_lock();
157  if (!Base::owns_lock()) {
158  LeaveCritical();
159  }
160  return Base::owns_lock();
161  }
162 
163 public:
164  UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
165  {
166  if (fTry)
167  TryEnter(pszName, pszFile, nLine);
168  else
169  Enter(pszName, pszFile, nLine);
170  }
171 
172  UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
173  {
174  if (!pmutexIn) return;
175 
176  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
177  if (fTry)
178  TryEnter(pszName, pszFile, nLine);
179  else
180  Enter(pszName, pszFile, nLine);
181  }
182 
184  {
185  if (Base::owns_lock())
186  LeaveCritical();
187  }
188 
189  operator bool()
190  {
191  return Base::owns_lock();
192  }
193 
194 protected:
195  // needed for reverse_lock
197 
198 public:
202  class reverse_lock {
203  public:
204  explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {
205  CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
206  lock.unlock();
207  LeaveCritical();
208  lock.swap(templock);
209  }
210 
212  templock.swap(lock);
213  EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
214  lock.lock();
215  }
216 
217  private:
218  reverse_lock(reverse_lock const&);
219  reverse_lock& operator=(reverse_lock const&);
220 
223  std::string lockname;
224  const std::string file;
225  const int line;
226  };
227  friend class reverse_lock;
228 };
229 
230 #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__)
231 
232 template<typename MutexArg>
234 
235 #define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(cs, #cs, __FILE__, __LINE__)
236 #define LOCK2(cs1, cs2) \
237  DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
238  DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
239 #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
240 #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
241 
242 #define ENTER_CRITICAL_SECTION(cs) \
243  { \
244  EnterCritical(#cs, __FILE__, __LINE__, &cs); \
245  (cs).lock(); \
246  }
247 
248 #define LEAVE_CRITICAL_SECTION(cs) \
249  { \
250  std::string lockname; \
251  CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \
252  (cs).unlock(); \
253  LeaveCritical(); \
254  }
255 
279 #define WITH_LOCK(cs, code) [&]() -> decltype(auto) { LOCK(cs); code; }()
280 
282 {
283 private:
284  std::condition_variable condition;
285  std::mutex mutex;
286  int value;
287 
288 public:
289  explicit CSemaphore(int init) : value(init) {}
290 
291  void wait()
292  {
293  std::unique_lock<std::mutex> lock(mutex);
294  condition.wait(lock, [&]() { return value >= 1; });
295  value--;
296  }
297 
298  bool try_wait()
299  {
300  std::lock_guard<std::mutex> lock(mutex);
301  if (value < 1)
302  return false;
303  value--;
304  return true;
305  }
306 
307  void post()
308  {
309  {
310  std::lock_guard<std::mutex> lock(mutex);
311  value++;
312  }
313  condition.notify_one();
314  }
315 };
316 
319 {
320 private:
323 
324 public:
325  void Acquire()
326  {
327  if (fHaveGrant)
328  return;
329  sem->wait();
330  fHaveGrant = true;
331  }
332 
333  void Release()
334  {
335  if (!fHaveGrant)
336  return;
337  sem->post();
338  fHaveGrant = false;
339  }
340 
341  bool TryAcquire()
342  {
343  if (!fHaveGrant && sem->try_wait())
344  fHaveGrant = true;
345  return fHaveGrant;
346  }
347 
348  void MoveTo(CSemaphoreGrant& grant)
349  {
350  grant.Release();
351  grant.sem = sem;
352  grant.fHaveGrant = fHaveGrant;
353  fHaveGrant = false;
354  }
355 
356  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
357 
358  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
359  {
360  if (fTry)
361  TryAcquire();
362  else
363  Acquire();
364  }
365 
367  {
368  Release();
369  }
370 
371  operator bool() const
372  {
373  return fHaveGrant;
374  }
375 };
376 
377 #endif // BITCOIN_SYNC_H
CSemaphore::post
void post()
Definition: sync.h:307
UniqueLock::reverse_lock::~reverse_lock
~reverse_lock()
Definition: sync.h:211
UniqueLock::Enter
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:143
EXCLUSIVE_LOCK_FUNCTION
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:42
UNLOCK_FUNCTION
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:46
UniqueLock::reverse_lock::reverse_lock
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition: sync.h:204
CSemaphoreGrant::fHaveGrant
bool fHaveGrant
Definition: sync.h:322
UniqueLock::reverse_lock::line
const int line
Definition: sync.h:225
UniqueLock::reverse_lock::lock
UniqueLock & lock
Definition: sync.h:221
CSemaphoreGrant::MoveTo
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:348
UniqueLock::~UniqueLock
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:183
AnnotatedMixin
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:92
CheckLastCritical
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, const char *file, int line)
Definition: sync.h:78
CSemaphoreGrant::~CSemaphoreGrant
~CSemaphoreGrant()
Definition: sync.h:366
macros.h
DeleteLock
void DeleteLock(void *cs)
Definition: sync.h:83
CSemaphore::condition
std::condition_variable condition
Definition: sync.h:284
UniqueLock::UniqueLock
UniqueLock()
Definition: sync.h:196
UniqueLock::reverse_lock::templock
UniqueLock templock
Definition: sync.h:222
LeaveCritical
void LeaveCritical()
Definition: sync.h:77
CSemaphore::CSemaphore
CSemaphore(int init)
Definition: sync.h:289
cs
static void pool cs
Definition: mempool_eviction.cpp:12
SCOPED_LOCKABLE
#define SCOPED_LOCKABLE
Definition: threadsafety.h:37
CSemaphore
Definition: sync.h:281
CSemaphoreGrant
RAII-style semaphore lock.
Definition: sync.h:318
AnnotatedMixin::unlock
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:104
threadsafety.h
CSemaphore::mutex
std::mutex mutex
Definition: sync.h:285
CSemaphoreGrant::CSemaphoreGrant
CSemaphoreGrant()
Definition: sync.h:356
LOCKABLE
#define LOCKABLE
Definition: threadsafety.h:36
AssertLockNotHeldInline
void AssertLockNotHeldInline(const char *name, const char *file, int line, Mutex *cs) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: sync.h:134
AssertLockHeldInternal
void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: sync.h:80
CSemaphoreGrant::TryAcquire
bool TryAcquire()
Definition: sync.h:341
LOG_TIME_MICROS_WITH_CATEGORY
#define LOG_TIME_MICROS_WITH_CATEGORY(end_msg, log_category)
Definition: timer.h:99
timer.h
EXCLUSIVE_TRYLOCK_FUNCTION
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:44
LockStackEmpty
bool LockStackEmpty()
Definition: sync.h:84
name
const char * name
Definition: rest.cpp:46
UniqueLock::TryEnter
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:153
UniqueLock::reverse_lock::file
const std::string file
Definition: sync.h:224
UniqueLock
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:140
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
LOCKS_EXCLUDED
#define LOCKS_EXCLUDED(...)
Definition: threadsafety.h:48
EnterCritical
void EnterCritical(const char *pszName, const char *pszFile, int nLine, MutexType *cs, bool fTry=false)
Definition: sync.h:76
AnnotatedMixin::~AnnotatedMixin
~AnnotatedMixin()
Definition: sync.h:95
EXCLUSIVE_LOCKS_REQUIRED
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
CSemaphoreGrant::Acquire
void Acquire()
Definition: sync.h:325
LOCK
#define LOCK(cs)
Definition: sync.h:235
UniqueLock::UniqueLock
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:172
std
Definition: setup_common.h:33
CSemaphore::try_wait
bool try_wait()
Definition: sync.h:298
CSemaphoreGrant::Release
void Release()
Definition: sync.h:333
init
Definition: bitcoin-gui.cpp:17
AnnotatedMixin::lock
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:99
UniqueLock::reverse_lock::lockname
std::string lockname
Definition: sync.h:223
CSemaphoreGrant::CSemaphoreGrant
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:358
AnnotatedMixin::try_lock
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:109
AssertLockNotHeldInternal
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) LOCKS_EXCLUDED(cs)
Definition: sync.h:82
CSemaphore::wait
void wait()
Definition: sync.h:291
CSemaphoreGrant::sem
CSemaphore * sem
Definition: sync.h:321
UniqueLock::UniqueLock
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:164
CSemaphore::value
int value
Definition: sync.h:286
UniqueLock::reverse_lock
An RAII-style reverse lock.
Definition: sync.h:202