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