]> Git Repo - VerusCoin.git/blob - src/sync.h
Merge pull request #4503
[VerusCoin.git] / src / sync.h
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
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
17 ////////////////////////////////////////////////
18 //                                            //
19 // THE SIMPLE DEFINITON, EXCLUDING DEBUG CODE //
20 //                                            //
21 ////////////////////////////////////////////////
22
23 /*
24  
25  
26  
27 CCriticalSection mutex;
28     boost::recursive_mutex mutex;
29
30 LOCK(mutex);
31     boost::unique_lock<boost::recursive_mutex> criticalblock(mutex);
32
33 LOCK2(mutex1, mutex2);
34     boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1);
35     boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2);
36
37 TRY_LOCK(mutex, name);
38     boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t);
39
40 ENTER_CRITICAL_SECTION(mutex); // no RAII
41     mutex.lock();
42
43 LEAVE_CRITICAL_SECTION(mutex); // no RAII
44     mutex.unlock();
45  
46  
47  
48  */
49
50
51
52 ///////////////////////////////
53 //                           //
54 // THE ACTUAL IMPLEMENTATION //
55 //                           //
56 ///////////////////////////////
57
58 // Template mixin that adds -Wthread-safety locking annotations to a
59 // subset of the mutex API.
60 template <typename PARENT>
61 class LOCKABLE AnnotatedMixin : public PARENT
62 {
63 public:
64     void lock() EXCLUSIVE_LOCK_FUNCTION()
65     {
66       PARENT::lock();
67     }
68
69     void unlock() UNLOCK_FUNCTION()
70     {
71       PARENT::unlock();
72     }
73
74     bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
75     {
76       return PARENT::try_lock();
77     }
78 };
79
80 /** Wrapped boost mutex: supports recursive locking, but no waiting  */
81 // TODO: We should move away from using the recursive lock by default.
82 typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
83
84 /** Wrapped boost mutex: supports waiting but not recursive locking */
85 typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
86
87 /** Just a typedef for boost::condition_variable, can be wrapped later if desired */
88 typedef boost::condition_variable CConditionVariable;
89
90 #ifdef DEBUG_LOCKORDER
91 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
92 void LeaveCritical();
93 std::string LocksHeld();
94 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs);
95 #else
96 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
97 void static inline LeaveCritical() {}
98 void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs) {}
99 #endif
100 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
101
102 #ifdef DEBUG_LOCKCONTENTION
103 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
104 #endif
105
106 /** Wrapper around boost::unique_lock<Mutex> */
107 template<typename Mutex>
108 class CMutexLock
109 {
110 private:
111     boost::unique_lock<Mutex> lock;
112
113     void Enter(const char* pszName, const char* pszFile, int nLine)
114     {
115         EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
116 #ifdef DEBUG_LOCKCONTENTION
117         if (!lock.try_lock())
118         {
119             PrintLockContention(pszName, pszFile, nLine);
120 #endif
121         lock.lock();
122 #ifdef DEBUG_LOCKCONTENTION
123         }
124 #endif
125     }
126
127     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
128     {
129         EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
130         lock.try_lock();
131         if (!lock.owns_lock())
132             LeaveCritical();
133         return lock.owns_lock();
134     }
135
136 public:
137     CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
138     {
139         if (fTry)
140             TryEnter(pszName, pszFile, nLine);
141         else
142             Enter(pszName, pszFile, nLine);
143     }
144
145     ~CMutexLock()
146     {
147         if (lock.owns_lock())
148             LeaveCritical();
149     }
150
151     operator bool()
152     {
153         return lock.owns_lock();
154     }
155 };
156
157 typedef CMutexLock<CCriticalSection> CCriticalBlock;
158
159 #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
160 #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
161 #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
162
163 #define ENTER_CRITICAL_SECTION(cs) \
164     { \
165         EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
166         (cs).lock(); \
167     }
168
169 #define LEAVE_CRITICAL_SECTION(cs) \
170     { \
171         (cs).unlock(); \
172         LeaveCritical(); \
173     }
174
175 class CSemaphore
176 {
177 private:
178     boost::condition_variable condition;
179     boost::mutex mutex;
180     int value;
181
182 public:
183     CSemaphore(int init) : value(init) {}
184
185     void wait() {
186         boost::unique_lock<boost::mutex> lock(mutex);
187         while (value < 1) {
188             condition.wait(lock);
189         }
190         value--;
191     }
192
193     bool try_wait() {
194         boost::unique_lock<boost::mutex> lock(mutex);
195         if (value < 1)
196             return false;
197         value--;
198         return true;
199     }
200
201     void post() {
202         {
203             boost::unique_lock<boost::mutex> lock(mutex);
204             value++;
205         }
206         condition.notify_one();
207     }
208 };
209
210 /** RAII-style semaphore lock */
211 class CSemaphoreGrant
212 {
213 private:
214     CSemaphore *sem;
215     bool fHaveGrant;
216
217 public:
218     void Acquire() {
219         if (fHaveGrant)
220             return;
221         sem->wait();
222         fHaveGrant = true;
223     }
224
225     void Release() {
226         if (!fHaveGrant)
227             return;
228         sem->post();
229         fHaveGrant = false;
230     }
231
232     bool TryAcquire() {
233         if (!fHaveGrant && sem->try_wait())
234             fHaveGrant = true;
235         return fHaveGrant;
236     }
237
238     void MoveTo(CSemaphoreGrant &grant) {
239         grant.Release();
240         grant.sem = sem;
241         grant.fHaveGrant = fHaveGrant;
242         sem = NULL;
243         fHaveGrant = false;
244     }
245
246     CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
247
248     CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) {
249         if (fTry)
250             TryAcquire();
251         else
252             Acquire();
253     }
254
255     ~CSemaphoreGrant() {
256         Release();
257     }
258
259     operator bool() {
260         return fHaveGrant;
261     }
262 };
263 #endif
264
This page took 0.038664 seconds and 4 git commands to generate.