sync.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-present 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 // This header declares threading primitives compatible with Clang 10 // Thread Safety Analysis and provides appropriate annotation macros. 11 #include <threadsafety.h> // IWYU pragma: export 12 #include <util/macros.h> 13 14 #include <cassert> 15 #include <condition_variable> 16 #include <mutex> 17 #include <string> 18 #include <thread> 19 20 //////////////////////////////////////////////// 21 // // 22 // THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE // 23 // // 24 //////////////////////////////////////////////// 25 26 /* 27 RecursiveMutex mutex; 28 std::recursive_mutex mutex; 29 30 LOCK(mutex); 31 std::unique_lock<std::recursive_mutex> criticalblock(mutex); 32 33 LOCK2(mutex1, mutex2); 34 std::unique_lock<std::recursive_mutex> criticalblock1(mutex1); 35 std::unique_lock<std::recursive_mutex> criticalblock2(mutex2); 36 37 TRY_LOCK(mutex, name); 38 std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t); 39 */ 40 41 /////////////////////////////// 42 // // 43 // THE ACTUAL IMPLEMENTATION // 44 // // 45 /////////////////////////////// 46 47 #ifdef DEBUG_LOCKORDER 48 template <typename MutexType> 49 void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false); 50 void LeaveCritical(); 51 void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line); 52 template <typename MutexType> 53 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs); 54 template <typename MutexType> 55 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs); 56 void DeleteLock(void* cs); 57 bool LockStackEmpty(); 58 59 /** 60 * Call abort() if a potential lock order deadlock bug is detected, instead of 61 * just logging information and throwing a logic_error. Defaults to true, and 62 * set to false in DEBUG_LOCKORDER unit tests. 63 */ 64 extern bool g_debug_lockorder_abort; 65 #else 66 template <typename MutexType> 67 inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {} 68 inline void LeaveCritical() {} 69 inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {} 70 template <typename MutexType> 71 inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {} 72 template <typename MutexType> 73 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {} 74 inline void DeleteLock(void* cs) {} 75 inline bool LockStackEmpty() { return true; } 76 #endif 77 78 /* 79 * Called when a mutex fails to lock immediately because it is held by another 80 * thread, or spuriously. Responsible for locking the lock before returning. 81 */ 82 #ifdef DEBUG_LOCKCONTENTION 83 84 template <typename LockType> 85 void ContendedLock(std::string_view name, std::string_view file, int nLine, LockType& lock); 86 #endif 87 88 /** 89 * Template mixin that adds -Wthread-safety locking annotations and lock order 90 * checking to a subset of the mutex API. 91 */ 92 template <typename PARENT> 93 class LOCKABLE AnnotatedMixin : public PARENT 94 { 95 public: 96 ~AnnotatedMixin() { 97 DeleteLock((void*)this); 98 } 99 100 void lock() EXCLUSIVE_LOCK_FUNCTION() 101 { 102 PARENT::lock(); 103 } 104 105 void unlock() UNLOCK_FUNCTION() 106 { 107 PARENT::unlock(); 108 } 109 110 bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) 111 { 112 return PARENT::try_lock(); 113 } 114 115 using unique_lock = std::unique_lock<PARENT>; 116 #ifdef __clang__ 117 //! For negative capabilities in the Clang Thread Safety Analysis. 118 //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction 119 //! with the ! operator, to indicate that a mutex should not be held. 120 const AnnotatedMixin& operator!() const { return *this; } 121 #endif // __clang__ 122 }; 123 124 /** 125 * Wrapped mutex: supports recursive locking, but no waiting 126 * TODO: We should move away from using the recursive lock by default. 127 */ 128 using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>; 129 130 /** Wrapped mutex: supports waiting but not recursive locking */ 131 using Mutex = AnnotatedMixin<std::mutex>; 132 133 /** Different type to mark Mutex at global scope 134 * 135 * Thread safety analysis can't handle negative assertions about mutexes 136 * with global scope well, so mark them with a separate type, and 137 * eventually move all the mutexes into classes so they are not globally 138 * visible. 139 * 140 * See: https://github.com/bitcoin/bitcoin/pull/20272#issuecomment-720755781 141 */ 142 class GlobalMutex : public Mutex { }; 143 144 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) 145 146 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); } 147 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } 148 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } 149 #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) 150 151 /** Wrapper around std::unique_lock style lock for MutexType. */ 152 template <typename MutexType> 153 class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock 154 { 155 private: 156 using Base = typename MutexType::unique_lock; 157 158 void Enter(const char* pszName, const char* pszFile, int nLine) 159 { 160 EnterCritical(pszName, pszFile, nLine, Base::mutex()); 161 #ifdef DEBUG_LOCKCONTENTION 162 if (!Base::try_lock()) { 163 ContendedLock(pszName, pszFile, nLine, static_cast<Base&>(*this)); 164 } 165 #else 166 Base::lock(); 167 #endif 168 } 169 170 bool TryEnter(const char* pszName, const char* pszFile, int nLine) 171 { 172 EnterCritical(pszName, pszFile, nLine, Base::mutex(), true); 173 if (Base::try_lock()) { 174 return true; 175 } 176 LeaveCritical(); 177 return false; 178 } 179 180 public: 181 UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) 182 { 183 if (fTry) 184 TryEnter(pszName, pszFile, nLine); 185 else 186 Enter(pszName, pszFile, nLine); 187 } 188 189 UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) 190 { 191 if (!pmutexIn) return; 192 193 *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock); 194 if (fTry) 195 TryEnter(pszName, pszFile, nLine); 196 else 197 Enter(pszName, pszFile, nLine); 198 } 199 200 ~UniqueLock() UNLOCK_FUNCTION() 201 { 202 if (Base::owns_lock()) 203 LeaveCritical(); 204 } 205 206 operator bool() 207 { 208 return Base::owns_lock(); 209 } 210 211 protected: 212 // needed for reverse_lock 213 UniqueLock() = default; 214 215 public: 216 /** 217 * An RAII-style reverse lock. Unlocks on construction and locks on destruction. 218 */ 219 class SCOPED_LOCKABLE reverse_lock { 220 public: 221 explicit reverse_lock(UniqueLock& _lock, const MutexType& mutex, const char* _guardname, const char* _file, int _line) UNLOCK_FUNCTION(mutex) : lock(_lock), file(_file), line(_line) { 222 // Ensure that mutex passed back for thread-safety analysis is indeed the original 223 assert(std::addressof(mutex) == lock.mutex()); 224 225 CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line); 226 lock.unlock(); 227 LeaveCritical(); 228 lock.swap(templock); 229 } 230 231 ~reverse_lock() UNLOCK_FUNCTION() { 232 templock.swap(lock); 233 EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex()); 234 lock.lock(); 235 } 236 237 private: 238 reverse_lock(reverse_lock const&); 239 reverse_lock& operator=(reverse_lock const&); 240 241 UniqueLock& lock; 242 UniqueLock templock; 243 std::string lockname; 244 const std::string file; 245 const int line; 246 }; 247 friend class reverse_lock; 248 }; 249 250 // clang's thread-safety analyzer is unable to deal with aliases of mutexes, so 251 // it is not possible to use the lock's copy of the mutex for that purpose. 252 // Instead, the original mutex needs to be passed back to the reverse_lock for 253 // the sake of thread-safety analysis, but it is not actually used otherwise. 254 #define REVERSE_LOCK(g, cs) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, cs, #cs, __FILE__, __LINE__) 255 256 // When locking a Mutex, require negative capability to ensure the lock 257 // is not already held 258 inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; } 259 inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; } 260 261 // When locking a GlobalMutex or RecursiveMutex, just check it is not 262 // locked in the surrounding scope. 263 template <typename MutexType> 264 inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } 265 template <typename MutexType> 266 inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } 267 268 #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) 269 #define LOCK2(cs1, cs2) \ 270 UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \ 271 UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__) 272 #define LOCK_ARGS(cs) MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__ 273 #define TRY_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs), true) 274 #define WAIT_LOCK(cs, name) UniqueLock name(LOCK_ARGS(cs)) 275 276 //! Run code while locking a mutex. 277 //! 278 //! Examples: 279 //! 280 //! WITH_LOCK(cs, shared_val = shared_val + 1); 281 //! 282 //! int val = WITH_LOCK(cs, return shared_val); 283 //! 284 //! Note: 285 //! 286 //! Since the return type deduction follows that of decltype(auto), while the 287 //! deduced type of: 288 //! 289 //! WITH_LOCK(cs, int i = 1; return i); 290 //! 291 //! is int, the deduced type of: 292 //! 293 //! WITH_LOCK(cs, int j = 1; return (j)); 294 //! 295 //! is &int, a reference to a local variable 296 //! 297 //! The above is detectable at compile-time with the -Wreturn-local-addr flag in 298 //! gcc and the -Wreturn-stack-address flag in clang, both enabled by default. 299 #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) 300 301 #endif // BITCOIN_SYNC_H