18096a8c8SDmitry Vyukov #include "test.h" 28096a8c8SDmitry Vyukov #include <atomic> 38096a8c8SDmitry Vyukov #include <vector> 48096a8c8SDmitry Vyukov #include <sanitizer/tsan_interface.h> 58096a8c8SDmitry Vyukov 68096a8c8SDmitry Vyukov // A very primitive mutex annotated with tsan annotations. 78096a8c8SDmitry Vyukov class Mutex { 88096a8c8SDmitry Vyukov public: 9*9e2cd1c1SDmitry Vyukov Mutex(bool prof, unsigned create_flags, unsigned destroy_flags=0) prof_(prof)108096a8c8SDmitry Vyukov : prof_(prof) 118096a8c8SDmitry Vyukov , locked_(false) 12*9e2cd1c1SDmitry Vyukov , seq_(0) 13*9e2cd1c1SDmitry Vyukov , destroy_flags_(destroy_flags) { 14*9e2cd1c1SDmitry Vyukov __tsan_mutex_create(this, create_flags); 158096a8c8SDmitry Vyukov } 168096a8c8SDmitry Vyukov ~Mutex()178096a8c8SDmitry Vyukov ~Mutex() { 18*9e2cd1c1SDmitry Vyukov __tsan_mutex_destroy(this, destroy_flags_); 198096a8c8SDmitry Vyukov } 208096a8c8SDmitry Vyukov Lock()218096a8c8SDmitry Vyukov void Lock() { 228096a8c8SDmitry Vyukov __tsan_mutex_pre_lock(this, 0); 238096a8c8SDmitry Vyukov LockImpl(); 248096a8c8SDmitry Vyukov __tsan_mutex_post_lock(this, 0, 0); 258096a8c8SDmitry Vyukov } 268096a8c8SDmitry Vyukov TryLock()278096a8c8SDmitry Vyukov bool TryLock() { 288096a8c8SDmitry Vyukov __tsan_mutex_pre_lock(this, __tsan_mutex_try_lock); 298096a8c8SDmitry Vyukov bool ok = TryLockImpl(); 308096a8c8SDmitry Vyukov __tsan_mutex_post_lock(this, __tsan_mutex_try_lock | 318096a8c8SDmitry Vyukov (ok ? 0 : __tsan_mutex_try_lock_failed), 0); 328096a8c8SDmitry Vyukov return ok; 338096a8c8SDmitry Vyukov } 348096a8c8SDmitry Vyukov Unlock()358096a8c8SDmitry Vyukov void Unlock() { 368096a8c8SDmitry Vyukov __tsan_mutex_pre_unlock(this, 0); 378096a8c8SDmitry Vyukov UnlockImpl(); 388096a8c8SDmitry Vyukov __tsan_mutex_post_unlock(this, 0); 398096a8c8SDmitry Vyukov } 408096a8c8SDmitry Vyukov Wait()418096a8c8SDmitry Vyukov void Wait() { 428096a8c8SDmitry Vyukov for (int seq = seq_; seq == seq_;) { 438096a8c8SDmitry Vyukov Unlock(); 448096a8c8SDmitry Vyukov usleep(100); 458096a8c8SDmitry Vyukov Lock(); 468096a8c8SDmitry Vyukov } 478096a8c8SDmitry Vyukov } 488096a8c8SDmitry Vyukov Broadcast()498096a8c8SDmitry Vyukov void Broadcast() { 508096a8c8SDmitry Vyukov __tsan_mutex_pre_signal(this, 0); 518096a8c8SDmitry Vyukov LockImpl(false); 528096a8c8SDmitry Vyukov seq_++; 538096a8c8SDmitry Vyukov UnlockImpl(); 548096a8c8SDmitry Vyukov __tsan_mutex_post_signal(this, 0); 558096a8c8SDmitry Vyukov } 568096a8c8SDmitry Vyukov 578096a8c8SDmitry Vyukov private: 588096a8c8SDmitry Vyukov const bool prof_; 598096a8c8SDmitry Vyukov std::atomic<bool> locked_; 608096a8c8SDmitry Vyukov int seq_; 61*9e2cd1c1SDmitry Vyukov unsigned destroy_flags_; 628096a8c8SDmitry Vyukov 638096a8c8SDmitry Vyukov // This models mutex profiling subsystem. 648096a8c8SDmitry Vyukov static Mutex prof_mu_; 658096a8c8SDmitry Vyukov static int prof_data_; 668096a8c8SDmitry Vyukov 678096a8c8SDmitry Vyukov void LockImpl(bool prof = true) { 688096a8c8SDmitry Vyukov while (!TryLockImpl()) 698096a8c8SDmitry Vyukov usleep(100); 708096a8c8SDmitry Vyukov if (prof && prof_) 718096a8c8SDmitry Vyukov Prof(); 728096a8c8SDmitry Vyukov } 738096a8c8SDmitry Vyukov TryLockImpl()748096a8c8SDmitry Vyukov bool TryLockImpl() { 758096a8c8SDmitry Vyukov return !locked_.exchange(true); 768096a8c8SDmitry Vyukov } 778096a8c8SDmitry Vyukov UnlockImpl()788096a8c8SDmitry Vyukov void UnlockImpl() { 798096a8c8SDmitry Vyukov locked_.store(false); 808096a8c8SDmitry Vyukov } 818096a8c8SDmitry Vyukov Prof()828096a8c8SDmitry Vyukov void Prof() { 838096a8c8SDmitry Vyukov // This happens inside of mutex lock annotations. 848096a8c8SDmitry Vyukov __tsan_mutex_pre_divert(this, 0); 858096a8c8SDmitry Vyukov prof_mu_.Lock(); 868096a8c8SDmitry Vyukov prof_data_++; 878096a8c8SDmitry Vyukov prof_mu_.Unlock(); 888096a8c8SDmitry Vyukov __tsan_mutex_post_divert(this, 0); 898096a8c8SDmitry Vyukov } 908096a8c8SDmitry Vyukov }; 918096a8c8SDmitry Vyukov 92dc2a38cdSDmitry Vyukov Mutex Mutex::prof_mu_(false, __tsan_mutex_linker_init); 938096a8c8SDmitry Vyukov int Mutex::prof_data_; 94