Tsan fix
diff --git a/include/perfetto/base/thread_annotations.h b/include/perfetto/base/thread_annotations.h index 3d91269..691b521 100644 --- a/include/perfetto/base/thread_annotations.h +++ b/include/perfetto/base/thread_annotations.h
@@ -55,6 +55,26 @@ #include "perfetto/base/build_config.h" +#ifdef THREAD_SANITIZER +#include <sanitizer/tsan_interface.h> + +#define PERFETTO_TSAN_MUTEX_CREATE __tsan_mutex_create +#define PERFETTO_TSAN_MUTEX_DESTROY __tsan_mutex_destroy +#define PERFETTO_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock +#define PERFETTO_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock +#define PERFETTO_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock +#define PERFETTO_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock +#else + +#define PERFETTO_TSAN_MUTEX_CREATE(...) +#define PERFETTO_TSAN_MUTEX_DESTROY(...) +#define PERFETTO_TSAN_MUTEX_PRE_LOCK(...) +#define PERFETTO_TSAN_MUTEX_POST_LOCK(...) +#define PERFETTO_TSAN_MUTEX_PRE_UNLOCK(...) +#define PERFETTO_TSAN_MUTEX_POST_UNLOCK(...) + +#endif + #if defined(__clang__) && PERFETTO_BUILDFLAG(PERFETTO_THREAD_SAFETY_ANNOTATIONS) #define PERFETTO_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else
diff --git a/include/perfetto/ext/base/rt_mutex.h b/include/perfetto/ext/base/rt_mutex.h index 8b8053c..764186c 100644 --- a/include/perfetto/ext/base/rt_mutex.h +++ b/include/perfetto/ext/base/rt_mutex.h
@@ -30,6 +30,7 @@ // https://github.com/MicrosoftDocs/win32/commit/a43cb3b5039c5cfc53642bfcea174003a2f1168f #include "perfetto/base/build_config.h" +#include "perfetto/base/thread_annotations.h" // Note: PERFETTO_HAS_RT_FUTEX() does not imply that we will use futexes. For // now the usage of futexes is gated behind a runtime flag (for experiment @@ -91,8 +92,8 @@ // waiters. class PERFETTO_LOCKABLE RtFutex { public: - RtFutex() = default; - ~RtFutex() = default; + RtFutex() { PERFETTO_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); } + ~RtFutex() { PERFETTO_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } // Disable copy or move. Copy doesn't make sense. Move isn't feasible because // the pointer to the atomic integer is the handle used by the kernel to setup @@ -112,29 +113,37 @@ } bool try_lock() noexcept PERFETTO_EXCLUSIVE_TRYLOCK_FUNCTION(true) { - if (PERFETTO_LIKELY(TryLockFastpath())) { + PERFETTO_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock); + if (PERFETTO_LIKELY(TryLockFastpath()) || TryLockSlowpath()) { + PERFETTO_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0); return true; } - return TryLockSlowpath(); + PERFETTO_TSAN_MUTEX_POST_LOCK( + this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0); + return false; } void lock() PERFETTO_EXCLUSIVE_LOCK_FUNCTION() { + PERFETTO_TSAN_MUTEX_PRE_LOCK(this, 0); if (!PERFETTO_LIKELY(TryLockFastpath())) { LockSlowpath(); } + PERFETTO_TSAN_MUTEX_POST_LOCK(this, 0, 0); } void unlock() noexcept PERFETTO_UNLOCK_FUNCTION() { + PERFETTO_TSAN_MUTEX_PRE_UNLOCK(this, 0); int expected = GetTid(); - if (lock_.compare_exchange_strong(expected, 0, std::memory_order_release, - std::memory_order_relaxed)) { - // If the current value is our tid, we can unlock without a syscall since - // there are no current waiters. - return; + // If the current value is our tid, we can unlock without a syscall since + // there are no current waiters. + if (!PERFETTO_LIKELY(lock_.compare_exchange_strong( + expected, 0, std::memory_order_release, + std::memory_order_relaxed))) { + // The tid doesn't match because the kernel appended the FUTEX_WAITERS + // bit. There are waiters, tell the kernel to notify them and unlock. + UnlockSlowpath(); } - // The tid doesn't match because the kernel appended the FUTEX_WAITERS bit. - // There are waiters, tell the kernel to notify them and unlock. - UnlockSlowpath(); + PERFETTO_TSAN_MUTEX_POST_UNLOCK(this, 0); } private:
diff --git a/src/base/rt_mutex_benchmark.cc b/src/base/rt_mutex_benchmark.cc index ac0f924..7f2ed8a 100644 --- a/src/base/rt_mutex_benchmark.cc +++ b/src/base/rt_mutex_benchmark.cc
@@ -38,8 +38,8 @@ for (auto _ : state) { mutex.lock(); n++; - mutex.unlock(); benchmark::DoNotOptimize(n); + mutex.unlock(); benchmark::ClobberMemory(); } } @@ -55,8 +55,8 @@ while (!stop.load(std::memory_order_relaxed)) { mutex.lock(); counter++; - mutex.unlock(); benchmark::DoNotOptimize(counter); + mutex.unlock(); } };