Bitcoin Core  0.20.99
P2P Digital Currency
sync.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 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, void* cs, bool fTry = false);
52 void LeaveCritical();
53 void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
54 std::string LocksHeld();
55 template <typename MutexType>
56 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
57 template <typename MutexType>
58 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs);
59 void DeleteLock(void* cs);
60 bool LockStackEmpty();
61 
67 extern bool g_debug_lockorder_abort;
68 #else
69 inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
70 inline void LeaveCritical() {}
71 inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
72 template <typename MutexType>
73 inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
74 template <typename MutexType>
75 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) {}
76 inline void DeleteLock(void* cs) {}
77 inline bool LockStackEmpty() { return true; }
78 #endif
79 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
80 #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
81 
86 template <typename PARENT>
87 class LOCKABLE AnnotatedMixin : public PARENT
88 {
89 public:
91  DeleteLock((void*)this);
92  }
93 
95  {
96  PARENT::lock();
97  }
98 
100  {
101  PARENT::unlock();
102  }
103 
105  {
106  return PARENT::try_lock();
107  }
108 
109  using UniqueLock = std::unique_lock<PARENT>;
110 #ifdef __clang__
111  const AnnotatedMixin& operator!() const { return *this; }
115 #endif // __clang__
116 };
117 
123 
126 
127 #ifdef DEBUG_LOCKCONTENTION
128 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
129 #endif
130 
132 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
133 class SCOPED_LOCKABLE UniqueLock : public Base
134 {
135 private:
136  void Enter(const char* pszName, const char* pszFile, int nLine)
137  {
138  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
139 #ifdef DEBUG_LOCKCONTENTION
140  if (!Base::try_lock()) {
141  PrintLockContention(pszName, pszFile, nLine);
142 #endif
143  Base::lock();
144 #ifdef DEBUG_LOCKCONTENTION
145  }
146 #endif
147  }
148 
149  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
150  {
151  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
152  Base::try_lock();
153  if (!Base::owns_lock())
154  LeaveCritical();
155  return Base::owns_lock();
156  }
157 
158 public:
159  UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
160  {
161  if (fTry)
162  TryEnter(pszName, pszFile, nLine);
163  else
164  Enter(pszName, pszFile, nLine);
165  }
166 
167  UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
168  {
169  if (!pmutexIn) return;
170 
171  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
172  if (fTry)
173  TryEnter(pszName, pszFile, nLine);
174  else
175  Enter(pszName, pszFile, nLine);
176  }
177 
179  {
180  if (Base::owns_lock())
181  LeaveCritical();
182  }
183 
184  operator bool()
185  {
186  return Base::owns_lock();
187  }
188 
189 protected:
190  // needed for reverse_lock
192 
193 public:
197  class reverse_lock {
198  public:
199  explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {
200  CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
201  lock.unlock();
202  LeaveCritical();
203  lock.swap(templock);
204  }
205 
207  templock.swap(lock);
208  EnterCritical(lockname.c_str(), file.c_str(), line, (void*)lock.mutex());
209  lock.lock();
210  }
211 
212  private:
213  reverse_lock(reverse_lock const&);
214  reverse_lock& operator=(reverse_lock const&);
215 
218  std::string lockname;
219  const std::string file;
220  const int line;
221  };
222  friend class reverse_lock;
223 };
224 
225 #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
226 
227 template<typename MutexArg>
229 
230 #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
231 #define LOCK2(cs1, cs2) \
232  DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
233  DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
234 #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
235 #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
236 
237 #define ENTER_CRITICAL_SECTION(cs) \
238  { \
239  EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
240  (cs).lock(); \
241  }
242 
243 #define LEAVE_CRITICAL_SECTION(cs) \
244  { \
245  (cs).unlock(); \
246  LeaveCritical(); \
247  }
248 
257 #define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
258 
260 {
261 private:
262  std::condition_variable condition;
263  std::mutex mutex;
264  int value;
265 
266 public:
267  explicit CSemaphore(int init) : value(init) {}
268 
269  void wait()
270  {
271  std::unique_lock<std::mutex> lock(mutex);
272  condition.wait(lock, [&]() { return value >= 1; });
273  value--;
274  }
275 
276  bool try_wait()
277  {
278  std::lock_guard<std::mutex> lock(mutex);
279  if (value < 1)
280  return false;
281  value--;
282  return true;
283  }
284 
285  void post()
286  {
287  {
288  std::lock_guard<std::mutex> lock(mutex);
289  value++;
290  }
291  condition.notify_one();
292  }
293 };
294 
297 {
298 private:
301 
302 public:
303  void Acquire()
304  {
305  if (fHaveGrant)
306  return;
307  sem->wait();
308  fHaveGrant = true;
309  }
310 
311  void Release()
312  {
313  if (!fHaveGrant)
314  return;
315  sem->post();
316  fHaveGrant = false;
317  }
318 
319  bool TryAcquire()
320  {
321  if (!fHaveGrant && sem->try_wait())
322  fHaveGrant = true;
323  return fHaveGrant;
324  }
325 
326  void MoveTo(CSemaphoreGrant& grant)
327  {
328  grant.Release();
329  grant.sem = sem;
330  grant.fHaveGrant = fHaveGrant;
331  fHaveGrant = false;
332  }
333 
334  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
335 
336  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
337  {
338  if (fTry)
339  TryAcquire();
340  else
341  Acquire();
342  }
343 
345  {
346  Release();
347  }
348 
349  operator bool() const
350  {
351  return fHaveGrant;
352  }
353 };
354 
355 #endif // BITCOIN_SYNC_H
void LeaveCritical()
Definition: sync.h:70
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:326
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:99
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:42
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition: sync.h:199
void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(!cs)
Definition: sync.h:75
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:136
UniqueLock & lock
Definition: sync.h:216
static void pool cs
RAII-style semaphore lock.
Definition: sync.h:296
bool try_wait()
Definition: sync.h:276
UniqueLock templock
Definition: sync.h:217
~AnnotatedMixin()
Definition: sync.h:90
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:94
void Acquire()
Definition: sync.h:303
bool LockStackEmpty()
Definition: sync.h:77
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:46
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:336
void CheckLastCritical(void *cs, std::string &lockname, const char *guardname, const char *file, int line)
Definition: sync.h:71
~CSemaphoreGrant()
Definition: sync.h:344
void DeleteLock(void *cs)
Definition: sync.h:76
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:104
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:167
CSemaphore * sem
Definition: sync.h:299
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:159
int value
Definition: sync.h:264
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:178
void Release()
Definition: sync.h:311
void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, MutexType *cs) EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: sync.h:73
CSemaphoreGrant()
Definition: sync.h:334
void EnterCritical(const char *pszName, const char *pszFile, int nLine, void *cs, bool fTry=false)
Definition: sync.h:69
#define LOCKABLE
Definition: threadsafety.h:36
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
std::condition_variable condition
Definition: sync.h:262
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:87
const std::string file
Definition: sync.h:219
An RAII-style reverse lock.
Definition: sync.h:197
void wait()
Definition: sync.h:269
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:44
std::string lockname
Definition: sync.h:218
#define SCOPED_LOCKABLE
Definition: threadsafety.h:37
CSemaphore(int init)
Definition: sync.h:267
UniqueLock()
Definition: sync.h:191
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:133
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition: sync.h:125
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:149
void post()
Definition: sync.h:285
bool TryAcquire()
Definition: sync.h:319
bool fHaveGrant
Definition: sync.h:300
std::mutex mutex
Definition: sync.h:263