/ 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  // 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