]> Git Repo - VerusCoin.git/blob - src/sync.h
Update libsecp256k1
[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 // THE ACTUAL IMPLEMENTATION //
54 //                           //
55 ///////////////////////////////
56
57 // Template mixin that adds -Wthread-safety locking annotations to a
58 // subset of the mutex API.
59 template <typename PARENT>
60 class LOCKABLE AnnotatedMixin : public PARENT
61 {
62 public:
63     void lock() EXCLUSIVE_LOCK_FUNCTION()
64     {
65         PARENT::lock();
66     }
67
68     void unlock() UNLOCK_FUNCTION()
69     {
70         PARENT::unlock();
71     }
72
73     bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
74     {
75         return PARENT::try_lock();
76     }
77 };
78
79 /** Wrapped boost mutex: supports recursive locking, but no waiting  */
80 // TODO: We should move away from using the recursive lock by default.
81 typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
82
83 /** Wrapped boost mutex: supports waiting but not recursive locking */
84 typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
85
86 /** Just a typedef for boost::condition_variable, can be wrapped later if desired */
87 typedef boost::condition_variable CConditionVariable;
88
89 #ifdef DEBUG_LOCKORDER
90 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
91 void LeaveCritical();
92 std::string LocksHeld();
93 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
94 #else
95 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false)
96 {
97 }
98 void static inline LeaveCritical() {}
99 void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
100 #endif
101 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
102
103 #ifdef DEBUG_LOCKCONTENTION
104 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
105 #endif
106
107 /** Wrapper around boost::unique_lock<Mutex> */
108 template <typename Mutex>
109 class CMutexLock
110 {
111 private:
112     boost::unique_lock<Mutex> lock;
113
114     void Enter(const char* pszName, const char* pszFile, int nLine)
115     {
116         EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
117 #ifdef DEBUG_LOCKCONTENTION
118         if (!lock.try_lock()) {
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     {
187         boost::unique_lock<boost::mutex> lock(mutex);
188         while (value < 1) {
189             condition.wait(lock);
190         }
191         value--;
192     }
193
194     bool try_wait()
195     {
196         boost::unique_lock<boost::mutex> lock(mutex);
197         if (value < 1)
198             return false;
199         value--;
200         return true;
201     }
202
203     void post()
204     {
205         {
206             boost::unique_lock<boost::mutex> lock(mutex);
207             value++;
208         }
209         condition.notify_one();
210     }
211 };
212
213 /** RAII-style semaphore lock */
214 class CSemaphoreGrant
215 {
216 private:
217     CSemaphore* sem;
218     bool fHaveGrant;
219
220 public:
221     void Acquire()
222     {
223         if (fHaveGrant)
224             return;
225         sem->wait();
226         fHaveGrant = true;
227     }
228
229     void Release()
230     {
231         if (!fHaveGrant)
232             return;
233         sem->post();
234         fHaveGrant = false;
235     }
236
237     bool TryAcquire()
238     {
239         if (!fHaveGrant && sem->try_wait())
240             fHaveGrant = true;
241         return fHaveGrant;
242     }
243
244     void MoveTo(CSemaphoreGrant& grant)
245     {
246         grant.Release();
247         grant.sem = sem;
248         grant.fHaveGrant = fHaveGrant;
249         sem = NULL;
250         fHaveGrant = false;
251     }
252
253     CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
254
255     CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
256     {
257         if (fTry)
258             TryAcquire();
259         else
260             Acquire();
261     }
262
263     ~CSemaphoreGrant()
264     {
265         Release();
266     }
267
268     operator bool()
269     {
270         return fHaveGrant;
271     }
272 };
273
274 #endif // BITCOIN_SYNC_H
This page took 0.039012 seconds and 4 git commands to generate.