LCOV - code coverage report
Current view: top level - src - sync.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 121 123 98.4 %
Date: 2021-06-29 14:35:33 Functions: 98 100 98.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 24 30 80.0 %

           Branch data     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                 :            : template <typename MutexType>
#      52                 :            : void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false);
#      53                 :            : void LeaveCritical();
#      54                 :            : void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
#      55                 :            : std::string LocksHeld();
#      56                 :            : template <typename MutexType>
#      57                 :            : void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
#      58                 :            : template <typename MutexType>
#      59                 :            : void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs);
#      60                 :            : void DeleteLock(void* cs);
#      61                 :            : bool LockStackEmpty();
#      62                 :            : 
#      63                 :            : /**
#      64                 :            :  * Call abort() if a potential lock order deadlock bug is detected, instead of
#      65                 :            :  * just logging information and throwing a logic_error. Defaults to true, and
#      66                 :            :  * set to false in DEBUG_LOCKORDER unit tests.
#      67                 :            :  */
#      68                 :            : extern bool g_debug_lockorder_abort;
#      69                 :            : #else
#      70                 :            : template <typename MutexType>
#      71                 :            : inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {}
#      72                 :            : inline void LeaveCritical() {}
#      73                 :            : inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
#      74                 :            : template <typename MutexType>
#      75                 :            : inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
#      76                 :            : template <typename MutexType>
#      77                 :            : void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {}
#      78                 :            : inline void DeleteLock(void* cs) {}
#      79                 :            : inline bool LockStackEmpty() { return true; }
#      80                 :            : #endif
#      81                 :   22770242 : #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
#      82                 :     325431 : #define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
#      83                 :            : 
#      84                 :            : /**
#      85                 :            :  * Template mixin that adds -Wthread-safety locking annotations and lock order
#      86                 :            :  * checking to a subset of the mutex API.
#      87                 :            :  */
#      88                 :            : template <typename PARENT>
#      89                 :            : class LOCKABLE AnnotatedMixin : public PARENT
#      90                 :            : {
#      91                 :            : public:
#      92                 :      94977 :     ~AnnotatedMixin() {
#      93                 :      94977 :         DeleteLock((void*)this);
#      94                 :      94977 :     }
#      95                 :            : 
#      96                 :            :     void lock() EXCLUSIVE_LOCK_FUNCTION()
#      97                 :      92215 :     {
#      98                 :      92215 :         PARENT::lock();
#      99                 :      92215 :     }
#     100                 :            : 
#     101                 :            :     void unlock() UNLOCK_FUNCTION()
#     102                 :      92215 :     {
#     103                 :      92215 :         PARENT::unlock();
#     104                 :      92215 :     }
#     105                 :            : 
#     106                 :            :     bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true)
#     107                 :        400 :     {
#     108                 :        400 :         return PARENT::try_lock();
#     109                 :        400 :     }
#     110                 :            : 
#     111                 :            :     using UniqueLock = std::unique_lock<PARENT>;
#     112                 :            : #ifdef __clang__
#     113                 :            :     //! For negative capabilities in the Clang Thread Safety Analysis.
#     114                 :            :     //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction
#     115                 :            :     //! with the ! operator, to indicate that a mutex should not be held.
#     116                 :            :     const AnnotatedMixin& operator!() const { return *this; }
#     117                 :            : #endif // __clang__
#     118                 :            : };
#     119                 :            : 
#     120                 :            : /**
#     121                 :            :  * Wrapped mutex: supports recursive locking, but no waiting
#     122                 :            :  * TODO: We should move away from using the recursive lock by default.
#     123                 :            :  */
#     124                 :            : using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;
#     125                 :            : 
#     126                 :            : /** Wrapped mutex: supports waiting but not recursive locking */
#     127                 :            : typedef AnnotatedMixin<std::mutex> Mutex;
#     128                 :            : 
#     129                 :            : #ifdef DEBUG_LOCKCONTENTION
#     130                 :            : void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
#     131                 :            : #endif
#     132                 :            : 
#     133                 :            : /** Wrapper around std::unique_lock style lock for Mutex. */
#     134                 :            : template <typename Mutex, typename Base = typename Mutex::UniqueLock>
#     135                 :            : class SCOPED_LOCKABLE UniqueLock : public Base
#     136                 :            : {
#     137                 :            : private:
#     138                 :            :     void Enter(const char* pszName, const char* pszFile, int nLine)
#     139                 :  115598309 :     {
#     140                 :  115598309 :         EnterCritical(pszName, pszFile, nLine, Base::mutex());
#     141                 :            : #ifdef DEBUG_LOCKCONTENTION
#     142                 :            :         if (!Base::try_lock()) {
#     143                 :            :             PrintLockContention(pszName, pszFile, nLine);
#     144                 :            : #endif
#     145                 :  115598309 :             Base::lock();
#     146                 :            : #ifdef DEBUG_LOCKCONTENTION
#     147                 :            :         }
#     148                 :            : #endif
#     149                 :  115598309 :     }
#     150                 :            : 
#     151                 :            :     bool TryEnter(const char* pszName, const char* pszFile, int nLine)
#     152                 :        956 :     {
#     153                 :        956 :         EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
#     154                 :        956 :         Base::try_lock();
#     155 [ +  + ][ -  + ]:        956 :         if (!Base::owns_lock())
#     156                 :          7 :             LeaveCritical();
#     157                 :        956 :         return Base::owns_lock();
#     158                 :        956 :     }
#     159                 :            : 
#     160                 :            : public:
#     161                 :            :     UniqueLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
#     162                 :  115600092 :     {
#     163 [ +  + ][ +  + ]:  115600092 :         if (fTry)
#     164                 :        956 :             TryEnter(pszName, pszFile, nLine);
#     165                 :  115599136 :         else
#     166                 :  115599136 :             Enter(pszName, pszFile, nLine);
#     167                 :  115600092 :     }
#     168                 :            : 
#     169                 :            :     UniqueLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
#     170                 :            :     {
#     171                 :            :         if (!pmutexIn) return;
#     172                 :            : 
#     173                 :            :         *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
#     174                 :            :         if (fTry)
#     175                 :            :             TryEnter(pszName, pszFile, nLine);
#     176                 :            :         else
#     177                 :            :             Enter(pszName, pszFile, nLine);
#     178                 :            :     }
#     179                 :            : 
#     180                 :            :     ~UniqueLock() UNLOCK_FUNCTION()
#     181                 :  116394331 :     {
#     182 [ +  + ][ +  + ]:  116394331 :         if (Base::owns_lock())
#     183                 :  115602050 :             LeaveCritical();
#     184                 :  116394331 :     }
#     185                 :            : 
#     186                 :            :     operator bool()
#     187                 :        956 :     {
#     188                 :        956 :         return Base::owns_lock();
#     189                 :        956 :     }
#     190                 :            : 
#     191                 :            : protected:
#     192                 :            :     // needed for reverse_lock
#     193                 :     792164 :     UniqueLock() { }
#     194                 :            : 
#     195                 :            : public:
#     196                 :            :     /**
#     197                 :            :      * An RAII-style reverse lock. Unlocks on construction and locks on destruction.
#     198                 :            :      */
#     199                 :            :     class reverse_lock {
#     200                 :            :     public:
#     201                 :     792164 :         explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) {
#     202                 :     792164 :             CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line);
#     203                 :     792164 :             lock.unlock();
#     204                 :     792164 :             LeaveCritical();
#     205                 :     792164 :             lock.swap(templock);
#     206                 :     792164 :         }
#     207                 :            : 
#     208                 :     792158 :         ~reverse_lock() {
#     209                 :     792158 :             templock.swap(lock);
#     210                 :     792158 :             EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex());
#     211                 :     792158 :             lock.lock();
#     212                 :     792158 :         }
#     213                 :            : 
#     214                 :            :      private:
#     215                 :            :         reverse_lock(reverse_lock const&);
#     216                 :            :         reverse_lock& operator=(reverse_lock const&);
#     217                 :            : 
#     218                 :            :         UniqueLock& lock;
#     219                 :            :         UniqueLock templock;
#     220                 :            :         std::string lockname;
#     221                 :            :         const std::string file;
#     222                 :            :         const int line;
#     223                 :            :      };
#     224                 :            :      friend class reverse_lock;
#     225                 :            : };
#     226                 :            : 
#     227                 :     792162 : #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
#     228                 :            : 
#     229                 :            : template<typename MutexArg>
#     230                 :            : using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
#     231                 :            : 
#     232                 :  111233877 : #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
#     233                 :            : #define LOCK2(cs1, cs2)                                               \
#     234                 :     432688 :     DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
#     235                 :     432688 :     DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
#     236                 :        956 : #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
#     237                 :    4358959 : #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
#     238                 :            : 
#     239                 :            : #define ENTER_CRITICAL_SECTION(cs)                            \
#     240                 :      92201 :     {                                                         \
#     241                 :      92201 :         EnterCritical(#cs, __FILE__, __LINE__, &cs); \
#     242                 :      92201 :         (cs).lock();                                          \
#     243                 :      92201 :     }
#     244                 :            : 
#     245                 :            : #define LEAVE_CRITICAL_SECTION(cs)                                          \
#     246                 :      92201 :     {                                                                       \
#     247                 :      92201 :         std::string lockname;                                               \
#     248                 :      92201 :         CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \
#     249                 :      92201 :         (cs).unlock();                                                      \
#     250                 :      92201 :         LeaveCritical();                                                    \
#     251                 :      92201 :     }
#     252                 :            : 
#     253                 :            : //! Run code while locking a mutex.
#     254                 :            : //!
#     255                 :            : //! Examples:
#     256                 :            : //!
#     257                 :            : //!   WITH_LOCK(cs, shared_val = shared_val + 1);
#     258                 :            : //!
#     259                 :            : //!   int val = WITH_LOCK(cs, return shared_val);
#     260                 :            : //!
#     261                 :            : //! Note:
#     262                 :            : //!
#     263                 :            : //! Since the return type deduction follows that of decltype(auto), while the
#     264                 :            : //! deduced type of:
#     265                 :            : //!
#     266                 :            : //!   WITH_LOCK(cs, return {int i = 1; return i;});
#     267                 :            : //!
#     268                 :            : //! is int, the deduced type of:
#     269                 :            : //!
#     270                 :            : //!   WITH_LOCK(cs, return {int j = 1; return (j);});
#     271                 :            : //!
#     272                 :            : //! is &int, a reference to a local variable
#     273                 :            : //!
#     274                 :            : //! The above is detectable at compile-time with the -Wreturn-local-addr flag in
#     275                 :            : //! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.
#     276 [ +  - ][ +  + ]:     179519 : #define WITH_LOCK(cs, code) [&]() -> decltype(auto) { LOCK(cs); code; }()
#                 [ -  + ]
#     277                 :            : 
#     278                 :            : class CSemaphore
#     279                 :            : {
#     280                 :            : private:
#     281                 :            :     std::condition_variable condition;
#     282                 :            :     std::mutex mutex;
#     283                 :            :     int value;
#     284                 :            : 
#     285                 :            : public:
#     286                 :       1236 :     explicit CSemaphore(int init) : value(init) {}
#     287                 :            : 
#     288                 :            :     void wait()
#     289                 :      25741 :     {
#     290                 :      25741 :         std::unique_lock<std::mutex> lock(mutex);
#     291                 :      25741 :         condition.wait(lock, [&]() { return value >= 1; });
#     292                 :      25741 :         value--;
#     293                 :      25741 :     }
#     294                 :            : 
#     295                 :            :     bool try_wait()
#     296                 :         46 :     {
#     297                 :         46 :         std::lock_guard<std::mutex> lock(mutex);
#     298         [ -  + ]:         46 :         if (value < 1)
#     299                 :          0 :             return false;
#     300                 :         46 :         value--;
#     301                 :         46 :         return true;
#     302                 :         46 :     }
#     303                 :            : 
#     304                 :            :     void post()
#     305                 :      37525 :     {
#     306                 :      37525 :         {
#     307                 :      37525 :             std::lock_guard<std::mutex> lock(mutex);
#     308                 :      37525 :             value++;
#     309                 :      37525 :         }
#     310                 :      37525 :         condition.notify_one();
#     311                 :      37525 :     }
#     312                 :            : };
#     313                 :            : 
#     314                 :            : /** RAII-style semaphore lock */
#     315                 :            : class CSemaphoreGrant
#     316                 :            : {
#     317                 :            : private:
#     318                 :            :     CSemaphore* sem;
#     319                 :            :     bool fHaveGrant;
#     320                 :            : 
#     321                 :            : public:
#     322                 :            :     void Acquire()
#     323                 :      25741 :     {
#     324         [ -  + ]:      25741 :         if (fHaveGrant)
#     325                 :          0 :             return;
#     326                 :      25741 :         sem->wait();
#     327                 :      25741 :         fHaveGrant = true;
#     328                 :      25741 :     }
#     329                 :            : 
#     330                 :            :     void Release()
#     331                 :      27189 :     {
#     332         [ +  + ]:      27189 :         if (!fHaveGrant)
#     333                 :       1402 :             return;
#     334                 :      25787 :         sem->post();
#     335                 :      25787 :         fHaveGrant = false;
#     336                 :      25787 :     }
#     337                 :            : 
#     338                 :            :     bool TryAcquire()
#     339                 :         48 :     {
#     340 [ +  + ][ +  - ]:         48 :         if (!fHaveGrant && sem->try_wait())
#     341                 :         46 :             fHaveGrant = true;
#     342                 :         48 :         return fHaveGrant;
#     343                 :         48 :     }
#     344                 :            : 
#     345                 :            :     void MoveTo(CSemaphoreGrant& grant)
#     346                 :         46 :     {
#     347                 :         46 :         grant.Release();
#     348                 :         46 :         grant.sem = sem;
#     349                 :         46 :         grant.fHaveGrant = fHaveGrant;
#     350                 :         46 :         fHaveGrant = false;
#     351                 :         46 :     }
#     352                 :            : 
#     353                 :       1014 :     CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
#     354                 :            : 
#     355                 :            :     explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
#     356                 :      25787 :     {
#     357         [ +  + ]:      25787 :         if (fTry)
#     358                 :         46 :             TryAcquire();
#     359                 :      25741 :         else
#     360                 :      25741 :             Acquire();
#     361                 :      25787 :     }
#     362                 :            : 
#     363                 :            :     ~CSemaphoreGrant()
#     364                 :      26801 :     {
#     365                 :      26801 :         Release();
#     366                 :      26801 :     }
#     367                 :            : 
#     368                 :            :     operator bool() const
#     369                 :         46 :     {
#     370                 :         46 :         return fHaveGrant;
#     371                 :         46 :     }
#     372                 :            : };
#     373                 :            : 
#     374                 :            : #endif // BITCOIN_SYNC_H

Generated by: LCOV version 1.14