Fix getbalance() bug
[novacoin.git] / src / sync.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 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
13
14
15
16 /** Wrapped boost mutex: supports recursive locking, but no waiting  */
17 typedef boost::recursive_mutex CCriticalSection;
18
19 /** Wrapped boost mutex: supports waiting but not recursive locking */
20 typedef boost::mutex CWaitableCriticalSection;
21
22 #ifdef DEBUG_LOCKORDER
23 void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
24 void LeaveCritical();
25 #else
26 void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
27 void static inline LeaveCritical() {}
28 #endif
29
30 #ifdef DEBUG_LOCKCONTENTION
31 void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
32 #endif
33
34 /** Wrapper around boost::unique_lock<Mutex> */
35 template<typename Mutex>
36 class CMutexLock
37 {
38 private:
39     boost::unique_lock<Mutex> lock;
40 public:
41
42     void Enter(const char* pszName, const char* pszFile, int nLine)
43     {
44         if (!lock.owns_lock())
45         {
46             EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
47 #ifdef DEBUG_LOCKCONTENTION
48             if (!lock.try_lock())
49             {
50                 PrintLockContention(pszName, pszFile, nLine);
51 #endif
52             lock.lock();
53 #ifdef DEBUG_LOCKCONTENTION
54             }
55 #endif
56         }
57     }
58
59     void Leave()
60     {
61         if (lock.owns_lock())
62         {
63             lock.unlock();
64             LeaveCritical();
65         }
66     }
67
68     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
69     {
70         if (!lock.owns_lock())
71         {
72             EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
73             lock.try_lock();
74             if (!lock.owns_lock())
75                 LeaveCritical();
76         }
77         return lock.owns_lock();
78     }
79
80     CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
81     {
82         if (fTry)
83             TryEnter(pszName, pszFile, nLine);
84         else
85             Enter(pszName, pszFile, nLine);
86     }
87
88     ~CMutexLock()
89     {
90         if (lock.owns_lock())
91             LeaveCritical();
92     }
93
94     operator bool()
95     {
96         return lock.owns_lock();
97     }
98
99     boost::unique_lock<Mutex> &GetLock()
100     {
101         return lock;
102     }
103 };
104
105 typedef CMutexLock<CCriticalSection> CCriticalBlock;
106
107 #define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
108 #define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
109 #define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
110
111 #define ENTER_CRITICAL_SECTION(cs) \
112     { \
113         EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
114         (cs).lock(); \
115     }
116
117 #define LEAVE_CRITICAL_SECTION(cs) \
118     { \
119         (cs).unlock(); \
120         LeaveCritical(); \
121     }
122
123 class CSemaphore
124 {
125 private:
126     boost::condition_variable condition;
127     boost::mutex mutex;
128     int value;
129
130 public:
131     CSemaphore(int init) : value(init) {}
132
133     void wait() {
134         boost::unique_lock<boost::mutex> lock(mutex);
135         while (value < 1) {
136             condition.wait(lock);
137         }
138         value--;
139     }
140
141     bool try_wait() {
142         boost::unique_lock<boost::mutex> lock(mutex);
143         if (value < 1)
144             return false;
145         value--;
146         return true;
147     }
148
149     void post() {
150         {
151             boost::unique_lock<boost::mutex> lock(mutex);
152             value++;
153         }
154         condition.notify_one();
155     }
156 };
157
158 /** RAII-style semaphore lock */
159 class CSemaphoreGrant
160 {
161 private:
162     CSemaphore *sem;
163     bool fHaveGrant;
164
165 public:
166     void Acquire() {
167         if (fHaveGrant)
168             return;
169         sem->wait();
170         fHaveGrant = true;
171     }
172
173     void Release() {
174         if (!fHaveGrant)
175             return;
176         sem->post();
177         fHaveGrant = false;
178     }
179
180     bool TryAcquire() {
181         if (!fHaveGrant && sem->try_wait())
182             fHaveGrant = true;
183         return fHaveGrant;
184     }
185
186     void MoveTo(CSemaphoreGrant &grant) {
187         grant.Release();
188         grant.sem = sem;
189         grant.fHaveGrant = fHaveGrant;
190         sem = NULL;
191         fHaveGrant = false;
192     }
193
194     CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
195
196     CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) {
197         if (fTry)
198             TryAcquire();
199         else
200             Acquire();
201     }
202
203     ~CSemaphoreGrant() {
204         Release();
205     }
206
207     operator bool() {
208         return fHaveGrant;
209     }
210 };
211 #endif
212