LCOV - code coverage report
Current view: top level - src - sync.h (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 129 132 97.7 %
Date: 2022-04-21 14:51:19 Functions: 112 114 98.2 %
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: 28 34 82.4 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a