]> Git Repo - VerusCoin.git/blob - src/sync.h
Merge pull request #3207
[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 #ifdef DEBUG_LOCKORDER
88 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
89 void LeaveCritical();
90 std::string LocksHeld();
91 void AssertLockHeld(std::string strName);
92 #else
93 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
94 void static inline LeaveCritical() {}
95 void static inline AssertLockHeld(std::string) {}
96 #endif
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 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         {
115             PrintLockContention(pszName, pszFile, nLine);
116 #endif
117         lock.lock();
118 #ifdef DEBUG_LOCKCONTENTION
119         }
120 #endif
121     }
122
123     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
124     {
125         EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
126         lock.try_lock();
127         if (!lock.owns_lock())
128             LeaveCritical();
129         return lock.owns_lock();
130     }
131
132 public:
133     CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
134     {
135         if (fTry)
136             TryEnter(pszName, pszFile, nLine);
137         else
138             Enter(pszName, pszFile, nLine);
139     }
140
141     ~CMutexLock()
142     {
143         if (lock.owns_lock())
144             LeaveCritical();
145     }
146
147     operator bool()
148     {
149         return lock.owns_lock();
150     }
151 };
152
153 typedef CMutexLock<CCriticalSection> CCriticalBlock;
154
155 #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
156 #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
157 #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
158
159 #define ENTER_CRITICAL_SECTION(cs) \
160     { \
161         EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
162         (cs).lock(); \
163     }
164
165 #define LEAVE_CRITICAL_SECTION(cs) \
166     { \
167         (cs).unlock(); \
168         LeaveCritical(); \
169     }
170
171 class CSemaphore
172 {
173 private:
174     boost::condition_variable condition;
175     boost::mutex mutex;
176     int value;
177
178 public:
179     CSemaphore(int init) : value(init) {}
180
181     void wait() {
182         boost::unique_lock<boost::mutex> lock(mutex);
183         while (value < 1) {
184             condition.wait(lock);
185         }
186         value--;
187     }
188
189     bool try_wait() {
190         boost::unique_lock<boost::mutex> lock(mutex);
191         if (value < 1)
192             return false;
193         value--;
194         return true;
195     }
196
197     void post() {
198         {
199             boost::unique_lock<boost::mutex> lock(mutex);
200             value++;
201         }
202         condition.notify_one();
203     }
204 };
205
206 /** RAII-style semaphore lock */
207 class CSemaphoreGrant
208 {
209 private:
210     CSemaphore *sem;
211     bool fHaveGrant;
212
213 public:
214     void Acquire() {
215         if (fHaveGrant)
216             return;
217         sem->wait();
218         fHaveGrant = true;
219     }
220
221     void Release() {
222         if (!fHaveGrant)
223             return;
224         sem->post();
225         fHaveGrant = false;
226     }
227
228     bool TryAcquire() {
229         if (!fHaveGrant && sem->try_wait())
230             fHaveGrant = true;
231         return fHaveGrant;
232     }
233
234     void MoveTo(CSemaphoreGrant &grant) {
235         grant.Release();
236         grant.sem = sem;
237         grant.fHaveGrant = fHaveGrant;
238         sem = NULL;
239         fHaveGrant = false;
240     }
241
242     CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
243
244     CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) {
245         if (fTry)
246             TryAcquire();
247         else
248             Acquire();
249     }
250
251     ~CSemaphoreGrant() {
252         Release();
253     }
254
255     operator bool() {
256         return fHaveGrant;
257     }
258 };
259 #endif
260
This page took 0.039534 seconds and 4 git commands to generate.