PIVX Core  5.6.99
P2P Digital Currency
sync.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2017 The Bitcoin developers
3 // Copyright (c) 2017-2020 The PIVX Core developers
4 // Distributed under the MIT/X11 software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #ifndef PIVX_SYNC_H
8 #define PIVX_SYNC_H
9 
10 #include "threadsafety.h"
11 #include "util/macros.h"
12 
13 #include <condition_variable>
14 #include <mutex>
15 #include <string>
16 #include <thread>
17 
18 
20 // //
21 // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
22 // //
24 
25 /*
26 RecursiveMutex mutex;
27  std::recursive_mutex mutex;
28 
29 LOCK(mutex);
30  std::unique_lock<std::recursive_mutex> criticalblock(mutex);
31 
32 LOCK2(mutex1, mutex2);
33  std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
34  std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
35 
36 TRY_LOCK(mutex, name);
37  std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
38 
39 ENTER_CRITICAL_SECTION(mutex); // no RAII
40  mutex.lock();
41 
42 LEAVE_CRITICAL_SECTION(mutex); // no RAII
43  mutex.unlock();
44  */
45 
47 // //
48 // THE ACTUAL IMPLEMENTATION //
49 // //
51 
52 #ifdef DEBUG_LOCKORDER
53 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
54 void LeaveCritical();
55 void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
56 std::string LocksHeld();
57 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
58 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
59 void DeleteLock(void* cs);
60 
66 extern bool g_debug_lockorder_abort;
67 #else
68 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
69 void static inline LeaveCritical() {}
70 void static inline CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
71 void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
72 void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
73 void static inline DeleteLock(void* cs) {}
74 #endif
75 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
76 #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
77 
82 template <typename PARENT>
83 class LOCKABLE AnnotatedMixin : public PARENT
84 {
85 public:
87  DeleteLock((void*)this);
88  }
89 
91  {
92  PARENT::lock();
93  }
94 
96  {
97  PARENT::unlock();
98  }
99 
101  {
102  return PARENT::try_lock();
103  }
104 
105  using UniqueLock = std::unique_lock<PARENT>;
106 };
107 
113 
116 
117 #ifdef DEBUG_LOCKCONTENTION
118 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
119 #endif
120 
122 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
123 class SCOPED_LOCKABLE UniqueLock : public Base
124 {
125 private:
126  void Enter(const char* pszName, const char* pszFile, int nLine)
127  {
128  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
129 #ifdef DEBUG_LOCKCONTENTION
130  if (!Base::try_lock()) {
131  PrintLockContention(pszName, pszFile, nLine);
132 #endif
133  Base::lock();
134 #ifdef DEBUG_LOCKCONTENTION
135  }
136 #endif
137  }
138 
139  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
140  {
141  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
142  Base::try_lock();
143  if (!Base::owns_lock())
144  LeaveCritical();
145  return Base::owns_lock();
146  }
147 
148 public:
149  UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
150  {
151  if (fTry)
152  TryEnter(pszName, pszFile, nLine);
153  else
154  Enter(pszName, pszFile, nLine);
155  }
156 
157  UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
158  {
159  if (!pmutexIn) return;
160 
161  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
162  if (fTry)
163  TryEnter(pszName, pszFile, nLine);
164  else
165  Enter(pszName, pszFile, nLine);
166  }
167 
169  {
170  if (Base::owns_lock())
171  LeaveCritical();
172  }
173 
174  operator bool()
175  {
176  return Base::owns_lock();
177  }
178 
179 protected:
180  // needed for reverse_lock
182 
183 public:
187  class reverse_lock {
188  public:
189  explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {
190  CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
191  lock.unlock();
192  LeaveCritical();
193  lock.swap(templock);
194  }
195 
197  templock.swap(lock);
198  EnterCritical(lockname.c_str(), file.c_str(), line, (void*)lock.mutex());
199  lock.lock();
200  }
201 
202  private:
205 
208  std::string lockname;
209  const std::string file;
210  const int line;
211  };
212  friend class reverse_lock;
213 };
214 
215 #define REVERSE_LOCK(g) decltype(g)::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
216 
217 template<typename MutexArg>
219 
220 #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
221 #define LOCK2(cs1, cs2) \
222  DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
223  DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
224 #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
225 #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
226 
227 #define ENTER_CRITICAL_SECTION(cs) \
228  { \
229  EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
230  (cs).lock(); \
231  }
232 
233 #define LEAVE_CRITICAL_SECTION(cs) \
234  { \
235  (cs).unlock(); \
236  LeaveCritical(); \
237  }
238 
247 #define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
248 
250 {
251 private:
252  std::condition_variable condition;
253  std::mutex mutex;
254  int value;
255 
256 public:
257  explicit CSemaphore(int init) : value(init) {}
258 
259  void wait()
260  {
261  std::unique_lock<std::mutex> lock(mutex);
262  condition.wait(lock, [&]() { return value >= 1; });
263  value--;
264  }
265 
266  bool try_wait()
267  {
268  std::lock_guard<std::mutex> lock(mutex);
269  if (value < 1)
270  return false;
271  value--;
272  return true;
273  }
274 
275  void post()
276  {
277  {
278  std::lock_guard<std::mutex> lock(mutex);
279  value++;
280  }
281  condition.notify_one();
282  }
283 };
284 
287 {
288 private:
291 
292 public:
293  void Acquire()
294  {
295  if (fHaveGrant)
296  return;
297  sem->wait();
298  fHaveGrant = true;
299  }
300 
301  void Release()
302  {
303  if (!fHaveGrant)
304  return;
305  sem->post();
306  fHaveGrant = false;
307  }
308 
309  bool TryAcquire()
310  {
311  if (!fHaveGrant && sem->try_wait())
312  fHaveGrant = true;
313  return fHaveGrant;
314  }
315 
316  void MoveTo(CSemaphoreGrant& grant)
317  {
318  grant.Release();
319  grant.sem = sem;
320  grant.fHaveGrant = fHaveGrant;
321  fHaveGrant = false;
322  }
323 
325 
326  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
327  {
328  if (fTry)
329  TryAcquire();
330  else
331  Acquire();
332  }
333 
335  {
336  Release();
337  }
338 
339  operator bool() const
340  {
341  return fHaveGrant;
342  }
343 };
344 
345 #endif // PIVX_SYNC_H
true
Definition: bls_dkg.cpp:153
false
Definition: bls_dkg.cpp:151
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:84
~AnnotatedMixin()
Definition: sync.h:86
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:100
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:95
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:90
RAII-style semaphore lock.
Definition: sync.h:287
bool fHaveGrant
Definition: sync.h:290
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:326
CSemaphoreGrant()
Definition: sync.h:324
void Release()
Definition: sync.h:301
bool TryAcquire()
Definition: sync.h:309
~CSemaphoreGrant()
Definition: sync.h:334
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:316
void Acquire()
Definition: sync.h:293
CSemaphore * sem
Definition: sync.h:289
void wait()
Definition: sync.h:259
int value
Definition: sync.h:254
std::mutex mutex
Definition: sync.h:253
bool try_wait()
Definition: sync.h:266
CSemaphore(int init)
Definition: sync.h:257
std::condition_variable condition
Definition: sync.h:252
void post()
Definition: sync.h:275
An RAII-style reverse lock.
Definition: sync.h:187
reverse_lock(reverse_lock const &)
reverse_lock & operator=(reverse_lock const &)
std::string lockname
Definition: sync.h:208
const std::string file
Definition: sync.h:209
UniqueLock templock
Definition: sync.h:207
UniqueLock & lock
Definition: sync.h:206
reverse_lock(UniqueLock &_lock, const char *_guardname, const char *_file, int _line)
Definition: sync.h:189
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:124
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:139
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:168
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:149
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:126
UniqueLock()
Definition: sync.h:181
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:157
Definition: uint256.h:212
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition: sync.h:115
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:45
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:43
#define SCOPED_LOCKABLE
Definition: threadsafety.h:36
#define LOCKABLE
Definition: threadsafety.h:35
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:47