Dogecoin Core  1.14.2
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 // 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 <boost/thread/condition_variable.hpp>
12 #include <boost/thread/locks.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 
103 
105 typedef boost::condition_variable CConditionVariable;
106 
107 #ifdef DEBUG_LOCKCONTENTION
108 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
109 #endif
110 
112 template <typename Mutex>
114 {
115 private:
116  boost::unique_lock<Mutex> lock;
117 
118  void Enter(const char* pszName, const char* pszFile, int nLine)
119  {
120  EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
121 #ifdef DEBUG_LOCKCONTENTION
122  if (!lock.try_lock()) {
123  PrintLockContention(pszName, pszFile, nLine);
124 #endif
125  lock.lock();
126 #ifdef DEBUG_LOCKCONTENTION
127  }
128 #endif
129  }
130 
131  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
132  {
133  EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
134  lock.try_lock();
135  if (!lock.owns_lock())
136  LeaveCritical();
137  return lock.owns_lock();
138  }
139 
140 public:
141  CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
142  {
143  if (fTry)
144  TryEnter(pszName, pszFile, nLine);
145  else
146  Enter(pszName, pszFile, nLine);
147  }
148 
149  CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
150  {
151  if (!pmutexIn) return;
152 
153  lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
154  if (fTry)
155  TryEnter(pszName, pszFile, nLine);
156  else
157  Enter(pszName, pszFile, nLine);
158  }
159 
161  {
162  if (lock.owns_lock())
163  LeaveCritical();
164  }
165 
166  operator bool()
167  {
168  return lock.owns_lock();
169  }
170 };
171 
173 
174 #define PASTE(x, y) x ## y
175 #define PASTE2(x, y) PASTE(x, y)
176 
177 #define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
178 #define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
179 #define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
180 
181 #define ENTER_CRITICAL_SECTION(cs) \
182  { \
183  EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
184  (cs).lock(); \
185  }
186 
187 #define LEAVE_CRITICAL_SECTION(cs) \
188  { \
189  (cs).unlock(); \
190  LeaveCritical(); \
191  }
192 
194 {
195 private:
196  boost::condition_variable condition;
197  boost::mutex mutex;
198  int value;
199 
200 public:
201  CSemaphore(int init) : value(init) {}
202 
203  void wait()
204  {
205  boost::unique_lock<boost::mutex> lock(mutex);
206  while (value < 1) {
207  condition.wait(lock);
208  }
209  value--;
210  }
211 
212  bool try_wait()
213  {
214  boost::unique_lock<boost::mutex> lock(mutex);
215  if (value < 1)
216  return false;
217  value--;
218  return true;
219  }
220 
221  void post()
222  {
223  {
224  boost::unique_lock<boost::mutex> lock(mutex);
225  value++;
226  }
227  condition.notify_one();
228  }
229 };
230 
233 {
234 private:
237 
238 public:
239  void Acquire()
240  {
241  if (fHaveGrant)
242  return;
243  sem->wait();
244  fHaveGrant = true;
245  }
246 
247  void Release()
248  {
249  if (!fHaveGrant)
250  return;
251  sem->post();
252  fHaveGrant = false;
253  }
254 
255  bool TryAcquire()
256  {
257  if (!fHaveGrant && sem->try_wait())
258  fHaveGrant = true;
259  return fHaveGrant;
260  }
261 
262  void MoveTo(CSemaphoreGrant& grant)
263  {
264  grant.Release();
265  grant.sem = sem;
266  grant.fHaveGrant = fHaveGrant;
267  fHaveGrant = false;
268  }
269 
270  CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
271 
272  CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
273  {
274  if (fTry)
275  TryAcquire();
276  else
277  Acquire();
278  }
279 
281  {
282  Release();
283  }
284 
285  operator bool()
286  {
287  return fHaveGrant;
288  }
289 };
290 
291 #endif // BITCOIN_SYNC_H
Template mixin that adds -Wthread-safety locking annotations to a subset of the mutex API.
Definition: sync.h:56
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:68
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:63
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:58
Wrapped boost mutex: supports recursive locking, but no waiting TODO: We should move away from using ...
Definition: sync.h:93
~CCriticalSection()
Definition: sync.h:95
Wrapper around boost::unique_lock<Mutex>
Definition: sync.h:114
boost::unique_lock< Mutex > lock
Definition: sync.h:116
CMutexLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:149
CMutexLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:141
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:118
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:131
~CMutexLock() UNLOCK_FUNCTION()
Definition: sync.h:160
RAII-style semaphore lock.
Definition: sync.h:233
bool fHaveGrant
Definition: sync.h:236
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:272
CSemaphoreGrant()
Definition: sync.h:270
void Release()
Definition: sync.h:247
bool TryAcquire()
Definition: sync.h:255
~CSemaphoreGrant()
Definition: sync.h:280
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:262
void Acquire()
Definition: sync.h:239
CSemaphore * sem
Definition: sync.h:235
void wait()
Definition: sync.h:203
int value
Definition: sync.h:198
bool try_wait()
Definition: sync.h:212
boost::mutex mutex
Definition: sync.h:197
CSemaphore(int init)
Definition: sync.h:201
void post()
Definition: sync.h:221
boost::condition_variable condition
Definition: sync.h:196
AnnotatedMixin< boost::mutex > CWaitableCriticalSection
Wrapped boost mutex: supports waiting but not recursive locking.
Definition: sync.h:102
CMutexLock< CCriticalSection > CCriticalBlock
Definition: sync.h:172
boost::condition_variable CConditionVariable
Just a typedef for boost::condition_variable, can be wrapped later if desired.
Definition: sync.h:105
CCriticalSection CDynamicCriticalSection
Definition: sync.h:100
#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