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