sync.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto 2 // Copyright (c) 2009-2022 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> // IWYU pragma: export 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 template <typename MutexType> 61 void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs); 62 template <typename MutexType> 63 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs); 64 void DeleteLock(void* cs); 65 bool LockStackEmpty(); 66 67 /** 68 * Call abort() if a potential lock order deadlock bug is detected, instead of 69 * just logging information and throwing a logic_error. Defaults to true, and 70 * set to false in DEBUG_LOCKORDER unit tests. 71 */ 72 extern bool g_debug_lockorder_abort; 73 #else 74 template <typename MutexType> 75 inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {} 76 inline void LeaveCritical() {} 77 inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {} 78 template <typename MutexType> 79 inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {} 80 template <typename MutexType> 81 void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) LOCKS_EXCLUDED(cs) {} 82 inline void DeleteLock(void* cs) {} 83 inline bool LockStackEmpty() { return true; } 84 #endif 85 86 /** 87 * Template mixin that adds -Wthread-safety locking annotations and lock order 88 * checking to a subset of the mutex API. 89 */ 90 template <typename PARENT> 91 class LOCKABLE AnnotatedMixin : public PARENT 92 { 93 public: 94 ~AnnotatedMixin() { 95 DeleteLock((void*)this); 96 } 97 98 void lock() EXCLUSIVE_LOCK_FUNCTION() 99 { 100 PARENT::lock(); 101 } 102 103 void unlock() UNLOCK_FUNCTION() 104 { 105 PARENT::unlock(); 106 } 107 108 bool try_lock() EXCLUSIVE_TRYLOCK_FUNCTION(true) 109 { 110 return PARENT::try_lock(); 111 } 112 113 using unique_lock = std::unique_lock<PARENT>; 114 #ifdef __clang__ 115 //! For negative capabilities in the Clang Thread Safety Analysis. 116 //! A negative requirement uses the EXCLUSIVE_LOCKS_REQUIRED attribute, in conjunction 117 //! with the ! operator, to indicate that a mutex should not be held. 118 const AnnotatedMixin& operator!() const { return *this; } 119 #endif // __clang__ 120 }; 121 122 /** 123 * Wrapped mutex: supports recursive locking, but no waiting 124 * TODO: We should move away from using the recursive lock by default. 125 */ 126 using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>; 127 128 /** Wrapped mutex: supports waiting but not recursive locking */ 129 using Mutex = AnnotatedMixin<std::mutex>; 130 131 /** Different type to mark Mutex at global scope 132 * 133 * Thread safety analysis can't handle negative assertions about mutexes 134 * with global scope well, so mark them with a separate type, and 135 * eventually move all the mutexes into classes so they are not globally 136 * visible. 137 * 138 * See: https://github.com/bitcoin/bitcoin/pull/20272#issuecomment-720755781 139 */ 140 class GlobalMutex : public Mutex { }; 141 142 #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) 143 144 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) { AssertLockNotHeldInternal(name, file, line, cs); } 145 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, RecursiveMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } 146 inline void AssertLockNotHeldInline(const char* name, const char* file, int line, GlobalMutex* cs) LOCKS_EXCLUDED(cs) { AssertLockNotHeldInternal(name, file, line, cs); } 147 #define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs) 148 149 /** Wrapper around std::unique_lock style lock for MutexType. */ 150 template <typename MutexType> 151 class SCOPED_LOCKABLE UniqueLock : public MutexType::unique_lock 152 { 153 private: 154 using Base = typename MutexType::unique_lock; 155 156 void Enter(const char* pszName, const char* pszFile, int nLine) 157 { 158 EnterCritical(pszName, pszFile, nLine, Base::mutex()); 159 #ifdef DEBUG_LOCKCONTENTION 160 if (Base::try_lock()) return; 161 LOG_TIME_MICROS_WITH_CATEGORY(strprintf("lock contention %s, %s:%d", pszName, pszFile, nLine), BCLog::LOCK); 162 #endif 163 Base::lock(); 164 } 165 166 bool TryEnter(const char* pszName, const char* pszFile, int nLine) 167 { 168 EnterCritical(pszName, pszFile, nLine, Base::mutex(), true); 169 if (Base::try_lock()) { 170 return true; 171 } 172 LeaveCritical(); 173 return false; 174 } 175 176 public: 177 UniqueLock(MutexType& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock) 178 { 179 if (fTry) 180 TryEnter(pszName, pszFile, nLine); 181 else 182 Enter(pszName, pszFile, nLine); 183 } 184 185 UniqueLock(MutexType* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) 186 { 187 if (!pmutexIn) return; 188 189 *static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock); 190 if (fTry) 191 TryEnter(pszName, pszFile, nLine); 192 else 193 Enter(pszName, pszFile, nLine); 194 } 195 196 ~UniqueLock() UNLOCK_FUNCTION() 197 { 198 if (Base::owns_lock()) 199 LeaveCritical(); 200 } 201 202 operator bool() 203 { 204 return Base::owns_lock(); 205 } 206 207 protected: 208 // needed for reverse_lock 209 UniqueLock() { } 210 211 public: 212 /** 213 * An RAII-style reverse lock. Unlocks on construction and locks on destruction. 214 */ 215 class reverse_lock { 216 public: 217 explicit reverse_lock(UniqueLock& _lock, const char* _guardname, const char* _file, int _line) : lock(_lock), file(_file), line(_line) { 218 CheckLastCritical((void*)lock.mutex(), lockname, _guardname, _file, _line); 219 lock.unlock(); 220 LeaveCritical(); 221 lock.swap(templock); 222 } 223 224 ~reverse_lock() { 225 templock.swap(lock); 226 EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex()); 227 lock.lock(); 228 } 229 230 private: 231 reverse_lock(reverse_lock const&); 232 reverse_lock& operator=(reverse_lock const&); 233 234 UniqueLock& lock; 235 UniqueLock templock; 236 std::string lockname; 237 const std::string file; 238 const int line; 239 }; 240 friend class reverse_lock; 241 }; 242 243 #define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock UNIQUE_NAME(revlock)(g, #g, __FILE__, __LINE__) 244 245 // When locking a Mutex, require negative capability to ensure the lock 246 // is not already held 247 inline Mutex& MaybeCheckNotHeld(Mutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; } 248 inline Mutex* MaybeCheckNotHeld(Mutex* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; } 249 250 // When locking a GlobalMutex or RecursiveMutex, just check it is not 251 // locked in the surrounding scope. 252 template <typename MutexType> 253 inline MutexType& MaybeCheckNotHeld(MutexType& m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } 254 template <typename MutexType> 255 inline MutexType* MaybeCheckNotHeld(MutexType* m) LOCKS_EXCLUDED(m) LOCK_RETURNED(m) { return m; } 256 257 #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) 258 #define LOCK2(cs1, cs2) \ 259 UniqueLock criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \ 260 UniqueLock criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__) 261 #define TRY_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true) 262 #define WAIT_LOCK(cs, name) UniqueLock name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) 263 264 #define ENTER_CRITICAL_SECTION(cs) \ 265 { \ 266 EnterCritical(#cs, __FILE__, __LINE__, &cs); \ 267 (cs).lock(); \ 268 } 269 270 #define LEAVE_CRITICAL_SECTION(cs) \ 271 { \ 272 std::string lockname; \ 273 CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \ 274 (cs).unlock(); \ 275 LeaveCritical(); \ 276 } 277 278 //! Run code while locking a mutex. 279 //! 280 //! Examples: 281 //! 282 //! WITH_LOCK(cs, shared_val = shared_val + 1); 283 //! 284 //! int val = WITH_LOCK(cs, return shared_val); 285 //! 286 //! Note: 287 //! 288 //! Since the return type deduction follows that of decltype(auto), while the 289 //! deduced type of: 290 //! 291 //! WITH_LOCK(cs, return {int i = 1; return i;}); 292 //! 293 //! is int, the deduced type of: 294 //! 295 //! WITH_LOCK(cs, return {int j = 1; return (j);}); 296 //! 297 //! is &int, a reference to a local variable 298 //! 299 //! The above is detectable at compile-time with the -Wreturn-local-addr flag in 300 //! gcc and the -Wreturn-stack-address flag in clang, both enabled by default. 301 #define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }()) 302 303 /** An implementation of a semaphore. 304 * 305 * See https://en.wikipedia.org/wiki/Semaphore_(programming) 306 */ 307 class CSemaphore 308 { 309 private: 310 std::condition_variable condition; 311 std::mutex mutex; 312 int value; 313 314 public: 315 explicit CSemaphore(int init) noexcept : value(init) {} 316 317 // Disallow default construct, copy, move. 318 CSemaphore() = delete; 319 CSemaphore(const CSemaphore&) = delete; 320 CSemaphore(CSemaphore&&) = delete; 321 CSemaphore& operator=(const CSemaphore&) = delete; 322 CSemaphore& operator=(CSemaphore&&) = delete; 323 324 void wait() noexcept 325 { 326 std::unique_lock<std::mutex> lock(mutex); 327 condition.wait(lock, [&]() { return value >= 1; }); 328 value--; 329 } 330 331 bool try_wait() noexcept 332 { 333 std::lock_guard<std::mutex> lock(mutex); 334 if (value < 1) { 335 return false; 336 } 337 value--; 338 return true; 339 } 340 341 void post() noexcept 342 { 343 { 344 std::lock_guard<std::mutex> lock(mutex); 345 value++; 346 } 347 condition.notify_one(); 348 } 349 }; 350 351 /** RAII-style semaphore lock */ 352 class CSemaphoreGrant 353 { 354 private: 355 CSemaphore* sem; 356 bool fHaveGrant; 357 358 public: 359 void Acquire() noexcept 360 { 361 if (fHaveGrant) { 362 return; 363 } 364 sem->wait(); 365 fHaveGrant = true; 366 } 367 368 void Release() noexcept 369 { 370 if (!fHaveGrant) { 371 return; 372 } 373 sem->post(); 374 fHaveGrant = false; 375 } 376 377 bool TryAcquire() noexcept 378 { 379 if (!fHaveGrant && sem->try_wait()) { 380 fHaveGrant = true; 381 } 382 return fHaveGrant; 383 } 384 385 // Disallow copy. 386 CSemaphoreGrant(const CSemaphoreGrant&) = delete; 387 CSemaphoreGrant& operator=(const CSemaphoreGrant&) = delete; 388 389 // Allow move. 390 CSemaphoreGrant(CSemaphoreGrant&& other) noexcept 391 { 392 sem = other.sem; 393 fHaveGrant = other.fHaveGrant; 394 other.fHaveGrant = false; 395 other.sem = nullptr; 396 } 397 398 CSemaphoreGrant& operator=(CSemaphoreGrant&& other) noexcept 399 { 400 Release(); 401 sem = other.sem; 402 fHaveGrant = other.fHaveGrant; 403 other.fHaveGrant = false; 404 other.sem = nullptr; 405 return *this; 406 } 407 408 CSemaphoreGrant() noexcept : sem(nullptr), fHaveGrant(false) {} 409 410 explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) noexcept : sem(&sema), fHaveGrant(false) 411 { 412 if (fTry) { 413 TryAcquire(); 414 } else { 415 Acquire(); 416 } 417 } 418 419 ~CSemaphoreGrant() 420 { 421 Release(); 422 } 423 424 explicit operator bool() const noexcept 425 { 426 return fHaveGrant; 427 } 428 }; 429 430 #endif // BITCOIN_SYNC_H