Raven Core  3.0.0
P2P Digital Currency
sync.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 The Bitcoin Core developers
3 // Copyright (c) 2017-2019 The Raven Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #ifndef RAVEN_SYNC_H
8 #define RAVEN_SYNC_H
9 
10 #include "threadsafety.h"
11 
12 #include <boost/thread/condition_variable.hpp>
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/recursive_mutex.hpp>
15 
16 
18 // //
19 // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
20 // //
22 
23 /*
24 CCriticalSection mutex;
25  boost::recursive_mutex mutex;
26 
27 LOCK(mutex);
28  boost::unique_lock<boost::recursive_mutex> criticalblock(mutex);
29 
30 LOCK2(mutex1, mutex2);
31  boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1);
32  boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2);
33 
34 TRY_LOCK(mutex, name);
35  boost::unique_lock<boost::recursive_mutex> name(mutex, boost::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 
54 template <typename PARENT>
55 class LOCKABLE AnnotatedMixin : public PARENT
56 {
57 public:
59  {
60  PARENT::lock();
61  }
62 
64  {
65  PARENT::unlock();
66  }
67 
69  {
70  return PARENT::try_lock();
71  }
72 };
73 
74 #ifdef DEBUG_LOCKORDER
75 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
76 void LeaveCritical();
77 std::string LocksHeld();
78 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
79 void DeleteLock(void* cs);
80 #else
81 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
82 void static inline LeaveCritical() {}
83 void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
84 void static inline DeleteLock(void* cs) {}
85 #endif
86 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
87 
92 class CCriticalSection : public AnnotatedMixin<boost::recursive_mutex>
93 {
94 public:
96  DeleteLock((void*)this);
97  }
98 };
99 
102 
104 typedef boost::condition_variable CConditionVariable;
105 
106 #ifdef DEBUG_LOCKCONTENTION
107 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
108 #endif
109 
111 template <typename Mutex>
113 {
114 private:
115  boost::unique_lock<Mutex> lock;
116 
117  void Enter(const char* pszName, const char* pszFile, int nLine)
118  {
119  EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
120 #ifdef DEBUG_LOCKCONTENTION
121  if (!lock.try_lock()) {
122  PrintLockContention(pszName, pszFile, nLine);
123 #endif
124  lock.lock();
125 #ifdef DEBUG_LOCKCONTENTION
126  }
127 #endif
128  }
129 
130  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
131  {
132  EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
133  lock.try_lock();
134  if (!lock.owns_lock())
135  LeaveCritical();
136  return lock.owns_lock();
137  }
138 
139 public:
140  CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
141  {
142  if (fTry)
143  TryEnter(pszName, pszFile, nLine);
144  else
145  Enter(pszName, pszFile, nLine);
146  }
147 
148  CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
149  {
150  if (!pmutexIn) return;
151 
152  lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
153  if (fTry)
154  TryEnter(pszName, pszFile, nLine);
155  else
156  Enter(pszName, pszFile, nLine);
157  }
158 
160  {
161  if (lock.owns_lock())
162  LeaveCritical();
163  }
164 
165  operator bool()
166  {
167  return lock.owns_lock();
168  }
169 };
170 
172 
173 #define PASTE(x, y) x ## y
174 #define PASTE2(x, y) PASTE(x, y)
175 
176 #define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
177 #define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
178 #define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
179 
180 #define ENTER_CRITICAL_SECTION(cs) \
181  { \
182  EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
183  (cs).lock(); \
184  }
185 
186 #define LEAVE_CRITICAL_SECTION(cs) \
187  { \
188  (cs).unlock(); \
189  LeaveCritical(); \
190  }
191 
193 {
194 private:
195  boost::condition_variable condition;
196  boost::mutex mutex;
197  int value;
198 
199 public:
200  explicit CSemaphore(int init) : value(init) {}
201 
202  void wait()
203  {
204  boost::unique_lock<boost::mutex> lock(mutex);
205  while (value < 1) {
206  condition.wait(lock);
207  }
208  value--;
209  }
210 
211  bool try_wait()
212  {
213  boost::unique_lock<boost::mutex> lock(mutex);
214  if (value < 1)
215  return false;
216  value--;
217  return true;
218  }
219 
220  void post()
221  {
222  {
223  boost::unique_lock<boost::mutex> lock(mutex);
224  value++;
225  }
226  condition.notify_one();
227  }
228 };
229 
232 {
233 private:
236 
237 public:
238  void Acquire()
239  {
240  if (fHaveGrant)
241  return;
242  sem->wait();
243  fHaveGrant = true;
244  }
245 
246  void Release()
247  {
248  if (!fHaveGrant)
249  return;
250  sem->post();
251  fHaveGrant = false;
252  }
253 
254  bool TryAcquire()
255  {
256  if (!fHaveGrant && sem->try_wait())
257  fHaveGrant = true;
258  return fHaveGrant;
259  }
260 
261  void MoveTo(CSemaphoreGrant& grant)
262  {
263  grant.Release();
264  grant.sem = sem;
265  grant.fHaveGrant = fHaveGrant;
266  fHaveGrant = false;
267  }
268 
269  CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
270 
271  explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
272  {
273  if (fTry)
274  TryAcquire();
275  else
276  Acquire();
277  }
278 
280  {
281  Release();
282  }
283 
284  operator bool() const
285  {
286  return fHaveGrant;
287  }
288 };
289 
290 #endif // RAVEN_SYNC_H
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:261
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:63
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:44
boost::condition_variable CConditionVariable
Just a typedef for boost::condition_variable, can be wrapped later if desired.
Definition: sync.h:104
CMutexLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:140
CMutexLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:148
Definition: init.h:16
~CMutexLock() UNLOCK_FUNCTION()
Definition: sync.h:159
RAII-style semaphore lock.
Definition: sync.h:231
CMutexLock< CCriticalSection > CCriticalBlock
Definition: sync.h:171
bool try_wait()
Definition: sync.h:211
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:58
void Acquire()
Definition: sync.h:238
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:48
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:271
~CSemaphoreGrant()
Definition: sync.h:279
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:117
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:68
AnnotatedMixin< boost::mutex > CWaitableCriticalSection
Wrapped boost mutex: supports waiting but not recursive locking.
Definition: sync.h:101
CSemaphore * sem
Definition: sync.h:234
int value
Definition: sync.h:197
void Release()
Definition: sync.h:246
Wrapper around boost::unique_lock<Mutex>
Definition: sync.h:112
CSemaphoreGrant()
Definition: sync.h:269
boost::mutex mutex
Definition: sync.h:196
#define LOCKABLE
Definition: threadsafety.h:36
Template mixin that adds -Wthread-safety locking annotations to a subset of the mutex API...
Definition: sync.h:55
boost::condition_variable condition
Definition: sync.h:195
void wait()
Definition: sync.h:202
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:130
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:46
#define SCOPED_LOCKABLE
Definition: threadsafety.h:37
CSemaphore(int init)
Definition: sync.h:200
void post()
Definition: sync.h:220
bool TryAcquire()
Definition: sync.h:254
~CCriticalSection()
Definition: sync.h:95
bool fHaveGrant
Definition: sync.h:235
boost::unique_lock< Mutex > lock
Definition: sync.h:115
Wrapped boost mutex: supports recursive locking, but no waiting TODO: We should move away from using ...
Definition: sync.h:92