1*7c3d14c8STreehugger Robot //===-- sanitizer_mutex.h ---------------------------------------*- C++ -*-===// 2*7c3d14c8STreehugger Robot // 3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure 4*7c3d14c8STreehugger Robot // 5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source 6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details. 7*7c3d14c8STreehugger Robot // 8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===// 9*7c3d14c8STreehugger Robot // 10*7c3d14c8STreehugger Robot // This file is a part of ThreadSanitizer/AddressSanitizer runtime. 11*7c3d14c8STreehugger Robot // 12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===// 13*7c3d14c8STreehugger Robot 14*7c3d14c8STreehugger Robot #ifndef SANITIZER_MUTEX_H 15*7c3d14c8STreehugger Robot #define SANITIZER_MUTEX_H 16*7c3d14c8STreehugger Robot 17*7c3d14c8STreehugger Robot #include "sanitizer_atomic.h" 18*7c3d14c8STreehugger Robot #include "sanitizer_internal_defs.h" 19*7c3d14c8STreehugger Robot #include "sanitizer_libc.h" 20*7c3d14c8STreehugger Robot 21*7c3d14c8STreehugger Robot namespace __sanitizer { 22*7c3d14c8STreehugger Robot 23*7c3d14c8STreehugger Robot class StaticSpinMutex { 24*7c3d14c8STreehugger Robot public: Init()25*7c3d14c8STreehugger Robot void Init() { 26*7c3d14c8STreehugger Robot atomic_store(&state_, 0, memory_order_relaxed); 27*7c3d14c8STreehugger Robot } 28*7c3d14c8STreehugger Robot Lock()29*7c3d14c8STreehugger Robot void Lock() { 30*7c3d14c8STreehugger Robot if (TryLock()) 31*7c3d14c8STreehugger Robot return; 32*7c3d14c8STreehugger Robot LockSlow(); 33*7c3d14c8STreehugger Robot } 34*7c3d14c8STreehugger Robot TryLock()35*7c3d14c8STreehugger Robot bool TryLock() { 36*7c3d14c8STreehugger Robot return atomic_exchange(&state_, 1, memory_order_acquire) == 0; 37*7c3d14c8STreehugger Robot } 38*7c3d14c8STreehugger Robot Unlock()39*7c3d14c8STreehugger Robot void Unlock() { 40*7c3d14c8STreehugger Robot atomic_store(&state_, 0, memory_order_release); 41*7c3d14c8STreehugger Robot } 42*7c3d14c8STreehugger Robot CheckLocked()43*7c3d14c8STreehugger Robot void CheckLocked() { 44*7c3d14c8STreehugger Robot CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1); 45*7c3d14c8STreehugger Robot } 46*7c3d14c8STreehugger Robot 47*7c3d14c8STreehugger Robot private: 48*7c3d14c8STreehugger Robot atomic_uint8_t state_; 49*7c3d14c8STreehugger Robot LockSlow()50*7c3d14c8STreehugger Robot void NOINLINE LockSlow() { 51*7c3d14c8STreehugger Robot for (int i = 0;; i++) { 52*7c3d14c8STreehugger Robot if (i < 10) 53*7c3d14c8STreehugger Robot proc_yield(10); 54*7c3d14c8STreehugger Robot else 55*7c3d14c8STreehugger Robot internal_sched_yield(); 56*7c3d14c8STreehugger Robot if (atomic_load(&state_, memory_order_relaxed) == 0 57*7c3d14c8STreehugger Robot && atomic_exchange(&state_, 1, memory_order_acquire) == 0) 58*7c3d14c8STreehugger Robot return; 59*7c3d14c8STreehugger Robot } 60*7c3d14c8STreehugger Robot } 61*7c3d14c8STreehugger Robot }; 62*7c3d14c8STreehugger Robot 63*7c3d14c8STreehugger Robot class SpinMutex : public StaticSpinMutex { 64*7c3d14c8STreehugger Robot public: SpinMutex()65*7c3d14c8STreehugger Robot SpinMutex() { 66*7c3d14c8STreehugger Robot Init(); 67*7c3d14c8STreehugger Robot } 68*7c3d14c8STreehugger Robot 69*7c3d14c8STreehugger Robot private: 70*7c3d14c8STreehugger Robot SpinMutex(const SpinMutex&); 71*7c3d14c8STreehugger Robot void operator=(const SpinMutex&); 72*7c3d14c8STreehugger Robot }; 73*7c3d14c8STreehugger Robot 74*7c3d14c8STreehugger Robot class BlockingMutex { 75*7c3d14c8STreehugger Robot public: 76*7c3d14c8STreehugger Robot #if SANITIZER_WINDOWS 77*7c3d14c8STreehugger Robot // Windows does not currently support LinkerInitialized 78*7c3d14c8STreehugger Robot explicit BlockingMutex(LinkerInitialized); 79*7c3d14c8STreehugger Robot #else 80*7c3d14c8STreehugger Robot explicit constexpr BlockingMutex(LinkerInitialized) 81*7c3d14c8STreehugger Robot : opaque_storage_ {0, }, owner_(0) {} 82*7c3d14c8STreehugger Robot #endif 83*7c3d14c8STreehugger Robot BlockingMutex(); 84*7c3d14c8STreehugger Robot void Lock(); 85*7c3d14c8STreehugger Robot void Unlock(); 86*7c3d14c8STreehugger Robot void CheckLocked(); 87*7c3d14c8STreehugger Robot private: 88*7c3d14c8STreehugger Robot uptr opaque_storage_[10]; 89*7c3d14c8STreehugger Robot uptr owner_; // for debugging 90*7c3d14c8STreehugger Robot }; 91*7c3d14c8STreehugger Robot 92*7c3d14c8STreehugger Robot // Reader-writer spin mutex. 93*7c3d14c8STreehugger Robot class RWMutex { 94*7c3d14c8STreehugger Robot public: RWMutex()95*7c3d14c8STreehugger Robot RWMutex() { 96*7c3d14c8STreehugger Robot atomic_store(&state_, kUnlocked, memory_order_relaxed); 97*7c3d14c8STreehugger Robot } 98*7c3d14c8STreehugger Robot ~RWMutex()99*7c3d14c8STreehugger Robot ~RWMutex() { 100*7c3d14c8STreehugger Robot CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked); 101*7c3d14c8STreehugger Robot } 102*7c3d14c8STreehugger Robot Lock()103*7c3d14c8STreehugger Robot void Lock() { 104*7c3d14c8STreehugger Robot u32 cmp = kUnlocked; 105*7c3d14c8STreehugger Robot if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock, 106*7c3d14c8STreehugger Robot memory_order_acquire)) 107*7c3d14c8STreehugger Robot return; 108*7c3d14c8STreehugger Robot LockSlow(); 109*7c3d14c8STreehugger Robot } 110*7c3d14c8STreehugger Robot Unlock()111*7c3d14c8STreehugger Robot void Unlock() { 112*7c3d14c8STreehugger Robot u32 prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release); 113*7c3d14c8STreehugger Robot DCHECK_NE(prev & kWriteLock, 0); 114*7c3d14c8STreehugger Robot (void)prev; 115*7c3d14c8STreehugger Robot } 116*7c3d14c8STreehugger Robot ReadLock()117*7c3d14c8STreehugger Robot void ReadLock() { 118*7c3d14c8STreehugger Robot u32 prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire); 119*7c3d14c8STreehugger Robot if ((prev & kWriteLock) == 0) 120*7c3d14c8STreehugger Robot return; 121*7c3d14c8STreehugger Robot ReadLockSlow(); 122*7c3d14c8STreehugger Robot } 123*7c3d14c8STreehugger Robot ReadUnlock()124*7c3d14c8STreehugger Robot void ReadUnlock() { 125*7c3d14c8STreehugger Robot u32 prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release); 126*7c3d14c8STreehugger Robot DCHECK_EQ(prev & kWriteLock, 0); 127*7c3d14c8STreehugger Robot DCHECK_GT(prev & ~kWriteLock, 0); 128*7c3d14c8STreehugger Robot (void)prev; 129*7c3d14c8STreehugger Robot } 130*7c3d14c8STreehugger Robot CheckLocked()131*7c3d14c8STreehugger Robot void CheckLocked() { 132*7c3d14c8STreehugger Robot CHECK_NE(atomic_load(&state_, memory_order_relaxed), kUnlocked); 133*7c3d14c8STreehugger Robot } 134*7c3d14c8STreehugger Robot 135*7c3d14c8STreehugger Robot private: 136*7c3d14c8STreehugger Robot atomic_uint32_t state_; 137*7c3d14c8STreehugger Robot 138*7c3d14c8STreehugger Robot enum { 139*7c3d14c8STreehugger Robot kUnlocked = 0, 140*7c3d14c8STreehugger Robot kWriteLock = 1, 141*7c3d14c8STreehugger Robot kReadLock = 2 142*7c3d14c8STreehugger Robot }; 143*7c3d14c8STreehugger Robot LockSlow()144*7c3d14c8STreehugger Robot void NOINLINE LockSlow() { 145*7c3d14c8STreehugger Robot for (int i = 0;; i++) { 146*7c3d14c8STreehugger Robot if (i < 10) 147*7c3d14c8STreehugger Robot proc_yield(10); 148*7c3d14c8STreehugger Robot else 149*7c3d14c8STreehugger Robot internal_sched_yield(); 150*7c3d14c8STreehugger Robot u32 cmp = atomic_load(&state_, memory_order_relaxed); 151*7c3d14c8STreehugger Robot if (cmp == kUnlocked && 152*7c3d14c8STreehugger Robot atomic_compare_exchange_weak(&state_, &cmp, kWriteLock, 153*7c3d14c8STreehugger Robot memory_order_acquire)) 154*7c3d14c8STreehugger Robot return; 155*7c3d14c8STreehugger Robot } 156*7c3d14c8STreehugger Robot } 157*7c3d14c8STreehugger Robot ReadLockSlow()158*7c3d14c8STreehugger Robot void NOINLINE ReadLockSlow() { 159*7c3d14c8STreehugger Robot for (int i = 0;; i++) { 160*7c3d14c8STreehugger Robot if (i < 10) 161*7c3d14c8STreehugger Robot proc_yield(10); 162*7c3d14c8STreehugger Robot else 163*7c3d14c8STreehugger Robot internal_sched_yield(); 164*7c3d14c8STreehugger Robot u32 prev = atomic_load(&state_, memory_order_acquire); 165*7c3d14c8STreehugger Robot if ((prev & kWriteLock) == 0) 166*7c3d14c8STreehugger Robot return; 167*7c3d14c8STreehugger Robot } 168*7c3d14c8STreehugger Robot } 169*7c3d14c8STreehugger Robot 170*7c3d14c8STreehugger Robot RWMutex(const RWMutex&); 171*7c3d14c8STreehugger Robot void operator = (const RWMutex&); 172*7c3d14c8STreehugger Robot }; 173*7c3d14c8STreehugger Robot 174*7c3d14c8STreehugger Robot template<typename MutexType> 175*7c3d14c8STreehugger Robot class GenericScopedLock { 176*7c3d14c8STreehugger Robot public: GenericScopedLock(MutexType * mu)177*7c3d14c8STreehugger Robot explicit GenericScopedLock(MutexType *mu) 178*7c3d14c8STreehugger Robot : mu_(mu) { 179*7c3d14c8STreehugger Robot mu_->Lock(); 180*7c3d14c8STreehugger Robot } 181*7c3d14c8STreehugger Robot ~GenericScopedLock()182*7c3d14c8STreehugger Robot ~GenericScopedLock() { 183*7c3d14c8STreehugger Robot mu_->Unlock(); 184*7c3d14c8STreehugger Robot } 185*7c3d14c8STreehugger Robot 186*7c3d14c8STreehugger Robot private: 187*7c3d14c8STreehugger Robot MutexType *mu_; 188*7c3d14c8STreehugger Robot 189*7c3d14c8STreehugger Robot GenericScopedLock(const GenericScopedLock&); 190*7c3d14c8STreehugger Robot void operator=(const GenericScopedLock&); 191*7c3d14c8STreehugger Robot }; 192*7c3d14c8STreehugger Robot 193*7c3d14c8STreehugger Robot template<typename MutexType> 194*7c3d14c8STreehugger Robot class GenericScopedReadLock { 195*7c3d14c8STreehugger Robot public: GenericScopedReadLock(MutexType * mu)196*7c3d14c8STreehugger Robot explicit GenericScopedReadLock(MutexType *mu) 197*7c3d14c8STreehugger Robot : mu_(mu) { 198*7c3d14c8STreehugger Robot mu_->ReadLock(); 199*7c3d14c8STreehugger Robot } 200*7c3d14c8STreehugger Robot ~GenericScopedReadLock()201*7c3d14c8STreehugger Robot ~GenericScopedReadLock() { 202*7c3d14c8STreehugger Robot mu_->ReadUnlock(); 203*7c3d14c8STreehugger Robot } 204*7c3d14c8STreehugger Robot 205*7c3d14c8STreehugger Robot private: 206*7c3d14c8STreehugger Robot MutexType *mu_; 207*7c3d14c8STreehugger Robot 208*7c3d14c8STreehugger Robot GenericScopedReadLock(const GenericScopedReadLock&); 209*7c3d14c8STreehugger Robot void operator=(const GenericScopedReadLock&); 210*7c3d14c8STreehugger Robot }; 211*7c3d14c8STreehugger Robot 212*7c3d14c8STreehugger Robot typedef GenericScopedLock<StaticSpinMutex> SpinMutexLock; 213*7c3d14c8STreehugger Robot typedef GenericScopedLock<BlockingMutex> BlockingMutexLock; 214*7c3d14c8STreehugger Robot typedef GenericScopedLock<RWMutex> RWMutexLock; 215*7c3d14c8STreehugger Robot typedef GenericScopedReadLock<RWMutex> RWMutexReadLock; 216*7c3d14c8STreehugger Robot 217*7c3d14c8STreehugger Robot } // namespace __sanitizer 218*7c3d14c8STreehugger Robot 219*7c3d14c8STreehugger Robot #endif // SANITIZER_MUTEX_H 220