BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
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 CCriticalSection 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 
108 
111 
112 #ifdef DEBUG_LOCKCONTENTION
113 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
114 #endif
115 
117 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
118 class SCOPED_LOCKABLE UniqueLock : public Base
119 {
120 private:
121  void Enter(const char* pszName, const char* pszFile, int nLine)
122  {
123  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
124 #ifdef DEBUG_LOCKCONTENTION
125  if (!Base::try_lock()) {
126  PrintLockContention(pszName, pszFile, nLine);
127 #endif
128  Base::lock();
129 #ifdef DEBUG_LOCKCONTENTION
130  }
131 #endif
132  }
133 
134  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
135  {
136  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
137  Base::try_lock();
138  if (!Base::owns_lock())
139  LeaveCritical();
140  return Base::owns_lock();
141  }
142 
143 public:
144  UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
145  {
146  if (fTry)
147  TryEnter(pszName, pszFile, nLine);
148  else
149  Enter(pszName, pszFile, nLine);
150  }
151 
152  UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
153  {
154  if (!pmutexIn) return;
155 
156  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
157  if (fTry)
158  TryEnter(pszName, pszFile, nLine);
159  else
160  Enter(pszName, pszFile, nLine);
161  }
162 
164  {
165  if (Base::owns_lock())
166  LeaveCritical();
167  }
168 
169  operator bool()
170  {
171  return Base::owns_lock();
172  }
173 };
174 
175 template<typename MutexArg>
177 
178 #define PASTE(x, y) x ## y
179 #define PASTE2(x, y) PASTE(x, y)
180 
181 #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
182 #define LOCK2(cs1, cs2) \
183  DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
184  DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
185 #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
186 #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
187 
188 #define ENTER_CRITICAL_SECTION(cs) \
189  { \
190  EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
191  (cs).lock(); \
192  }
193 
194 #define LEAVE_CRITICAL_SECTION(cs) \
195  { \
196  (cs).unlock(); \
197  LeaveCritical(); \
198  }
199 
201 {
202 private:
203  std::condition_variable condition;
204  std::mutex mutex;
205  int value;
206 
207 public:
208  explicit CSemaphore(int init) : value(init) {}
209 
210  void wait()
211  {
212  std::unique_lock<std::mutex> lock(mutex);
213  condition.wait(lock, [&]() { return value >= 1; });
214  value--;
215  }
216 
217  bool try_wait()
218  {
219  std::lock_guard<std::mutex> lock(mutex);
220  if (value < 1)
221  return false;
222  value--;
223  return true;
224  }
225 
226  void post()
227  {
228  {
229  std::lock_guard<std::mutex> lock(mutex);
230  value++;
231  }
232  condition.notify_one();
233  }
234 };
235 
238 {
239 private:
242 
243 public:
244  void Acquire()
245  {
246  if (fHaveGrant)
247  return;
248  sem->wait();
249  fHaveGrant = true;
250  }
251 
252  void Release()
253  {
254  if (!fHaveGrant)
255  return;
256  sem->post();
257  fHaveGrant = false;
258  }
259 
260  bool TryAcquire()
261  {
262  if (!fHaveGrant && sem->try_wait())
263  fHaveGrant = true;
264  return fHaveGrant;
265  }
266 
267  void MoveTo(CSemaphoreGrant& grant)
268  {
269  grant.Release();
270  grant.sem = sem;
271  grant.fHaveGrant = fHaveGrant;
272  fHaveGrant = false;
273  }
274 
275  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
276 
277  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
278  {
279  if (fTry)
280  TryAcquire();
281  else
282  Acquire();
283  }
284 
286  {
287  Release();
288  }
289 
290  operator bool() const
291  {
292  return fHaveGrant;
293  }
294 };
295 
296 #endif // BITCOIN_SYNC_H
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:267
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:121
AnnotatedMixin< std::recursive_mutex > CCriticalSection
Wrapped mutex: supports recursive locking, but no waiting TODO: We should move away from using the re...
Definition: sync.h:107
RAII-style semaphore lock.
Definition: sync.h:237
bool try_wait()
Definition: sync.h:217
~AnnotatedMixin()
Definition: sync.h:81
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:85
void Acquire()
Definition: sync.h:244
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:48
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:277
~CSemaphoreGrant()
Definition: sync.h:285
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:95
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:152
CSemaphore * sem
Definition: sync.h:240
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:144
int value
Definition: sync.h:205
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:163
void Release()
Definition: sync.h:252
CSemaphoreGrant()
Definition: sync.h:275
#define LOCKABLE
Definition: threadsafety.h:36
std::condition_variable condition
Definition: sync.h:203
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:78
void wait()
Definition: sync.h:210
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:46
#define SCOPED_LOCKABLE
Definition: threadsafety.h:37
CSemaphore(int init)
Definition: sync.h:208
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:118
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition: sync.h:110
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:134
void post()
Definition: sync.h:226
bool TryAcquire()
Definition: sync.h:260
bool fHaveGrant
Definition: sync.h:241
#define ASSERT_EXCLUSIVE_LOCK(...)
Definition: threadsafety.h:54
std::mutex mutex
Definition: sync.h:204