Bitcoin ABC  0.24.7
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 #include <threadsafety.h>
10 #include <util/macros.h>
11 
12 #include <condition_variable>
13 #include <mutex>
14 #include <string>
15 #include <thread>
16 
18 // //
19 // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
20 // //
22 
23 /*
24 RecursiveMutex mutex;
25  std::recursive_mutex mutex;
26 
27 LOCK(mutex);
28  std::unique_lock<std::recursive_mutex> criticalblock(mutex);
29 
30 LOCK2(mutex1, mutex2);
31  std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
32  std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
33 
34 TRY_LOCK(mutex, name);
35  std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
36 
37 ENTER_CRITICAL_SECTION(mutex); // no RAII
38  mutex.lock();
39 
40 LEAVE_CRITICAL_SECTION(mutex); // no RAII
41  mutex.unlock();
42  */
43 
45 // //
46 // THE ACTUAL IMPLEMENTATION //
47 // //
49 
50 #ifdef DEBUG_LOCKORDER
51 void EnterCritical(const char *pszName, const char *pszFile, int nLine,
52  void *cs, bool fTry = false);
53 void LeaveCritical();
54 void CheckLastCritical(void *cs, std::string &lockname, const char *guardname,
55  const char *file, int line);
56 std::string LocksHeld();
57 template <typename MutexType>
58 void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine,
59  MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
60 template <typename MutexType>
61 void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
62  int nLine, MutexType *cs) LOCKS_EXCLUDED(cs);
63 void DeleteLock(void *cs);
64 bool LockStackEmpty();
65 
71 extern bool g_debug_lockorder_abort;
72 #else
73 inline void EnterCritical(const char *pszName, const char *pszFile, int nLine,
74  void *cs, bool fTry = false) {}
75 inline void LeaveCritical() {}
76 inline void CheckLastCritical(void *cs, std::string &lockname,
77  const char *guardname, const char *file,
78  int line) {}
79 template <typename MutexType>
80 inline void AssertLockHeldInternal(const char *pszName, const char *pszFile,
81  int nLine, MutexType *cs)
83 template <typename MutexType>
84 void AssertLockNotHeldInternal(const char *pszName, const char *pszFile,
85  int nLine, MutexType *cs) LOCKS_EXCLUDED(cs) {}
86 inline void DeleteLock(void *cs) {}
87 inline bool LockStackEmpty() {
88  return true;
89 }
90 #endif
91 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
92 #define AssertLockNotHeld(cs) \
93  AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
94 
99 template <typename PARENT> class LOCKABLE AnnotatedMixin : public PARENT {
100 public:
101  ~AnnotatedMixin() { DeleteLock((void *)this); }
102 
103  void lock() EXCLUSIVE_LOCK_FUNCTION() { PARENT::lock(); }
104 
105  void unlock() UNLOCK_FUNCTION() { PARENT::unlock(); }
106 
108  return PARENT::try_lock();
109  }
110 
111  using UniqueLock = std::unique_lock<PARENT>;
112 #ifdef __clang__
113  const AnnotatedMixin &operator!() const { return *this; }
118 #endif // __clang__
119 };
120 
126 
129 
130 #ifdef DEBUG_LOCKCONTENTION
131 void PrintLockContention(const char *pszName, const char *pszFile, int nLine);
132 #endif
133 
135 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
136 class SCOPED_LOCKABLE UniqueLock : public Base {
137 private:
138  void Enter(const char *pszName, const char *pszFile, int nLine) {
139  EnterCritical(pszName, pszFile, nLine, (void *)(Base::mutex()));
140 #ifdef DEBUG_LOCKCONTENTION
141  if (!Base::try_lock()) {
142  PrintLockContention(pszName, pszFile, nLine);
143 #endif
144  Base::lock();
145 #ifdef DEBUG_LOCKCONTENTION
146  }
147 #endif
148  }
149 
150  bool TryEnter(const char *pszName, const char *pszFile, int nLine) {
151  EnterCritical(pszName, pszFile, nLine, (void *)(Base::mutex()), true);
152  Base::try_lock();
153  if (!Base::owns_lock()) {
154  LeaveCritical();
155  }
156  return Base::owns_lock();
157  }
158 
159 public:
160  UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile,
161  int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
162  : Base(mutexIn, std::defer_lock) {
163  if (fTry) {
164  TryEnter(pszName, pszFile, nLine);
165  } else {
166  Enter(pszName, pszFile, nLine);
167  }
168  }
169 
170  UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile,
171  int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) {
172  if (!pmutexIn) {
173  return;
174  }
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  }
183 
185  if (Base::owns_lock()) {
186  LeaveCritical();
187  }
188  }
189 
190  operator bool() { return Base::owns_lock(); }
191 
192 protected:
193  // needed for reverse_lock
195 
196 public:
201  class reverse_lock {
202  public:
203  explicit reverse_lock(UniqueLock &_lock, const char *_guardname,
204  const char *_file, int _line)
205  : lock(_lock), file(_file), line(_line) {
206  CheckLastCritical((void *)lock.mutex(), lockname, _guardname, _file,
207  _line);
208  lock.unlock();
209  LeaveCritical();
210  lock.swap(templock);
211  }
212 
214  templock.swap(lock);
215  EnterCritical(lockname.c_str(), file.c_str(), line,
216  (void *)lock.mutex());
217  lock.lock();
218  }
219 
220  private:
221  reverse_lock(reverse_lock const &);
222  reverse_lock &operator=(reverse_lock const &);
223 
226  std::string lockname;
227  const std::string file;
228  const int line;
229  };
230  friend class reverse_lock;
231 };
232 
233 #define REVERSE_LOCK(g) \
234  typename std::decay<decltype(g)>::type::reverse_lock PASTE2( \
235  revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
236 
237 template <typename MutexArg>
238 using DebugLock = UniqueLock<typename std::remove_reference<
239  typename std::remove_pointer<MutexArg>::type>::type>;
240 
241 #define LOCK(cs) \
242  DebugLock<decltype(cs)> PASTE2(criticalblock, \
243  __COUNTER__)(cs, #cs, __FILE__, __LINE__)
244 #define LOCK2(cs1, cs2) \
245  DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
246  DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
247 #define TRY_LOCK(cs, name) \
248  DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
249 #define WAIT_LOCK(cs, name) \
250  DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
251 
252 #define ENTER_CRITICAL_SECTION(cs) \
253  { \
254  EnterCritical(#cs, __FILE__, __LINE__, (void *)(&cs)); \
255  (cs).lock(); \
256  }
257 
258 #define LEAVE_CRITICAL_SECTION(cs) \
259  { \
260  (cs).unlock(); \
261  LeaveCritical(); \
262  }
263 
272 #define WITH_LOCK(cs, code) \
273  [&] { \
274  LOCK(cs); \
275  code; \
276  }()
277 
278 class CSemaphore {
279 private:
280  std::condition_variable condition;
281  std::mutex mutex;
282  int value;
283 
284 public:
285  explicit CSemaphore(int init) : value(init) {}
286 
287  void wait() {
288  std::unique_lock<std::mutex> lock(mutex);
289  condition.wait(lock, [&]() { return value >= 1; });
290  value--;
291  }
292 
293  bool try_wait() {
294  std::lock_guard<std::mutex> lock(mutex);
295  if (value < 1) {
296  return false;
297  }
298  value--;
299  return true;
300  }
301 
302  void post() {
303  {
304  std::lock_guard<std::mutex> lock(mutex);
305  value++;
306  }
307  condition.notify_one();
308  }
309 };
310 
313 private:
316 
317 public:
318  void Acquire() {
319  if (fHaveGrant) {
320  return;
321  }
322  sem->wait();
323  fHaveGrant = true;
324  }
325 
326  void Release() {
327  if (!fHaveGrant) {
328  return;
329  }
330  sem->post();
331  fHaveGrant = false;
332  }
333 
334  bool TryAcquire() {
335  if (!fHaveGrant && sem->try_wait()) {
336  fHaveGrant = true;
337  }
338  return fHaveGrant;
339  }
340 
341  void MoveTo(CSemaphoreGrant &grant) {
342  grant.Release();
343  grant.sem = sem;
344  grant.fHaveGrant = fHaveGrant;
345  fHaveGrant = false;
346  }
347 
348  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
349 
350  explicit CSemaphoreGrant(CSemaphore &sema, bool fTry = false)
351  : sem(&sema), fHaveGrant(false) {
352  if (fTry) {
353  TryAcquire();
354  } else {
355  Acquire();
356  }
357  }
358 
360 
361  operator bool() const { return fHaveGrant; }
362 };
363 
364 #endif // BITCOIN_SYNC_H
CSemaphore::post
void post()
Definition: sync.h:302
UniqueLock::reverse_lock::~reverse_lock
~reverse_lock()
Definition: sync.h:213
UniqueLock::Enter
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:138
EXCLUSIVE_LOCK_FUNCTION
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:49
UNLOCK_FUNCTION
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:53
UniqueLock::reverse_lock::reverse_lock
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition: sync.h:203
CSemaphoreGrant::fHaveGrant
bool fHaveGrant
Definition: sync.h:315
UniqueLock::reverse_lock::line
const int line
Definition: sync.h:228
UniqueLock::reverse_lock::lock
UniqueLock & lock
Definition: sync.h:224
CSemaphoreGrant::MoveTo
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:341
UniqueLock::~UniqueLock
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:184
AnnotatedMixin
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:99
CheckLastCritical
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, const char *file, int line)
Definition: sync.h:76
CSemaphoreGrant::~CSemaphoreGrant
~CSemaphoreGrant()
Definition: sync.h:359
macros.h
DeleteLock
void DeleteLock(void *cs)
Definition: sync.h:86
CSemaphore::condition
std::condition_variable condition
Definition: sync.h:280
UniqueLock::UniqueLock
UniqueLock()
Definition: sync.h:194
UniqueLock::reverse_lock::templock
UniqueLock templock
Definition: sync.h:225
LeaveCritical
void LeaveCritical()
Definition: sync.h:75
CSemaphore::CSemaphore
CSemaphore(int init)
Definition: sync.h:285
cs
static void pool cs
Definition: mempool_eviction.cpp:11
SCOPED_LOCKABLE
#define SCOPED_LOCKABLE
Definition: threadsafety.h:44
CSemaphore
Definition: sync.h:278
CSemaphoreGrant
RAII-style semaphore lock.
Definition: sync.h:312
EnterCritical
void EnterCritical(const char *pszName, const char *pszFile, int nLine, void *cs, bool fTry=false)
Definition: sync.h:73
AnnotatedMixin::unlock
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:105
threadsafety.h
CSemaphore::mutex
std::mutex mutex
Definition: sync.h:281
CSemaphoreGrant::CSemaphoreGrant
CSemaphoreGrant()
Definition: sync.h:348
LOCKABLE
#define LOCKABLE
Definition: threadsafety.h:43
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:334
EXCLUSIVE_TRYLOCK_FUNCTION
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:51
Mutex
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition: sync.h:128
LockStackEmpty
bool LockStackEmpty()
Definition: sync.h:87
UniqueLock::TryEnter
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:150
UniqueLock::reverse_lock::file
const std::string file
Definition: sync.h:227
UniqueLock
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:136
LOCKS_EXCLUDED
#define LOCKS_EXCLUDED(...)
Definition: threadsafety.h:55
AnnotatedMixin::~AnnotatedMixin
~AnnotatedMixin()
Definition: sync.h:101
EXCLUSIVE_LOCKS_REQUIRED
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
CSemaphoreGrant::Acquire
void Acquire()
Definition: sync.h:318
UniqueLock::UniqueLock
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:170
CSemaphore::try_wait
bool try_wait()
Definition: sync.h:293
CSemaphoreGrant::Release
void Release()
Definition: sync.h:326
AnnotatedMixin::lock
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:103
UniqueLock::reverse_lock::lockname
std::string lockname
Definition: sync.h:226
CSemaphoreGrant::CSemaphoreGrant
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:350
AnnotatedMixin::try_lock
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:107
AssertLockNotHeldInternal
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) LOCKS_EXCLUDED(cs)
Definition: sync.h:84
CSemaphore::wait
void wait()
Definition: sync.h:287
CSemaphoreGrant::sem
CSemaphore * sem
Definition: sync.h:314
UniqueLock::UniqueLock
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:160
CSemaphore::value
int value
Definition: sync.h:282
UniqueLock::reverse_lock
An RAII-style reverse lock.
Definition: sync.h:201