LCOV - code coverage report
Current view: top level - src - sync.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 43 71 60.6 %
Date: 2015-10-12 22:39:14 Functions: 8 21 38.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11