Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2013 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 :
17 : ////////////////////////////////////////////////
18 : // //
19 : // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
20 : // //
21 : ////////////////////////////////////////////////
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 :
44 : ///////////////////////////////
45 : // //
46 : // THE ACTUAL IMPLEMENTATION //
47 : // //
48 : ///////////////////////////////
49 :
50 : /**
51 : * Template mixin that adds -Wthread-safety locking
52 : * annotations to a subset of the mutex API.
53 : */
54 : template <typename PARENT>
55 25352 : class LOCKABLE AnnotatedMixin : public PARENT
56 : {
57 : public:
58 : void lock() EXCLUSIVE_LOCK_FUNCTION()
59 : {
60 5833334 : PARENT::lock();
61 : }
62 :
63 : void unlock() UNLOCK_FUNCTION()
64 : {
65 6134570 : PARENT::unlock();
66 : }
67 :
68 : bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
69 : {
70 306047 : return PARENT::try_lock();
71 : }
72 : };
73 :
74 : /**
75 : * Wrapped boost mutex: supports recursive locking, but no waiting
76 : * TODO: We should move away from using the recursive lock by default.
77 : */
78 : typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
79 :
80 : /** Wrapped boost mutex: supports waiting but not recursive locking */
81 : typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
82 :
83 : /** Just a typedef for boost::condition_variable, can be wrapped later if desired */
84 : typedef boost::condition_variable CConditionVariable;
85 :
86 : #ifdef DEBUG_LOCKORDER
87 : void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
88 : void LeaveCritical();
89 : std::string LocksHeld();
90 : void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
91 : #else
92 : void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
93 : void static inline LeaveCritical() {}
94 0 : void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
95 : #endif
96 : #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
97 :
98 : #ifdef DEBUG_LOCKCONTENTION
99 : void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
100 : #endif
101 :
102 : /** Wrapper around boost::unique_lock<Mutex> */
103 : template <typename Mutex>
104 : class SCOPED_LOCKABLE CMutexLock
105 : {
106 : private:
107 : boost::unique_lock<Mutex> lock;
108 :
109 0 : void Enter(const char* pszName, const char* pszFile, int nLine)
110 : {
111 4108561 : EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
112 : #ifdef DEBUG_LOCKCONTENTION
113 : if (!lock.try_lock()) {
114 : PrintLockContention(pszName, pszFile, nLine);
115 : #endif
116 4108561 : lock.lock();
117 : #ifdef DEBUG_LOCKCONTENTION
118 : }
119 : #endif
120 0 : }
121 :
122 0 : bool TryEnter(const char* pszName, const char* pszFile, int nLine)
123 : {
124 306045 : EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
125 306045 : lock.try_lock();
126 0 : if (!lock.owns_lock())
127 : LeaveCritical();
128 0 : return lock.owns_lock();
129 : }
130 :
131 : public:
132 4414550 : CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
133 : {
134 : if (fTry)
135 306045 : TryEnter(pszName, pszFile, nLine);
136 : else
137 4108505 : Enter(pszName, pszFile, nLine);
138 4414584 : }
139 :
140 56 : CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
141 56 : {
142 112 : if (!pmutexIn) return;
143 :
144 112 : lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
145 56 : if (fTry)
146 0 : TryEnter(pszName, pszFile, nLine);
147 : else
148 56 : Enter(pszName, pszFile, nLine);
149 : }
150 :
151 0 : ~CMutexLock() UNLOCK_FUNCTION()
152 : {
153 4414673 : if (lock.owns_lock())
154 : LeaveCritical();
155 8829346 : }
156 :
157 : operator bool()
158 : {
159 306078 : return lock.owns_lock();
160 : }
161 : };
162 :
163 : typedef CMutexLock<CCriticalSection> CCriticalBlock;
164 :
165 : #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
166 : #define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
167 : #define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
168 :
169 : #define ENTER_CRITICAL_SECTION(cs) \
170 : { \
171 : EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
172 : (cs).lock(); \
173 : }
174 :
175 : #define LEAVE_CRITICAL_SECTION(cs) \
176 : { \
177 : (cs).unlock(); \
178 : LeaveCritical(); \
179 : }
180 :
181 94 : class CSemaphore
182 : {
183 : private:
184 : boost::condition_variable condition;
185 : boost::mutex mutex;
186 : int value;
187 :
188 : public:
189 94 : CSemaphore(int init) : value(init) {}
190 :
191 1721 : void wait()
192 : {
193 1721 : boost::unique_lock<boost::mutex> lock(mutex);
194 1721 : while (value < 1) {
195 0 : condition.wait(lock);
196 : }
197 1721 : value--;
198 1721 : }
199 :
200 0 : bool try_wait()
201 : {
202 0 : boost::unique_lock<boost::mutex> lock(mutex);
203 0 : if (value < 1)
204 : return false;
205 0 : value--;
206 0 : return true;
207 : }
208 :
209 2473 : void post()
210 : {
211 : {
212 2473 : boost::unique_lock<boost::mutex> lock(mutex);
213 2473 : value++;
214 : }
215 2473 : condition.notify_one();
216 2473 : }
217 : };
218 :
219 : /** RAII-style semaphore lock */
220 : class CSemaphoreGrant
221 : {
222 : private:
223 : CSemaphore* sem;
224 : bool fHaveGrant;
225 :
226 : public:
227 : void Acquire()
228 : {
229 : if (fHaveGrant)
230 : return;
231 1721 : sem->wait();
232 1721 : fHaveGrant = true;
233 : }
234 :
235 : void Release()
236 : {
237 2123 : if (!fHaveGrant)
238 : return;
239 1721 : sem->post();
240 1721 : fHaveGrant = false;
241 : }
242 :
243 0 : bool TryAcquire()
244 : {
245 0 : if (!fHaveGrant && sem->try_wait())
246 0 : fHaveGrant = true;
247 0 : return fHaveGrant;
248 : }
249 :
250 0 : void MoveTo(CSemaphoreGrant& grant)
251 : {
252 : grant.Release();
253 0 : grant.sem = sem;
254 0 : grant.fHaveGrant = fHaveGrant;
255 0 : sem = NULL;
256 0 : fHaveGrant = false;
257 0 : }
258 :
259 363 : CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
260 :
261 1721 : CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
262 : {
263 1721 : if (fTry)
264 0 : TryAcquire();
265 : else
266 : Acquire();
267 1721 : }
268 :
269 0 : ~CSemaphoreGrant()
270 : {
271 : Release();
272 2084 : }
273 :
274 0 : operator bool()
275 : {
276 0 : return fHaveGrant;
277 : }
278 : };
279 :
280 : #endif // BITCOIN_SYNC_H
|