]> Git Repo - VerusCoin.git/blob - src/sync.h
Merge branch 'dev' into jl777
[VerusCoin.git] / src / sync.h
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 class LOCKABLE AnnotatedMixin : public PARENT
56 {
57 public:
58     void lock() EXCLUSIVE_LOCK_FUNCTION()
59     {
60         PARENT::lock();
61     }
62
63     void unlock() UNLOCK_FUNCTION()
64     {
65         PARENT::unlock();
66     }
67
68     bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
69     {
70         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 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     void Enter(const char* pszName, const char* pszFile, int nLine)
110     {
111         EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
112 #ifdef DEBUG_LOCKCONTENTION
113         if (!lock.try_lock()) {
114             PrintLockContention(pszName, pszFile, nLine);
115 #endif
116             lock.lock();
117 #ifdef DEBUG_LOCKCONTENTION
118         }
119 #endif
120     }
121
122     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
123     {
124         EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
125         lock.try_lock();
126         if (!lock.owns_lock())
127             LeaveCritical();
128         return lock.owns_lock();
129     }
130
131 public:
132     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             TryEnter(pszName, pszFile, nLine);
136         else
137             Enter(pszName, pszFile, nLine);
138     }
139
140     CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
141     {
142         if (!pmutexIn) return;
143
144         lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
145         if (fTry)
146             TryEnter(pszName, pszFile, nLine);
147         else
148             Enter(pszName, pszFile, nLine);
149     }
150
151     ~CMutexLock() UNLOCK_FUNCTION()
152     {
153         if (lock.owns_lock())
154             LeaveCritical();
155     }
156
157     operator bool()
158     {
159         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 class CSemaphore
182 {
183 private:
184     boost::condition_variable condition;
185     boost::mutex mutex;
186     int value;
187
188 public:
189     CSemaphore(int init) : value(init) {}
190
191     void wait()
192     {
193         boost::unique_lock<boost::mutex> lock(mutex);
194         while (value < 1) {
195             condition.wait(lock);
196         }
197         value--;
198     }
199
200     bool try_wait()
201     {
202         boost::unique_lock<boost::mutex> lock(mutex);
203         if (value < 1)
204             return false;
205         value--;
206         return true;
207     }
208
209     void post()
210     {
211         {
212             boost::unique_lock<boost::mutex> lock(mutex);
213             value++;
214         }
215         condition.notify_one();
216     }
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         sem->wait();
232         fHaveGrant = true;
233     }
234
235     void Release()
236     {
237         if (!fHaveGrant)
238             return;
239         sem->post();
240         fHaveGrant = false;
241     }
242
243     bool TryAcquire()
244     {
245         if (!fHaveGrant && sem->try_wait())
246             fHaveGrant = true;
247         return fHaveGrant;
248     }
249
250     void MoveTo(CSemaphoreGrant& grant)
251     {
252         grant.Release();
253         grant.sem = sem;
254         grant.fHaveGrant = fHaveGrant;
255         sem = NULL;
256         fHaveGrant = false;
257     }
258
259     CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
260
261     CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
262     {
263         if (fTry)
264             TryAcquire();
265         else
266             Acquire();
267     }
268
269     ~CSemaphoreGrant()
270     {
271         Release();
272     }
273
274     operator bool()
275     {
276         return fHaveGrant;
277     }
278 };
279
280 #endif // BITCOIN_SYNC_H
This page took 0.038711 seconds and 4 git commands to generate.