#include "test.h" #include #include #include // A very primitive mutex annotated with tsan annotations. class Mutex { public: Mutex(bool prof, unsigned create_flags, unsigned destroy_flags=0) : prof_(prof) , locked_(false) , seq_(0) , destroy_flags_(destroy_flags) { __tsan_mutex_create(this, create_flags); } ~Mutex() { __tsan_mutex_destroy(this, destroy_flags_); } void Lock() { __tsan_mutex_pre_lock(this, 0); LockImpl(); __tsan_mutex_post_lock(this, 0, 0); } bool TryLock() { __tsan_mutex_pre_lock(this, __tsan_mutex_try_lock); bool ok = TryLockImpl(); __tsan_mutex_post_lock(this, __tsan_mutex_try_lock | (ok ? 0 : __tsan_mutex_try_lock_failed), 0); return ok; } void Unlock() { __tsan_mutex_pre_unlock(this, 0); UnlockImpl(); __tsan_mutex_post_unlock(this, 0); } void Wait() { for (int seq = seq_; seq == seq_;) { Unlock(); usleep(100); Lock(); } } void Broadcast() { __tsan_mutex_pre_signal(this, 0); LockImpl(false); seq_++; UnlockImpl(); __tsan_mutex_post_signal(this, 0); } private: const bool prof_; std::atomic locked_; int seq_; unsigned destroy_flags_; // This models mutex profiling subsystem. static Mutex prof_mu_; static int prof_data_; void LockImpl(bool prof = true) { while (!TryLockImpl()) usleep(100); if (prof && prof_) Prof(); } bool TryLockImpl() { return !locked_.exchange(true); } void UnlockImpl() { locked_.store(false); } void Prof() { // This happens inside of mutex lock annotations. __tsan_mutex_pre_divert(this, 0); prof_mu_.Lock(); prof_data_++; prof_mu_.Unlock(); __tsan_mutex_post_divert(this, 0); } }; Mutex Mutex::prof_mu_(false, __tsan_mutex_linker_init); int Mutex::prof_data_;