Bitcoin ABC  0.29.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 /*
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,
58  MutexType *cs, bool fTry = false);
59 void LeaveCritical();
60 void CheckLastCritical(void *cs, std::string &lockname, const char *guardname,
61  const char *file, int line);
62 std::string LocksHeld();
63 template <typename MutexType>
64 void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine,
65  MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
66 template <typename MutexType>
67 void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
68  int nLine, MutexType *cs) LOCKS_EXCLUDED(cs);
69 void DeleteLock(void *cs);
70 bool LockStackEmpty();
71 
77 extern bool g_debug_lockorder_abort;
78 #else
79 template <typename MutexType>
80 inline void EnterCritical(const char *pszName, const char *pszFile, int nLine,
81  MutexType *cs, bool fTry = false) {}
82 inline void LeaveCritical() {}
83 inline void CheckLastCritical(void *cs, std::string &lockname,
84  const char *guardname, const char *file,
85  int line) {}
86 template <typename MutexType>
87 inline void AssertLockHeldInternal(const char *pszName, const char *pszFile,
88  int nLine, MutexType *cs)
90 template <typename MutexType>
91 void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
92  int nLine, MutexType *cs) LOCKS_EXCLUDED(cs) {}
93 inline void DeleteLock(void *cs) {}
94 inline bool LockStackEmpty() {
95  return true;
96 }
97 #endif
98 
103 template <typename PARENT> class LOCKABLE AnnotatedMixin : public PARENT {
104 public:
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 
144 class GlobalMutex : public Mutex {};
145 
146 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
147 
148 inline void AssertLockNotHeldInline(const char *name, const char *file,
149  int line, Mutex *cs)
151  AssertLockNotHeldInternal(name, file, line, cs);
152 }
153 inline void AssertLockNotHeldInline(const char *name, const char *file,
154  int line, RecursiveMutex *cs)
155  LOCKS_EXCLUDED(cs) {
156  AssertLockNotHeldInternal(name, file, line, cs);
157 }
158 inline void AssertLockNotHeldInline(const char *name, const char *file,
159  int line, GlobalMutex *cs)
160  LOCKS_EXCLUDED(cs) {
161  AssertLockNotHeldInternal(name, file, line, cs);
162 }
163 #define AssertLockNotHeld(cs) \
164  AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
165 
167 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
168 class SCOPED_LOCKABLE UniqueLock : public Base {
169 private:
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  }
188  LeaveCritical();
189  return false;
190  }
191 
192 public:
193  UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile,
194  int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
195  : Base(mutexIn, std::defer_lock) {
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()) {
219  LeaveCritical();
220  }
221  }
222 
223  operator bool() { return Base::owns_lock(); }
224 
225 protected:
226  // needed for reverse_lock
228 
229 public:
234  class reverse_lock {
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();
242  LeaveCritical();
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 
269 template <typename MutexArg>
270 using 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
276  LOCK_RETURNED(cs) {
277  return cs;
278 }
280  LOCK_RETURNED(cs) {
281  return cs;
282 }
283 
284 // When locking a GlobalMutex, just check it is not locked in the surrounding
285 // scope
287  LOCK_RETURNED(cs) {
288  return cs;
289 }
291  LOCK_RETURNED(cs) {
292  return cs;
293 }
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
298  LOCK_RETURNED(cs) {
299  return cs;
300 }
302  LOCK_RETURNED(cs) {
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 
363 class CSemaphore {
364 private:
365  std::condition_variable condition;
366  std::mutex mutex;
367  int value;
368 
369 public:
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 
398 private:
401 
402 public:
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 
426  void MoveTo(CSemaphoreGrant &grant) {
427  grant.Release();
428  grant.sem = sem;
429  grant.fHaveGrant = fHaveGrant;
430  fHaveGrant = false;
431  }
432 
433  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
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 &)
reverse_lock & operator=(reverse_lock const &)
std::string lockname
Definition: sync.h:258
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
Definition: common.cpp:28
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:257
const char * name
Definition: rest.cpp:48
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
Mutex & MaybeCheckNotHeld(Mutex &cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs)
Definition: sync.h:275
#define LOCK(cs)
Definition: sync.h:306
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
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:1202