PRCYCoin  2.0.0.7rc1
P2P Digital Currency
sync.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2013 The Bitcoin developers
3 // Distributed under the MIT/X11 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 #include "util/macros.h"
11 
12 #include <condition_variable>
13 #include <thread>
14 #include <mutex>
15 
16 
18 // //
19 // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
20 // //
22 
23 /*
24 RecursiveMutex mutex;
25  std::recursive_mutex mutex;
26 
27 LOCK(mutex);
28  std::unique_lock<std::recursive_mutex> criticalblock(mutex);
29 
30 LOCK2(mutex1, mutex2);
31  std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
32  std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
33 
34 TRY_LOCK(mutex, name);
35  std::unique_lock<std::recursive_mutex> name(mutex, std::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 
50 #ifdef DEBUG_LOCKORDER
51 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
52 void LeaveCritical();
53 std::string LocksHeld();
54 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
55 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
56 void DeleteLock(void* cs);
57 
63 extern bool g_debug_lockorder_abort;
64 #else
65 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
66 void static inline LeaveCritical() {}
67 void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
68 void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
69 void static inline DeleteLock(void* cs) {}
70 #endif
71 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
72 #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
73 
78 template <typename PARENT>
79 class LOCKABLE AnnotatedMixin : public PARENT
80 {
81 public:
83  DeleteLock((void*)this);
84  }
85 
87  {
88  PARENT::lock();
89  }
90 
92  {
93  PARENT::unlock();
94  }
95 
97  {
98  return PARENT::try_lock();
99  }
100 
101  using UniqueLock = std::unique_lock<PARENT>;
102 };
103 
109 
112 
114 typedef std::unique_lock<std::mutex> WaitableLock;
115 
116 #ifdef DEBUG_LOCKCONTENTION
117 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
118 #endif
119 
121 template <typename Mutex, typename Base = typename Mutex::UniqueLock>
122 class SCOPED_LOCKABLE UniqueLock : public Base
123 {
124 private:
125  void Enter(const char* pszName, const char* pszFile, int nLine)
126  {
127  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
128 #ifdef DEBUG_LOCKCONTENTION
129  if (!Base::try_lock()) {
130  PrintLockContention(pszName, pszFile, nLine);
131 #endif
132  Base::lock();
133 #ifdef DEBUG_LOCKCONTENTION
134  }
135 #endif
136  }
137 
138  bool TryEnter(const char* pszName, const char* pszFile, int nLine)
139  {
140  EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
141  Base::try_lock();
142  if (!Base::owns_lock())
143  LeaveCritical();
144  return Base::owns_lock();
145  }
146 
147 public:
148  UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
149  {
150  if (fTry)
151  TryEnter(pszName, pszFile, nLine);
152  else
153  Enter(pszName, pszFile, nLine);
154  }
155 
156  UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
157  {
158  if (!pmutexIn) return;
159 
160  *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
161  if (fTry)
162  TryEnter(pszName, pszFile, nLine);
163  else
164  Enter(pszName, pszFile, nLine);
165  }
166 
168  {
169  if (Base::owns_lock())
170  LeaveCritical();
171  }
172 
173  operator bool()
174  {
175  return Base::owns_lock();
176  }
177 };
178 
179 template<typename MutexArg>
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 #endif // BITCOIN_SYNC_H
CSemaphore::post
void post()
Definition: sync.h:237
UniqueLock::Enter
void Enter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:125
EXCLUSIVE_LOCK_FUNCTION
#define EXCLUSIVE_LOCK_FUNCTION(...)
Definition: threadsafety.h:43
UNLOCK_FUNCTION
#define UNLOCK_FUNCTION(...)
Definition: threadsafety.h:47
CSemaphoreGrant::fHaveGrant
bool fHaveGrant
Definition: sync.h:252
CSemaphoreGrant::MoveTo
void MoveTo(CSemaphoreGrant &grant)
Definition: sync.h:278
UniqueLock::~UniqueLock
~UniqueLock() UNLOCK_FUNCTION()
Definition: sync.h:167
AnnotatedMixin
Template mixin that adds -Wthread-safety locking annotations and lock order checking to a subset of t...
Definition: sync.h:79
CSemaphoreGrant::~CSemaphoreGrant
~CSemaphoreGrant()
Definition: sync.h:296
macros.h
CSemaphore::condition
std::condition_variable condition
Definition: sync.h:214
CSemaphore::CSemaphore
CSemaphore(int init)
Definition: sync.h:219
SCOPED_LOCKABLE
#define SCOPED_LOCKABLE
Definition: threadsafety.h:36
CSemaphore
Definition: sync.h:211
CSemaphoreGrant
RAII-style semaphore lock.
Definition: sync.h:248
AnnotatedMixin::unlock
void unlock() UNLOCK_FUNCTION()
Definition: sync.h:91
threadsafety.h
CSemaphore::mutex
std::mutex mutex
Definition: sync.h:215
CSemaphoreGrant::CSemaphoreGrant
CSemaphoreGrant()
Definition: sync.h:286
LOCKABLE
#define LOCKABLE
Definition: threadsafety.h:35
CSemaphoreGrant::TryAcquire
bool TryAcquire()
Definition: sync.h:271
EXCLUSIVE_TRYLOCK_FUNCTION
#define EXCLUSIVE_TRYLOCK_FUNCTION(...)
Definition: threadsafety.h:45
WaitableLock
std::unique_lock< std::mutex > WaitableLock
Just a typedef for std::unique_lock, can be wrapped later if desired.
Definition: sync.h:114
Mutex
AnnotatedMixin< std::mutex > Mutex
Wrapped mutex: supports waiting but not recursive locking.
Definition: sync.h:111
UniqueLock::TryEnter
bool TryEnter(const char *pszName, const char *pszFile, int nLine)
Definition: sync.h:138
UniqueLock
Wrapper around std::unique_lock style lock for Mutex.
Definition: sync.h:122
AnnotatedMixin::~AnnotatedMixin
~AnnotatedMixin()
Definition: sync.h:82
CSemaphoreGrant::Acquire
void Acquire()
Definition: sync.h:255
UniqueLock::UniqueLock
UniqueLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
Definition: sync.h:156
std
Definition: adjacency_graphs.hpp:25
CSemaphore::try_wait
bool try_wait()
Definition: sync.h:228
CSemaphoreGrant::Release
void Release()
Definition: sync.h:263
AnnotatedMixin::lock
void lock() EXCLUSIVE_LOCK_FUNCTION()
Definition: sync.h:86
CSemaphoreGrant::CSemaphoreGrant
CSemaphoreGrant(CSemaphore &sema, bool fTry=false)
Definition: sync.h:288
AnnotatedMixin::try_lock
bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
Definition: sync.h:96
CSemaphore::wait
void wait()
Definition: sync.h:221
CSemaphoreGrant::sem
CSemaphore * sem
Definition: sync.h:251
UniqueLock::UniqueLock
UniqueLock(Mutex &mutexIn, const char *pszName, const char *pszFile, int nLine, bool fTry=false) EXCLUSIVE_LOCK_FUNCTION(mutexIn)
Definition: sync.h:148
CSemaphore::value
int value
Definition: sync.h:216