Bitcoin Core  0.19.99
P2P Digital Currency
sync.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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 <thread>
14 #include <mutex>
15 
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 std::string LocksHeld();
54 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs);
55 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
56 void DeleteLock(void* cs);
57 
63 extern bool g_debug_lockorder_abort;
64 #else
65 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
66 void static inline LeaveCritical() {}
67 void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs) {}
68 void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
69 void static inline DeleteLock(void* cs) {}
70 #endif
71 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
72 #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
73 
78 template <typename PARENT>
79 class LOCKABLE AnnotatedMixin : public PARENT
80 {
81 public:
83  DeleteLock((void*)this);
84  }
85 
87  {
88  PARENT::lock();
89  }
90 
92  {
93  PARENT::unlock();
94  }
95 
97  {
98  return PARENT::try_lock();
99  }
100 
101  using UniqueLock = std::unique_lock<PARENT>;
102 };
103 
110 
113 
114 #ifdef DEBUG_LOCKCONTENTION
115 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
116 #endif
117 
119 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
120 class SCOPED_LOCKABLE UniqueLock : public Base
121 {
122 private:
123  void Enter(const char* pszName, const char* pszFile, int nLine)
124  {
125  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
126 #ifdef DEBUG_LOCKCONTENTION
127  if (!Base::try_lock()) {
128  PrintLockContention(pszName, pszFile, nLine);
129 #endif
130  Base::lock();
131 #ifdef DEBUG_LOCKCONTENTION
132  }
133 #endif
134  }
135 
136  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
137  {
138  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
139  Base::try_lock();
140  if (!Base::owns_lock())
141  LeaveCritical();
142  return Base::owns_lock();
143  }
144 
145 public:
146  UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
147  {
148  if (fTry)
149  TryEnter(pszName, pszFile, nLine);
150  else
151  Enter(pszName, pszFile, nLine);
152  }
153 
154  UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
155  {
156  if (!pmutexIn) return;
157 
158  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
159  if (fTry)
160  TryEnter(pszName, pszFile, nLine);
161  else
162  Enter(pszName, pszFile, nLine);
163  }
164 
166  {
167  if (Base::owns_lock())
168  LeaveCritical();
169  }
170 
171  operator bool()
172  {
173  return Base::owns_lock();
174  }
175 };
176 
177 template<typename MutexArg>
179 
180 #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
181 #define LOCK2(cs1, cs2) \
182  DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
183  DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
184 #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
185 #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
186 
187 #define ENTER_CRITICAL_SECTION(cs) \
188  { \
189  EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
190  (cs).lock(); \
191  }
192 
193 #define LEAVE_CRITICAL_SECTION(cs) \
194  { \
195  (cs).unlock(); \
196  LeaveCritical(); \
197  }
198 
207 #define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
208 
210 {
211 private:
212  std::condition_variable condition;
213  std::mutex mutex;
214  int value;
215 
216 public:
217  explicit CSemaphore(int init) : value(init) {}
218 
219  void wait()
220  {
221  std::unique_lock<std::mutex> lock(mutex);
222  condition.wait(lock, [&]() { return value >= 1; });
223  value--;
224  }
225 
226  bool try_wait()
227  {
228  std::lock_guard<std::mutex> lock(mutex);
229  if (value < 1)
230  return false;
231  value--;
232  return true;
233  }
234 
235  void post()
236  {
237  {
238  std::lock_guard<std::mutex> lock(mutex);
239  value++;
240  }
241  condition.notify_one();
242  }
243 };
244 
247 {
248 private:
251 
252 public:
253  void Acquire()
254  {
255  if (fHaveGrant)
256  return;
257  sem->wait();
258  fHaveGrant = true;
259  }
260 
261  void Release()
262  {
263  if (!fHaveGrant)
264  return;
265  sem->post();
266  fHaveGrant = false;
267  }
268 
269  bool TryAcquire()
270  {
271  if (!fHaveGrant && sem->try_wait())
272  fHaveGrant = true;
273  return fHaveGrant;
274  }
275 
276  void MoveTo(CSemaphoreGrant& grant)
277  {
278  grant.Release();
279  grant.sem = sem;
280  grant.fHaveGrant = fHaveGrant;
281  fHaveGrant = false;
282  }
283 
284  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
285 
286  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
287  {
288  if (fTry)
289  TryAcquire();
290  else
291  Acquire();
292  }
293 
295  {
296  Release();
297  }
298 
299  operator bool() const
300  {
301  return fHaveGrant;
302  }
303 };
304 
305 // Utility class for indicating to compiler thread analysis that a mutex is
306 // locked (when it couldn't be determined otherwise).
308 {
309  template <typename Mutex>
311  {
312 #ifdef DEBUG_LOCKORDER
313  AssertLockHeld(mutex);
314 #endif
315  }
317 };
318 
319 #endif // BITCOIN_SYNC_H
static void AssertLockHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs) ASSERT_EXCLUSIVE_LOCK(cs)
Definition: sync.h:67
static void AssertLockNotHeldInternal(const char *pszName, const char *pszFile, int nLine, void *cs)
Definition: sync.h:68
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:276
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:91
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:44
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:123
static void pool cs
AnnotatedMixin< std::recursive_mutex > CCriticalSection
Definition: sync.h:109
RAII-style semaphore lock.
Definition: sync.h:246
bool try_wait()
Definition: sync.h:226
~AnnotatedMixin()
Definition: sync.h:82
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:86
void Acquire()
Definition: sync.h:253
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:48
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:286
#define AssertLockHeld(cs)
Definition: sync.h:71
~CSemaphoreGrant()
Definition: sync.h:294
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:96
static void DeleteLock(void *cs)
Definition: sync.h:69
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:154
CSemaphore * sem
Definition: sync.h:249
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:146
int value
Definition: sync.h:214
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:165
void Release()
Definition: sync.h:261
static void EnterCritical(const char *pszName, const char *pszFile, int nLine, void *cs, bool fTry=false)
Definition: sync.h:65
static void LeaveCritical()
Definition: sync.h:66
CSemaphoreGrant()
Definition: sync.h:284
#define LOCKABLE
Definition: threadsafety.h:36
std::condition_variable condition
Definition: sync.h:212
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:79
~LockAssertion() UNLOCK_FUNCTION()
Definition: sync.h:316
void wait()
Definition: sync.h:219
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:46
#define SCOPED_LOCKABLE
Definition: threadsafety.h:37
CSemaphore(int init)
Definition: sync.h:217
LockAssertion(Mutex &mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
Definition: sync.h:310
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:120
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition: sync.h:112
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:136
void post()
Definition: sync.h:235
bool TryAcquire()
Definition: sync.h:269
bool fHaveGrant
Definition: sync.h:250
#define ASSERT_EXCLUSIVE_LOCK(...)
Definition: threadsafety.h:54
std::mutex mutex
Definition: sync.h:213