aboutsummaryrefslogtreecommitdiff
path: root/src/sync.h
diff options
context:
space:
mode:
authorJackson Palmer <[email protected]>2014-01-19 15:41:55 +1100
committerJackson Palmer <[email protected]>2014-01-19 15:41:55 +1100
commit68b0507f00ee29bcf29f3c992a882c712f990da6 (patch)
tree3140d6000b9018767e91069ccd83b0bad3e256f5 /src/sync.h
downloaddiscoin-68b0507f00ee29bcf29f3c992a882c712f990da6.tar.xz
discoin-68b0507f00ee29bcf29f3c992a882c712f990da6.zip
Initial commit
Successfully building on Ubuntu + Windows.
Diffstat (limited to 'src/sync.h')
-rw-r--r--src/sync.h213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/sync.h b/src/sync.h
new file mode 100644
index 000000000..930c9b2b8
--- /dev/null
+++ b/src/sync.h
@@ -0,0 +1,213 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_SYNC_H
+#define BITCOIN_SYNC_H
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include "threadsafety.h"
+
+// Template mixin that adds -Wthread-safety locking annotations to a
+// subset of the mutex API.
+template <typename PARENT>
+class LOCKABLE AnnotatedMixin : public PARENT
+{
+public:
+ void lock() EXCLUSIVE_LOCK_FUNCTION()
+ {
+ PARENT::lock();
+ }
+
+ void unlock() UNLOCK_FUNCTION()
+ {
+ PARENT::unlock();
+ }
+
+ bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
+ {
+ return PARENT::try_lock();
+ }
+};
+
+/** Wrapped boost mutex: supports recursive locking, but no waiting */
+// TODO: We should move away from using the recursive lock by default.
+typedef AnnotatedMixin<boost::recursive_mutex> CCriticalSection;
+
+/** Wrapped boost mutex: supports waiting but not recursive locking */
+typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
+
+#ifdef DEBUG_LOCKORDER
+void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
+void LeaveCritical();
+#else
+void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
+void static inline LeaveCritical() {}
+#endif
+
+#ifdef DEBUG_LOCKCONTENTION
+void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
+#endif
+
+/** Wrapper around boost::unique_lock<Mutex> */
+template<typename Mutex>
+class CMutexLock
+{
+private:
+ boost::unique_lock<Mutex> lock;
+
+ void Enter(const char* pszName, const char* pszFile, int nLine)
+ {
+ EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()));
+#ifdef DEBUG_LOCKCONTENTION
+ if (!lock.try_lock())
+ {
+ PrintLockContention(pszName, pszFile, nLine);
+#endif
+ lock.lock();
+#ifdef DEBUG_LOCKCONTENTION
+ }
+#endif
+ }
+
+ bool TryEnter(const char* pszName, const char* pszFile, int nLine)
+ {
+ EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true);
+ lock.try_lock();
+ if (!lock.owns_lock())
+ LeaveCritical();
+ return lock.owns_lock();
+ }
+
+public:
+ CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
+ {
+ if (fTry)
+ TryEnter(pszName, pszFile, nLine);
+ else
+ Enter(pszName, pszFile, nLine);
+ }
+
+ ~CMutexLock()
+ {
+ if (lock.owns_lock())
+ LeaveCritical();
+ }
+
+ operator bool()
+ {
+ return lock.owns_lock();
+ }
+};
+
+typedef CMutexLock<CCriticalSection> CCriticalBlock;
+
+#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+#define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__)
+#define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
+
+#define ENTER_CRITICAL_SECTION(cs) \
+ { \
+ EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
+ (cs).lock(); \
+ }
+
+#define LEAVE_CRITICAL_SECTION(cs) \
+ { \
+ (cs).unlock(); \
+ LeaveCritical(); \
+ }
+
+class CSemaphore
+{
+private:
+ boost::condition_variable condition;
+ boost::mutex mutex;
+ int value;
+
+public:
+ CSemaphore(int init) : value(init) {}
+
+ void wait() {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ while (value < 1) {
+ condition.wait(lock);
+ }
+ value--;
+ }
+
+ bool try_wait() {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ if (value < 1)
+ return false;
+ value--;
+ return true;
+ }
+
+ void post() {
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ value++;
+ }
+ condition.notify_one();
+ }
+};
+
+/** RAII-style semaphore lock */
+class CSemaphoreGrant
+{
+private:
+ CSemaphore *sem;
+ bool fHaveGrant;
+
+public:
+ void Acquire() {
+ if (fHaveGrant)
+ return;
+ sem->wait();
+ fHaveGrant = true;
+ }
+
+ void Release() {
+ if (!fHaveGrant)
+ return;
+ sem->post();
+ fHaveGrant = false;
+ }
+
+ bool TryAcquire() {
+ if (!fHaveGrant && sem->try_wait())
+ fHaveGrant = true;
+ return fHaveGrant;
+ }
+
+ void MoveTo(CSemaphoreGrant &grant) {
+ grant.Release();
+ grant.sem = sem;
+ grant.fHaveGrant = fHaveGrant;
+ sem = NULL;
+ fHaveGrant = false;
+ }
+
+ CSemaphoreGrant() : sem(NULL), fHaveGrant(false) {}
+
+ CSemaphoreGrant(CSemaphore &sema, bool fTry = false) : sem(&sema), fHaveGrant(false) {
+ if (fTry)
+ TryAcquire();
+ else
+ Acquire();
+ }
+
+ ~CSemaphoreGrant() {
+ Release();
+ }
+
+ operator bool() {
+ return fHaveGrant;
+ }
+};
+#endif
+