LCOV - code coverage report
Current view: top level - src - sync.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 92 109 84.4 %
Date: 2020-09-26 01:30:44 Functions: 63 66 95.5 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2020 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             : #include <util/macros.h>
      11             : 
      12             : #include <condition_variable>
      13             : #include <mutex>
      14             : #include <string>
      15             : #include <thread>
      16             : 
      17             : ////////////////////////////////////////////////
      18             : //                                            //
      19             : // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
      20             : //                                            //
      21             : ////////////////////////////////////////////////
      22             : 
      23             : /*
      24             : RecursiveMutex mutex;
      25             :     std::recursive_mutex mutex;
      26             : 
      27             : LOCK(mutex);
      28             :     std::unique_lock<std::recursive_mutex> criticalblock(mutex);
      29             : 
      30             : LOCK2(mutex1, mutex2);
      31             :     std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
      32             :     std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
      33             : 
      34             : TRY_LOCK(mutex, name);
      35             :     std::unique_lock<std::recursive_mutex> name(mutex, std::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             : #ifdef DEBUG_LOCKORDER
      51             : void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
      52             : void LeaveCritical();
      53             : void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
      54             : std::string LocksHeld();
      55             : template <typename MutexType>
      56             : void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
      57             : template <typename MutexType>
      58             : void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs);
      59             : void DeleteLock(void* cs);
      60             : bool LockStackEmpty();
      61             : 
      62             : /**
      63             :  * Call abort() if a potential lock order deadlock bug is detected, instead of
      64             :  * just logging information and throwing a logic_error. Defaults to true, and
      65             :  * set to false in DEBUG_LOCKORDER unit tests.
      66             :  */
      67             : extern bool g_debug_lockorder_abort;
      68             : #else
      69    50465230 : inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
      70    50467441 : inline void LeaveCritical() {}
      71      658769 : inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
      72             : template <typename MutexType>
      73    12434498 : inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
      74             : template <typename MutexType>
      75      229143 : void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) {}
      76       71546 : inline void DeleteLock(void* cs) {}
      77           8 : inline bool LockStackEmpty() { return true; }
      78             : #endif
      79             : #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
      80             : #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
      81             : 
      82             : /**
      83             :  * Template mixin that adds -Wthread-safety locking annotations and lock order
      84             :  * checking to a subset of the mutex API.
      85             :  */
      86             : template <typename PARENT>
      87      123176 : class LOCKABLE AnnotatedMixin : public PARENT
      88             : {
      89             : public:
      90      143092 :     ~AnnotatedMixin() {
      91       71546 :         DeleteLock((void*)this);
      92      143092 :     }
      93             : 
      94          20 :     void lock() EXCLUSIVE_LOCK_FUNCTION()
      95             :     {
      96          20 :         PARENT::lock();
      97          20 :     }
      98             : 
      99          20 :     void unlock() UNLOCK_FUNCTION()
     100             :     {
     101          20 :         PARENT::unlock();
     102          20 :     }
     103             : 
     104             :     bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
     105             :     {
     106             :         return PARENT::try_lock();
     107             :     }
     108             : 
     109             :     using UniqueLock = std::unique_lock<PARENT>;
     110             : #ifdef __clang__
     111             :     //! For negative capabilities in the Clang Thread Safety Analysis.
     112             :     //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction
     113             :     //! with the ! operator, to indicate that a mutex should not be held.
     114             :     const AnnotatedMixin& operator!() const { return *this; }
     115             : #endif // __clang__
     116             : };
     117             : 
     118             : /**
     119             :  * Wrapped mutex: supports recursive locking, but no waiting
     120             :  * TODO: We should move away from using the recursive lock by default.
     121             :  */
     122             : using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;
     123             : 
     124             : /** Wrapped mutex: supports waiting but not recursive locking */
     125             : typedef AnnotatedMixin<std::mutex> Mutex;
     126             : 
     127             : #ifdef DEBUG_LOCKCONTENTION
     128             : void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
     129             : #endif
     130             : 
     131             : /** Wrapper around std::unique_lock style lock for Mutex. */
     132             : template <typename Mutex, typename Base = typename Mutex::UniqueLock>
     133             : class SCOPED_LOCKABLE UniqueLock : public Base
     134             : {
     135             : private:
     136    49742912 :     void Enter(const char* pszName, const char* pszFile, int nLine)
     137             :     {
     138    49742912 :         EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()));
     139             : #ifdef DEBUG_LOCKCONTENTION
     140             :         if (!Base::try_lock()) {
     141             :             PrintLockContention(pszName, pszFile, nLine);
     142             : #endif
     143    49742912 :             Base::lock();
     144             : #ifdef DEBUG_LOCKCONTENTION
     145             :         }
     146             : #endif
     147    49742912 :     }
     148             : 
     149        1413 :     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
     150             :     {
     151        1413 :         EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true);
     152        1413 :         Base::try_lock();
     153        1413 :         if (!Base::owns_lock())
     154          25 :             LeaveCritical();
     155        1413 :         return Base::owns_lock();
     156             :     }
     157             : 
     158             : public:
     159    99489280 :     UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
     160    99489280 :     {
     161    49744484 :         if (fTry)
     162        1413 :             TryEnter(pszName, pszFile, nLine);
     163             :         else
     164    49742842 :             Enter(pszName, pszFile, nLine);
     165    99491592 :     }
     166             : 
     167             :     UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
     168             :     {
     169             :         if (!pmutexIn) return;
     170             : 
     171             :         *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
     172             :         if (fTry)
     173             :             TryEnter(pszName, pszFile, nLine);
     174             :         else
     175             :             Enter(pszName, pszFile, nLine);
     176             :     }
     177             : 
     178   100809843 :     ~UniqueLock() UNLOCK_FUNCTION()
     179    50404996 :     {
     180    50404847 :         if (Base::owns_lock())
     181    49746220 :             LeaveCritical();
     182   100809935 :     }
     183             : 
     184        1413 :     operator bool()
     185             :     {
     186        1413 :         return Base::owns_lock();
     187             :     }
     188             : 
     189             : protected:
     190             :     // needed for reverse_lock
     191     1317538 :     UniqueLock() { }
     192             : 
     193             : public:
     194             :     /**
     195             :      * An RAII-style reverse lock. Unlocks on construction and locks on destruction.
     196             :      */
     197             :     class reverse_lock {
     198             :     public:
     199     1317538 :         explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {
     200      658769 :             CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
     201      658769 :             lock.unlock();
     202      658768 :             LeaveCritical();
     203      658768 :             lock.swap(templock);
     204     1317538 :         }
     205             : 
     206     1317532 :         ~reverse_lock() {
     207      658766 :             templock.swap(lock);
     208      658766 :             EnterCritical(lockname.c_str(), file.c_str(), line, (void*)lock.mutex());
     209      658766 :             lock.lock();
     210     1317534 :         }
     211             : 
     212             :      private:
     213             :         reverse_lock(reverse_lock const&);
     214             :         reverse_lock& operator=(reverse_lock const&);
     215             : 
     216             :         UniqueLock& lock;
     217             :         UniqueLock templock;
     218             :         std::string lockname;
     219             :         const std::string file;
     220             :         const int line;
     221             :      };
     222             :      friend class reverse_lock;
     223             : };
     224             : 
     225             : #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
     226             : 
     227             : template<typename MutexArg>
     228             : using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
     229             : 
     230             : #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
     231             : #define LOCK2(cs1, cs2)                                               \
     232             :     DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
     233             :     DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
     234             : #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
     235             : #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
     236             : 
     237             : #define ENTER_CRITICAL_SECTION(cs)                            \
     238             :     {                                                         \
     239             :         EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \
     240             :         (cs).lock();                                          \
     241             :     }
     242             : 
     243             : #define LEAVE_CRITICAL_SECTION(cs) \
     244             :     {                              \
     245             :         (cs).unlock();             \
     246             :         LeaveCritical();           \
     247             :     }
     248             : 
     249             : //! Run code while locking a mutex.
     250             : //!
     251             : //! Examples:
     252             : //!
     253             : //!   WITH_LOCK(cs, shared_val = shared_val + 1);
     254             : //!
     255             : //!   int val = WITH_LOCK(cs, return shared_val);
     256             : //!
     257             : #define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
     258             : 
     259        1968 : class CSemaphore
     260             : {
     261             : private:
     262             :     std::condition_variable condition;
     263             :     std::mutex mutex;
     264             :     int value;
     265             : 
     266             : public:
     267        1968 :     explicit CSemaphore(int init) : value(init) {}
     268             : 
     269       32202 :     void wait()
     270             :     {
     271       32202 :         std::unique_lock<std::mutex> lock(mutex);
     272       64404 :         condition.wait(lock, [&]() { return value >= 1; });
     273       32202 :         value--;
     274       32202 :     }
     275             : 
     276           0 :     bool try_wait()
     277             :     {
     278           0 :         std::lock_guard<std::mutex> lock(mutex);
     279           0 :         if (value < 1)
     280           0 :             return false;
     281           0 :         value--;
     282           0 :         return true;
     283           0 :     }
     284             : 
     285       41549 :     void post()
     286             :     {
     287             :         {
     288       41549 :             std::lock_guard<std::mutex> lock(mutex);
     289       41549 :             value++;
     290       41549 :         }
     291       41549 :         condition.notify_one();
     292       41549 :     }
     293             : };
     294             : 
     295             : /** RAII-style semaphore lock */
     296             : class CSemaphoreGrant
     297             : {
     298             : private:
     299             :     CSemaphore* sem;
     300             :     bool fHaveGrant;
     301             : 
     302             : public:
     303       32202 :     void Acquire()
     304             :     {
     305       32202 :         if (fHaveGrant)
     306             :             return;
     307       32202 :         sem->wait();
     308       32202 :         fHaveGrant = true;
     309       32202 :     }
     310             : 
     311       33230 :     void Release()
     312             :     {
     313       33230 :         if (!fHaveGrant)
     314             :             return;
     315       32202 :         sem->post();
     316       32202 :         fHaveGrant = false;
     317       33230 :     }
     318             : 
     319           1 :     bool TryAcquire()
     320             :     {
     321           1 :         if (!fHaveGrant && sem->try_wait())
     322           0 :             fHaveGrant = true;
     323           1 :         return fHaveGrant;
     324             :     }
     325             : 
     326           0 :     void MoveTo(CSemaphoreGrant& grant)
     327             :     {
     328           0 :         grant.Release();
     329           0 :         grant.sem = sem;
     330           0 :         grant.fHaveGrant = fHaveGrant;
     331           0 :         fHaveGrant = false;
     332           0 :     }
     333             : 
     334        1458 :     CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
     335             : 
     336       64404 :     explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
     337       32202 :     {
     338       32202 :         if (fTry)
     339           0 :             TryAcquire();
     340             :         else
     341       32202 :             Acquire();
     342       64404 :     }
     343             : 
     344       65862 :     ~CSemaphoreGrant()
     345       32931 :     {
     346       32931 :         Release();
     347       65862 :     }
     348             : 
     349           0 :     operator bool() const
     350             :     {
     351           0 :         return fHaveGrant;
     352             :     }
     353             : };
     354             : 
     355             : // Utility class for indicating to compiler thread analysis that a mutex is
     356             : // locked (when it couldn't be determined otherwise).
     357             : struct SCOPED_LOCKABLE LockAssertion
     358             : {
     359             :     template <typename Mutex>
     360      156776 :     explicit LockAssertion(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
     361       78388 :     {
     362             : #ifdef DEBUG_LOCKORDER
     363             :         AssertLockHeld(mutex);
     364             : #endif
     365      156776 :     }
     366      156776 :     ~LockAssertion() UNLOCK_FUNCTION() {}
     367             : };
     368             : 
     369             : #endif // BITCOIN_SYNC_H

Generated by: LCOV version 1.15