xref: /aosp_15_r20/external/compiler-rt/lib/sanitizer_common/sanitizer_mutex.h (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
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