1 #include "test.h" 2 #include <atomic> 3 #include <vector> 4 #include <sanitizer/tsan_interface.h> 5 6 // A very primitive mutex annotated with tsan annotations. 7 class Mutex { 8 public: 9 Mutex(bool prof, unsigned create_flags, unsigned destroy_flags=0) prof_(prof)10 : prof_(prof) 11 , locked_(false) 12 , seq_(0) 13 , destroy_flags_(destroy_flags) { 14 __tsan_mutex_create(this, create_flags); 15 } 16 ~Mutex()17 ~Mutex() { 18 __tsan_mutex_destroy(this, destroy_flags_); 19 } 20 Lock()21 void Lock() { 22 __tsan_mutex_pre_lock(this, 0); 23 LockImpl(); 24 __tsan_mutex_post_lock(this, 0, 0); 25 } 26 TryLock()27 bool TryLock() { 28 __tsan_mutex_pre_lock(this, __tsan_mutex_try_lock); 29 bool ok = TryLockImpl(); 30 __tsan_mutex_post_lock(this, __tsan_mutex_try_lock | 31 (ok ? 0 : __tsan_mutex_try_lock_failed), 0); 32 return ok; 33 } 34 Unlock()35 void Unlock() { 36 __tsan_mutex_pre_unlock(this, 0); 37 UnlockImpl(); 38 __tsan_mutex_post_unlock(this, 0); 39 } 40 Wait()41 void Wait() { 42 for (int seq = seq_; seq == seq_;) { 43 Unlock(); 44 usleep(100); 45 Lock(); 46 } 47 } 48 Broadcast()49 void Broadcast() { 50 __tsan_mutex_pre_signal(this, 0); 51 LockImpl(false); 52 seq_++; 53 UnlockImpl(); 54 __tsan_mutex_post_signal(this, 0); 55 } 56 57 private: 58 const bool prof_; 59 std::atomic<bool> locked_; 60 int seq_; 61 unsigned destroy_flags_; 62 63 // This models mutex profiling subsystem. 64 static Mutex prof_mu_; 65 static int prof_data_; 66 67 void LockImpl(bool prof = true) { 68 while (!TryLockImpl()) 69 usleep(100); 70 if (prof && prof_) 71 Prof(); 72 } 73 TryLockImpl()74 bool TryLockImpl() { 75 return !locked_.exchange(true); 76 } 77 UnlockImpl()78 void UnlockImpl() { 79 locked_.store(false); 80 } 81 Prof()82 void Prof() { 83 // This happens inside of mutex lock annotations. 84 __tsan_mutex_pre_divert(this, 0); 85 prof_mu_.Lock(); 86 prof_data_++; 87 prof_mu_.Unlock(); 88 __tsan_mutex_post_divert(this, 0); 89 } 90 }; 91 92 Mutex Mutex::prof_mu_(false, __tsan_mutex_linker_init); 93 int Mutex::prof_data_; 94