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