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