]> Git Repo - VerusCoin.git/blame - src/sync.h
add support for miniupnpc api version 14
[VerusCoin.git] / src / sync.h
CommitLineData
7f3ccb59 1// Copyright (c) 2009-2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2013 The Bitcoin Core 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/*
042da8bc
EL
24CCriticalSection mutex;
25 boost::recursive_mutex mutex;
26
27LOCK(mutex);
28 boost::unique_lock<boost::recursive_mutex> criticalblock(mutex);
29
30LOCK2(mutex1, mutex2);
31 boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1);
32 boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2);
33
34TRY_LOCK(mutex, name);
35 boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t);
36
37ENTER_CRITICAL_SECTION(mutex); // no RAII
38 mutex.lock();
39
40LEAVE_CRITICAL_SECTION(mutex); // no RAII
41 mutex.unlock();
042da8bc
EL
42 */
43
042da8bc
EL
44///////////////////////////////
45// //
46// THE ACTUAL IMPLEMENTATION //
47// //
48///////////////////////////////
49
71ad6bd3
PK
50/**
51 * Template mixin that adds -Wthread-safety locking
52 * annotations to a subset of the mutex API.
53 */
05f97d12
AK
54template <typename PARENT>
55class LOCKABLE AnnotatedMixin : public PARENT
56{
57public:
58 void lock() EXCLUSIVE_LOCK_FUNCTION()
59 {
20e01b1a 60 PARENT::lock();
05f97d12 61 }
7f3ccb59 62
05f97d12
AK
63 void unlock() UNLOCK_FUNCTION()
64 {
20e01b1a 65 PARENT::unlock();
05f97d12 66 }
7f3ccb59 67
05f97d12
AK
68 bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
69 {
20e01b1a 70 return PARENT::try_lock();
05f97d12
AK
71 }
72};
7f3ccb59 73
71ad6bd3
PK
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 */
05f97d12 78typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
7f3ccb59
PW
79
80/** Wrapped boost mutex: supports waiting but not recursive locking */
05f97d12 81typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
7f3ccb59 82
ff6a7af1
LD
83/** Just a typedef for boost::condition_variable, can be wrapped later if desired */
84typedef boost::condition_variable CConditionVariable;
85
7f3ccb59
PW
86#ifdef DEBUG_LOCKORDER
87void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
88void LeaveCritical();
c649637b 89std::string LocksHeld();
20e01b1a 90void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
7f3ccb59 91#else
71ad6bd3 92void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
7f3ccb59 93void static inline LeaveCritical() {}
20e01b1a 94void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
7f3ccb59 95#endif
19a56762 96#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
7f3ccb59 97
4d009243
MC
98#ifdef DEBUG_LOCKCONTENTION
99void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
100#endif
101
4d369ec3 102/** Wrapper around boost::unique_lock<Mutex> */
20e01b1a 103template <typename Mutex>
7f3ccb59
PW
104class CMutexLock
105{
106private:
660ff174 107 boost::unique_lock<Mutex> lock;
7f3ccb59
PW
108
109 void Enter(const char* pszName, const char* pszFile, int nLine)
110 {
bfc96207 111 EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
7f3ccb59 112#ifdef DEBUG_LOCKCONTENTION
20e01b1a 113 if (!lock.try_lock()) {
bfc96207 114 PrintLockContention(pszName, pszFile, nLine);
7f3ccb59 115#endif
20e01b1a 116 lock.lock();
7f3ccb59 117#ifdef DEBUG_LOCKCONTENTION
7f3ccb59 118 }
bfc96207 119#endif
7f3ccb59
PW
120 }
121
122 bool TryEnter(const char* pszName, const char* pszFile, int nLine)
123 {
bfc96207
AK
124 EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
125 lock.try_lock();
660ff174 126 if (!lock.owns_lock())
bfc96207 127 LeaveCritical();
660ff174 128 return lock.owns_lock();
7f3ccb59
PW
129 }
130
bfc96207 131public:
660ff174 132 CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
7f3ccb59
PW
133 {
134 if (fTry)
135 TryEnter(pszName, pszFile, nLine);
136 else
137 Enter(pszName, pszFile, nLine);
138 }
139
4401b2d7
EL
140 CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
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
7f3ccb59
PW
151 ~CMutexLock()
152 {
660ff174 153 if (lock.owns_lock())
7f3ccb59
PW
154 LeaveCritical();
155 }
156
157 operator bool()
158 {
660ff174 159 return lock.owns_lock();
7f3ccb59 160 }
7f3ccb59
PW
161};
162
163typedef CMutexLock<CCriticalSection> CCriticalBlock;
164
165#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
20e01b1a
PW
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)
7f3ccb59 168
20e01b1a
PW
169#define ENTER_CRITICAL_SECTION(cs) \
170 { \
7f3ccb59 171 EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
20e01b1a 172 (cs).lock(); \
7f3ccb59
PW
173 }
174
175#define LEAVE_CRITICAL_SECTION(cs) \
20e01b1a
PW
176 { \
177 (cs).unlock(); \
178 LeaveCritical(); \
7f3ccb59
PW
179 }
180
7f3ccb59
PW
181class CSemaphore
182{
183private:
660ff174
PW
184 boost::condition_variable condition;
185 boost::mutex mutex;
186 int value;
7f3ccb59
PW
187
188public:
660ff174 189 CSemaphore(int init) : value(init) {}
7f3ccb59 190
20e01b1a
PW
191 void wait()
192 {
660ff174
PW
193 boost::unique_lock<boost::mutex> lock(mutex);
194 while (value < 1) {
195 condition.wait(lock);
196 }
197 value--;
7f3ccb59
PW
198 }
199
20e01b1a
PW
200 bool try_wait()
201 {
660ff174
PW
202 boost::unique_lock<boost::mutex> lock(mutex);
203 if (value < 1)
204 return false;
205 value--;
206 return true;
7f3ccb59
PW
207 }
208
20e01b1a
PW
209 void post()
210 {
660ff174
PW
211 {
212 boost::unique_lock<boost::mutex> lock(mutex);
213 value++;
214 }
215 condition.notify_one();
7f3ccb59
PW
216 }
217};
7f3ccb59
PW
218
219/** RAII-style semaphore lock */
220class CSemaphoreGrant
221{
222private:
20e01b1a 223 CSemaphore* sem;
7f3ccb59
PW
224 bool fHaveGrant;
225
226public:
20e01b1a
PW
227 void Acquire()
228 {
7f3ccb59
PW
229 if (fHaveGrant)
230 return;
231 sem->wait();
232 fHaveGrant = true;
233 }
234
20e01b1a
PW
235 void Release()
236 {
7f3ccb59
PW
237 if (!fHaveGrant)
238 return;
239 sem->post();
240 fHaveGrant = false;
241 }
242
20e01b1a
PW
243 bool TryAcquire()
244 {
7f3ccb59
PW
245 if (!fHaveGrant && sem->try_wait())
246 fHaveGrant = true;
247 return fHaveGrant;
248 }
249
20e01b1a
PW
250 void MoveTo(CSemaphoreGrant& grant)
251 {
7f3ccb59
PW
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
20e01b1a
PW
261 CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
262 {
7f3ccb59
PW
263 if (fTry)
264 TryAcquire();
265 else
266 Acquire();
267 }
268
20e01b1a
PW
269 ~CSemaphoreGrant()
270 {
7f3ccb59
PW
271 Release();
272 }
273
20e01b1a
PW
274 operator bool()
275 {
7f3ccb59
PW
276 return fHaveGrant;
277 }
278};
7f3ccb59 279
093303a8 280#endif // BITCOIN_SYNC_H
This page took 0.151379 seconds and 4 git commands to generate.