util/stdmutex.h: Add STDLOCK() and improve annotation checking for StdMutex

StdLockGuard and clang's thread safety annotations did not ensure that
the lock it was taking was not already held. Add a STDLOCK() macro which
uses an annotated StdMutex::CheckNotHeld() function to correct that.
This commit is contained in:
Anthony Towns
2026-03-23 13:40:53 +10:00
parent cdaf2f20ae
commit e196cf26e0

View File

@@ -10,6 +10,8 @@
// Thread Safety Analysis and provides appropriate annotation macros.
#include <threadsafety.h> // IWYU pragma: export
#include <util/macros.h>
#include <mutex>
// StdMutex provides an annotated version of std::mutex for us,
@@ -23,15 +25,21 @@ public:
//! with the ! operator, to indicate that a mutex should not be held.
const StdMutex& operator!() const { return *this; }
#endif // __clang__
// StdMutex::Guard provides an annotated version of std::lock_guard for us.
class SCOPED_LOCKABLE Guard : public std::lock_guard<StdMutex>
{
public:
explicit Guard(StdMutex& cs) EXCLUSIVE_LOCK_FUNCTION(cs) : std::lock_guard<StdMutex>(cs) {}
~Guard() UNLOCK_FUNCTION() = default;
};
static inline StdMutex& CheckNotHeld(StdMutex& cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) LOCK_RETURNED(cs) { return cs; }
};
// StdLockGuard provides an annotated version of std::lock_guard for us,
// and should only be used when sync.h Mutex/LOCK/etc are not usable.
class SCOPED_LOCKABLE StdLockGuard : public std::lock_guard<StdMutex>
{
public:
explicit StdLockGuard(StdMutex& cs) EXCLUSIVE_LOCK_FUNCTION(cs) : std::lock_guard<StdMutex>(cs) {}
~StdLockGuard() UNLOCK_FUNCTION() = default;
};
// Provide STDLOCK(..) wrapper around StdMutex::Guard that checks the lock is not already held
#define STDLOCK(cs) StdMutex::Guard UNIQUE_NAME(criticalblock){StdMutex::CheckNotHeld(cs)}
using StdLockGuard = StdMutex::Guard; // TODO: remove, provided for backwards compat only
#endif // BITCOIN_UTIL_STDMUTEX_H