xref: /llvm-project/compiler-rt/test/tsan/custom_mutex.h (revision 9e2cd1c1256c05537f6a464154c45905ce5be078)
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