]> Git Repo - VerusCoin.git/blame - src/sync.h
Remove references to X11 licence
[VerusCoin.git] / src / sync.h
CommitLineData
7f3ccb59 1// Copyright (c) 2009-2010 Satoshi Nakamoto
db0e8ccd 2// Copyright (c) 2009-2013 The Bitcoin developers
78253fcb 3// Distributed under the MIT software license, see the accompanying
3a25a2b9 4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
51ed9ec9 5
7f3ccb59
PW
6#ifndef BITCOIN_SYNC_H
7#define BITCOIN_SYNC_H
8
51ed9ec9
BD
9#include "threadsafety.h"
10
11#include <boost/thread/condition_variable.hpp>
12#include <boost/thread/locks.hpp>
660ff174
PW
13#include <boost/thread/mutex.hpp>
14#include <boost/thread/recursive_mutex.hpp>
7f3ccb59 15
042da8bc
EL
16
17////////////////////////////////////////////////
18// //
19// THE SIMPLE DEFINITON, EXCLUDING DEBUG CODE //
20// //
21////////////////////////////////////////////////
22
23/*
24
25
26
27CCriticalSection mutex;
28 boost::recursive_mutex mutex;
29
30LOCK(mutex);
31 boost::unique_lock<boost::recursive_mutex> criticalblock(mutex);
32
33LOCK2(mutex1, mutex2);
34 boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1);
35 boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2);
36
37TRY_LOCK(mutex, name);
38 boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t);
39
40ENTER_CRITICAL_SECTION(mutex); // no RAII
41 mutex.lock();
42
43LEAVE_CRITICAL_SECTION(mutex); // no RAII
44 mutex.unlock();
45
46
47
48 */
49
50
042da8bc
EL
51///////////////////////////////
52// //
53// THE ACTUAL IMPLEMENTATION //
54// //
55///////////////////////////////
56
05f97d12
AK
57// Template mixin that adds -Wthread-safety locking annotations to a
58// subset of the mutex API.
59template <typename PARENT>
60class LOCKABLE AnnotatedMixin : public PARENT
61{
62public:
63 void lock() EXCLUSIVE_LOCK_FUNCTION()
64 {
20e01b1a 65 PARENT::lock();
05f97d12 66 }
7f3ccb59 67
05f97d12
AK
68 void unlock() UNLOCK_FUNCTION()
69 {
20e01b1a 70 PARENT::unlock();
05f97d12 71 }
7f3ccb59 72
05f97d12
AK
73 bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
74 {
20e01b1a 75 return PARENT::try_lock();
05f97d12
AK
76 }
77};
7f3ccb59
PW
78
79/** Wrapped boost mutex: supports recursive locking, but no waiting */
05f97d12
AK
80// TODO: We should move away from using the recursive lock by default.
81typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
7f3ccb59
PW
82
83/** Wrapped boost mutex: supports waiting but not recursive locking */
05f97d12 84typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
7f3ccb59 85
ff6a7af1
LD
86/** Just a typedef for boost::condition_variable, can be wrapped later if desired */
87typedef boost::condition_variable CConditionVariable;
88
7f3ccb59
PW
89#ifdef DEBUG_LOCKORDER
90void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
91void LeaveCritical();
c649637b 92std::string LocksHeld();
20e01b1a 93void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
7f3ccb59 94#else
20e01b1a
PW
95void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false)
96{
97}
7f3ccb59 98void static inline LeaveCritical() {}
20e01b1a 99void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
7f3ccb59 100#endif
19a56762 101#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
7f3ccb59 102
4d009243
MC
103#ifdef DEBUG_LOCKCONTENTION
104void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
105#endif
106
4d369ec3 107/** Wrapper around boost::unique_lock<Mutex> */
20e01b1a 108template <typename Mutex>
7f3ccb59
PW
109class CMutexLock
110{
111private:
660ff174 112 boost::unique_lock<Mutex> lock;
7f3ccb59
PW
113
114 void Enter(const char* pszName, const char* pszFile, int nLine)
115 {
bfc96207 116 EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
7f3ccb59 117#ifdef DEBUG_LOCKCONTENTION
20e01b1a 118 if (!lock.try_lock()) {
bfc96207 119 PrintLockContention(pszName, pszFile, nLine);
7f3ccb59 120#endif
20e01b1a 121 lock.lock();
7f3ccb59 122#ifdef DEBUG_LOCKCONTENTION
7f3ccb59 123 }
bfc96207 124#endif
7f3ccb59
PW
125 }
126
127 bool TryEnter(const char* pszName, const char* pszFile, int nLine)
128 {
bfc96207
AK
129 EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
130 lock.try_lock();
660ff174 131 if (!lock.owns_lock())
bfc96207 132 LeaveCritical();
660ff174 133 return lock.owns_lock();
7f3ccb59
PW
134 }
135
bfc96207 136public:
660ff174 137 CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
7f3ccb59
PW
138 {
139 if (fTry)
140 TryEnter(pszName, pszFile, nLine);
141 else
142 Enter(pszName, pszFile, nLine);
143 }
144
145 ~CMutexLock()
146 {
660ff174 147 if (lock.owns_lock())
7f3ccb59
PW
148 LeaveCritical();
149 }
150
151 operator bool()
152 {
660ff174 153 return lock.owns_lock();
7f3ccb59 154 }
7f3ccb59
PW
155};
156
157typedef CMutexLock<CCriticalSection> CCriticalBlock;
158
159#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
20e01b1a
PW
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)
7f3ccb59 162
20e01b1a
PW
163#define ENTER_CRITICAL_SECTION(cs) \
164 { \
7f3ccb59 165 EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
20e01b1a 166 (cs).lock(); \
7f3ccb59
PW
167 }
168
169#define LEAVE_CRITICAL_SECTION(cs) \
20e01b1a
PW
170 { \
171 (cs).unlock(); \
172 LeaveCritical(); \
7f3ccb59
PW
173 }
174
7f3ccb59
PW
175class CSemaphore
176{
177private:
660ff174
PW
178 boost::condition_variable condition;
179 boost::mutex mutex;
180 int value;
7f3ccb59
PW
181
182public:
660ff174 183 CSemaphore(int init) : value(init) {}
7f3ccb59 184
20e01b1a
PW
185 void wait()
186 {
660ff174
PW
187 boost::unique_lock<boost::mutex> lock(mutex);
188 while (value < 1) {
189 condition.wait(lock);
190 }
191 value--;
7f3ccb59
PW
192 }
193
20e01b1a
PW
194 bool try_wait()
195 {
660ff174
PW
196 boost::unique_lock<boost::mutex> lock(mutex);
197 if (value < 1)
198 return false;
199 value--;
200 return true;
7f3ccb59
PW
201 }
202
20e01b1a
PW
203 void post()
204 {
660ff174
PW
205 {
206 boost::unique_lock<boost::mutex> lock(mutex);
207 value++;
208 }
209 condition.notify_one();
7f3ccb59
PW
210 }
211};
7f3ccb59
PW
212
213/** RAII-style semaphore lock */
214class CSemaphoreGrant
215{
216private:
20e01b1a 217 CSemaphore* sem;
7f3ccb59
PW
218 bool fHaveGrant;
219
220public:
20e01b1a
PW
221 void Acquire()
222 {
7f3ccb59
PW
223 if (fHaveGrant)
224 return;
225 sem->wait();
226 fHaveGrant = true;
227 }
228
20e01b1a
PW
229 void Release()
230 {
7f3ccb59
PW
231 if (!fHaveGrant)
232 return;
233 sem->post();
234 fHaveGrant = false;
235 }
236
20e01b1a
PW
237 bool TryAcquire()
238 {
7f3ccb59
PW
239 if (!fHaveGrant && sem->try_wait())
240 fHaveGrant = true;
241 return fHaveGrant;
242 }
243
20e01b1a
PW
244 void MoveTo(CSemaphoreGrant& grant)
245 {
7f3ccb59
PW
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
20e01b1a
PW
255 CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
256 {
7f3ccb59
PW
257 if (fTry)
258 TryAcquire();
259 else
260 Acquire();
261 }
262
20e01b1a
PW
263 ~CSemaphoreGrant()
264 {
7f3ccb59
PW
265 Release();
266 }
267
20e01b1a
PW
268 operator bool()
269 {
7f3ccb59
PW
270 return fHaveGrant;
271 }
272};
7f3ccb59 273
093303a8 274#endif // BITCOIN_SYNC_H
This page took 0.131653 seconds and 4 git commands to generate.