1*7c3d14c8STreehugger Robot //===-- tsan_mutex.cc -----------------------------------------------------===//
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 (TSan), a race detector.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
13*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_libc.h"
14*7c3d14c8STreehugger Robot #include "tsan_mutex.h"
15*7c3d14c8STreehugger Robot #include "tsan_platform.h"
16*7c3d14c8STreehugger Robot #include "tsan_rtl.h"
17*7c3d14c8STreehugger Robot
18*7c3d14c8STreehugger Robot namespace __tsan {
19*7c3d14c8STreehugger Robot
20*7c3d14c8STreehugger Robot // Simple reader-writer spin-mutex. Optimized for not-so-contended case.
21*7c3d14c8STreehugger Robot // Readers have preference, can possibly starvate writers.
22*7c3d14c8STreehugger Robot
23*7c3d14c8STreehugger Robot // The table fixes what mutexes can be locked under what mutexes.
24*7c3d14c8STreehugger Robot // E.g. if the row for MutexTypeThreads contains MutexTypeReport,
25*7c3d14c8STreehugger Robot // then Report mutex can be locked while under Threads mutex.
26*7c3d14c8STreehugger Robot // The leaf mutexes can be locked under any other mutexes.
27*7c3d14c8STreehugger Robot // Recursive locking is not supported.
28*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
29*7c3d14c8STreehugger Robot const MutexType MutexTypeLeaf = (MutexType)-1;
30*7c3d14c8STreehugger Robot static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
31*7c3d14c8STreehugger Robot /*0 MutexTypeInvalid*/ {},
32*7c3d14c8STreehugger Robot /*1 MutexTypeTrace*/ {MutexTypeLeaf},
33*7c3d14c8STreehugger Robot /*2 MutexTypeThreads*/ {MutexTypeReport},
34*7c3d14c8STreehugger Robot /*3 MutexTypeReport*/ {MutexTypeSyncVar,
35*7c3d14c8STreehugger Robot MutexTypeMBlock, MutexTypeJavaMBlock},
36*7c3d14c8STreehugger Robot /*4 MutexTypeSyncVar*/ {MutexTypeDDetector},
37*7c3d14c8STreehugger Robot /*5 MutexTypeSyncTab*/ {}, // unused
38*7c3d14c8STreehugger Robot /*6 MutexTypeSlab*/ {MutexTypeLeaf},
39*7c3d14c8STreehugger Robot /*7 MutexTypeAnnotations*/ {},
40*7c3d14c8STreehugger Robot /*8 MutexTypeAtExit*/ {MutexTypeSyncVar},
41*7c3d14c8STreehugger Robot /*9 MutexTypeMBlock*/ {MutexTypeSyncVar},
42*7c3d14c8STreehugger Robot /*10 MutexTypeJavaMBlock*/ {MutexTypeSyncVar},
43*7c3d14c8STreehugger Robot /*11 MutexTypeDDetector*/ {},
44*7c3d14c8STreehugger Robot /*12 MutexTypeFired*/ {MutexTypeLeaf},
45*7c3d14c8STreehugger Robot /*13 MutexTypeRacy*/ {MutexTypeLeaf},
46*7c3d14c8STreehugger Robot /*14 MutexTypeGlobalProc*/ {},
47*7c3d14c8STreehugger Robot };
48*7c3d14c8STreehugger Robot
49*7c3d14c8STreehugger Robot static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
50*7c3d14c8STreehugger Robot #endif
51*7c3d14c8STreehugger Robot
InitializeMutex()52*7c3d14c8STreehugger Robot void InitializeMutex() {
53*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
54*7c3d14c8STreehugger Robot // Build the "can lock" adjacency matrix.
55*7c3d14c8STreehugger Robot // If [i][j]==true, then one can lock mutex j while under mutex i.
56*7c3d14c8STreehugger Robot const int N = MutexTypeCount;
57*7c3d14c8STreehugger Robot int cnt[N] = {};
58*7c3d14c8STreehugger Robot bool leaf[N] = {};
59*7c3d14c8STreehugger Robot for (int i = 1; i < N; i++) {
60*7c3d14c8STreehugger Robot for (int j = 0; j < N; j++) {
61*7c3d14c8STreehugger Robot MutexType z = CanLockTab[i][j];
62*7c3d14c8STreehugger Robot if (z == MutexTypeInvalid)
63*7c3d14c8STreehugger Robot continue;
64*7c3d14c8STreehugger Robot if (z == MutexTypeLeaf) {
65*7c3d14c8STreehugger Robot CHECK(!leaf[i]);
66*7c3d14c8STreehugger Robot leaf[i] = true;
67*7c3d14c8STreehugger Robot continue;
68*7c3d14c8STreehugger Robot }
69*7c3d14c8STreehugger Robot CHECK(!CanLockAdj[i][(int)z]);
70*7c3d14c8STreehugger Robot CanLockAdj[i][(int)z] = true;
71*7c3d14c8STreehugger Robot cnt[i]++;
72*7c3d14c8STreehugger Robot }
73*7c3d14c8STreehugger Robot }
74*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
75*7c3d14c8STreehugger Robot CHECK(!leaf[i] || cnt[i] == 0);
76*7c3d14c8STreehugger Robot }
77*7c3d14c8STreehugger Robot // Add leaf mutexes.
78*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
79*7c3d14c8STreehugger Robot if (!leaf[i])
80*7c3d14c8STreehugger Robot continue;
81*7c3d14c8STreehugger Robot for (int j = 0; j < N; j++) {
82*7c3d14c8STreehugger Robot if (i == j || leaf[j] || j == MutexTypeInvalid)
83*7c3d14c8STreehugger Robot continue;
84*7c3d14c8STreehugger Robot CHECK(!CanLockAdj[j][i]);
85*7c3d14c8STreehugger Robot CanLockAdj[j][i] = true;
86*7c3d14c8STreehugger Robot }
87*7c3d14c8STreehugger Robot }
88*7c3d14c8STreehugger Robot // Build the transitive closure.
89*7c3d14c8STreehugger Robot bool CanLockAdj2[MutexTypeCount][MutexTypeCount];
90*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
91*7c3d14c8STreehugger Robot for (int j = 0; j < N; j++) {
92*7c3d14c8STreehugger Robot CanLockAdj2[i][j] = CanLockAdj[i][j];
93*7c3d14c8STreehugger Robot }
94*7c3d14c8STreehugger Robot }
95*7c3d14c8STreehugger Robot for (int k = 0; k < N; k++) {
96*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
97*7c3d14c8STreehugger Robot for (int j = 0; j < N; j++) {
98*7c3d14c8STreehugger Robot if (CanLockAdj2[i][k] && CanLockAdj2[k][j]) {
99*7c3d14c8STreehugger Robot CanLockAdj2[i][j] = true;
100*7c3d14c8STreehugger Robot }
101*7c3d14c8STreehugger Robot }
102*7c3d14c8STreehugger Robot }
103*7c3d14c8STreehugger Robot }
104*7c3d14c8STreehugger Robot #if 0
105*7c3d14c8STreehugger Robot Printf("Can lock graph:\n");
106*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
107*7c3d14c8STreehugger Robot for (int j = 0; j < N; j++) {
108*7c3d14c8STreehugger Robot Printf("%d ", CanLockAdj[i][j]);
109*7c3d14c8STreehugger Robot }
110*7c3d14c8STreehugger Robot Printf("\n");
111*7c3d14c8STreehugger Robot }
112*7c3d14c8STreehugger Robot Printf("Can lock graph closure:\n");
113*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
114*7c3d14c8STreehugger Robot for (int j = 0; j < N; j++) {
115*7c3d14c8STreehugger Robot Printf("%d ", CanLockAdj2[i][j]);
116*7c3d14c8STreehugger Robot }
117*7c3d14c8STreehugger Robot Printf("\n");
118*7c3d14c8STreehugger Robot }
119*7c3d14c8STreehugger Robot #endif
120*7c3d14c8STreehugger Robot // Verify that the graph is acyclic.
121*7c3d14c8STreehugger Robot for (int i = 0; i < N; i++) {
122*7c3d14c8STreehugger Robot if (CanLockAdj2[i][i]) {
123*7c3d14c8STreehugger Robot Printf("Mutex %d participates in a cycle\n", i);
124*7c3d14c8STreehugger Robot Die();
125*7c3d14c8STreehugger Robot }
126*7c3d14c8STreehugger Robot }
127*7c3d14c8STreehugger Robot #endif
128*7c3d14c8STreehugger Robot }
129*7c3d14c8STreehugger Robot
InternalDeadlockDetector()130*7c3d14c8STreehugger Robot InternalDeadlockDetector::InternalDeadlockDetector() {
131*7c3d14c8STreehugger Robot // Rely on zero initialization because some mutexes can be locked before ctor.
132*7c3d14c8STreehugger Robot }
133*7c3d14c8STreehugger Robot
134*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
Lock(MutexType t)135*7c3d14c8STreehugger Robot void InternalDeadlockDetector::Lock(MutexType t) {
136*7c3d14c8STreehugger Robot // Printf("LOCK %d @%zu\n", t, seq_ + 1);
137*7c3d14c8STreehugger Robot CHECK_GT(t, MutexTypeInvalid);
138*7c3d14c8STreehugger Robot CHECK_LT(t, MutexTypeCount);
139*7c3d14c8STreehugger Robot u64 max_seq = 0;
140*7c3d14c8STreehugger Robot u64 max_idx = MutexTypeInvalid;
141*7c3d14c8STreehugger Robot for (int i = 0; i != MutexTypeCount; i++) {
142*7c3d14c8STreehugger Robot if (locked_[i] == 0)
143*7c3d14c8STreehugger Robot continue;
144*7c3d14c8STreehugger Robot CHECK_NE(locked_[i], max_seq);
145*7c3d14c8STreehugger Robot if (max_seq < locked_[i]) {
146*7c3d14c8STreehugger Robot max_seq = locked_[i];
147*7c3d14c8STreehugger Robot max_idx = i;
148*7c3d14c8STreehugger Robot }
149*7c3d14c8STreehugger Robot }
150*7c3d14c8STreehugger Robot locked_[t] = ++seq_;
151*7c3d14c8STreehugger Robot if (max_idx == MutexTypeInvalid)
152*7c3d14c8STreehugger Robot return;
153*7c3d14c8STreehugger Robot // Printf(" last %d @%zu\n", max_idx, max_seq);
154*7c3d14c8STreehugger Robot if (!CanLockAdj[max_idx][t]) {
155*7c3d14c8STreehugger Robot Printf("ThreadSanitizer: internal deadlock detected\n");
156*7c3d14c8STreehugger Robot Printf("ThreadSanitizer: can't lock %d while under %zu\n",
157*7c3d14c8STreehugger Robot t, (uptr)max_idx);
158*7c3d14c8STreehugger Robot CHECK(0);
159*7c3d14c8STreehugger Robot }
160*7c3d14c8STreehugger Robot }
161*7c3d14c8STreehugger Robot
Unlock(MutexType t)162*7c3d14c8STreehugger Robot void InternalDeadlockDetector::Unlock(MutexType t) {
163*7c3d14c8STreehugger Robot // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
164*7c3d14c8STreehugger Robot CHECK(locked_[t]);
165*7c3d14c8STreehugger Robot locked_[t] = 0;
166*7c3d14c8STreehugger Robot }
167*7c3d14c8STreehugger Robot
CheckNoLocks()168*7c3d14c8STreehugger Robot void InternalDeadlockDetector::CheckNoLocks() {
169*7c3d14c8STreehugger Robot for (int i = 0; i != MutexTypeCount; i++) {
170*7c3d14c8STreehugger Robot CHECK_EQ(locked_[i], 0);
171*7c3d14c8STreehugger Robot }
172*7c3d14c8STreehugger Robot }
173*7c3d14c8STreehugger Robot #endif
174*7c3d14c8STreehugger Robot
CheckNoLocks(ThreadState * thr)175*7c3d14c8STreehugger Robot void CheckNoLocks(ThreadState *thr) {
176*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
177*7c3d14c8STreehugger Robot thr->internal_deadlock_detector.CheckNoLocks();
178*7c3d14c8STreehugger Robot #endif
179*7c3d14c8STreehugger Robot }
180*7c3d14c8STreehugger Robot
181*7c3d14c8STreehugger Robot const uptr kUnlocked = 0;
182*7c3d14c8STreehugger Robot const uptr kWriteLock = 1;
183*7c3d14c8STreehugger Robot const uptr kReadLock = 2;
184*7c3d14c8STreehugger Robot
185*7c3d14c8STreehugger Robot class Backoff {
186*7c3d14c8STreehugger Robot public:
Backoff()187*7c3d14c8STreehugger Robot Backoff()
188*7c3d14c8STreehugger Robot : iter_() {
189*7c3d14c8STreehugger Robot }
190*7c3d14c8STreehugger Robot
Do()191*7c3d14c8STreehugger Robot bool Do() {
192*7c3d14c8STreehugger Robot if (iter_++ < kActiveSpinIters)
193*7c3d14c8STreehugger Robot proc_yield(kActiveSpinCnt);
194*7c3d14c8STreehugger Robot else
195*7c3d14c8STreehugger Robot internal_sched_yield();
196*7c3d14c8STreehugger Robot return true;
197*7c3d14c8STreehugger Robot }
198*7c3d14c8STreehugger Robot
Contention() const199*7c3d14c8STreehugger Robot u64 Contention() const {
200*7c3d14c8STreehugger Robot u64 active = iter_ % kActiveSpinIters;
201*7c3d14c8STreehugger Robot u64 passive = iter_ - active;
202*7c3d14c8STreehugger Robot return active + 10 * passive;
203*7c3d14c8STreehugger Robot }
204*7c3d14c8STreehugger Robot
205*7c3d14c8STreehugger Robot private:
206*7c3d14c8STreehugger Robot int iter_;
207*7c3d14c8STreehugger Robot static const int kActiveSpinIters = 10;
208*7c3d14c8STreehugger Robot static const int kActiveSpinCnt = 20;
209*7c3d14c8STreehugger Robot };
210*7c3d14c8STreehugger Robot
Mutex(MutexType type,StatType stat_type)211*7c3d14c8STreehugger Robot Mutex::Mutex(MutexType type, StatType stat_type) {
212*7c3d14c8STreehugger Robot CHECK_GT(type, MutexTypeInvalid);
213*7c3d14c8STreehugger Robot CHECK_LT(type, MutexTypeCount);
214*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG
215*7c3d14c8STreehugger Robot type_ = type;
216*7c3d14c8STreehugger Robot #endif
217*7c3d14c8STreehugger Robot #if TSAN_COLLECT_STATS
218*7c3d14c8STreehugger Robot stat_type_ = stat_type;
219*7c3d14c8STreehugger Robot #endif
220*7c3d14c8STreehugger Robot atomic_store(&state_, kUnlocked, memory_order_relaxed);
221*7c3d14c8STreehugger Robot }
222*7c3d14c8STreehugger Robot
~Mutex()223*7c3d14c8STreehugger Robot Mutex::~Mutex() {
224*7c3d14c8STreehugger Robot CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
225*7c3d14c8STreehugger Robot }
226*7c3d14c8STreehugger Robot
Lock()227*7c3d14c8STreehugger Robot void Mutex::Lock() {
228*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
229*7c3d14c8STreehugger Robot cur_thread()->internal_deadlock_detector.Lock(type_);
230*7c3d14c8STreehugger Robot #endif
231*7c3d14c8STreehugger Robot uptr cmp = kUnlocked;
232*7c3d14c8STreehugger Robot if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
233*7c3d14c8STreehugger Robot memory_order_acquire))
234*7c3d14c8STreehugger Robot return;
235*7c3d14c8STreehugger Robot for (Backoff backoff; backoff.Do();) {
236*7c3d14c8STreehugger Robot if (atomic_load(&state_, memory_order_relaxed) == kUnlocked) {
237*7c3d14c8STreehugger Robot cmp = kUnlocked;
238*7c3d14c8STreehugger Robot if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
239*7c3d14c8STreehugger Robot memory_order_acquire)) {
240*7c3d14c8STreehugger Robot #if TSAN_COLLECT_STATS && !SANITIZER_GO
241*7c3d14c8STreehugger Robot StatInc(cur_thread(), stat_type_, backoff.Contention());
242*7c3d14c8STreehugger Robot #endif
243*7c3d14c8STreehugger Robot return;
244*7c3d14c8STreehugger Robot }
245*7c3d14c8STreehugger Robot }
246*7c3d14c8STreehugger Robot }
247*7c3d14c8STreehugger Robot }
248*7c3d14c8STreehugger Robot
Unlock()249*7c3d14c8STreehugger Robot void Mutex::Unlock() {
250*7c3d14c8STreehugger Robot uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
251*7c3d14c8STreehugger Robot (void)prev;
252*7c3d14c8STreehugger Robot DCHECK_NE(prev & kWriteLock, 0);
253*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
254*7c3d14c8STreehugger Robot cur_thread()->internal_deadlock_detector.Unlock(type_);
255*7c3d14c8STreehugger Robot #endif
256*7c3d14c8STreehugger Robot }
257*7c3d14c8STreehugger Robot
ReadLock()258*7c3d14c8STreehugger Robot void Mutex::ReadLock() {
259*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
260*7c3d14c8STreehugger Robot cur_thread()->internal_deadlock_detector.Lock(type_);
261*7c3d14c8STreehugger Robot #endif
262*7c3d14c8STreehugger Robot uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
263*7c3d14c8STreehugger Robot if ((prev & kWriteLock) == 0)
264*7c3d14c8STreehugger Robot return;
265*7c3d14c8STreehugger Robot for (Backoff backoff; backoff.Do();) {
266*7c3d14c8STreehugger Robot prev = atomic_load(&state_, memory_order_acquire);
267*7c3d14c8STreehugger Robot if ((prev & kWriteLock) == 0) {
268*7c3d14c8STreehugger Robot #if TSAN_COLLECT_STATS && !SANITIZER_GO
269*7c3d14c8STreehugger Robot StatInc(cur_thread(), stat_type_, backoff.Contention());
270*7c3d14c8STreehugger Robot #endif
271*7c3d14c8STreehugger Robot return;
272*7c3d14c8STreehugger Robot }
273*7c3d14c8STreehugger Robot }
274*7c3d14c8STreehugger Robot }
275*7c3d14c8STreehugger Robot
ReadUnlock()276*7c3d14c8STreehugger Robot void Mutex::ReadUnlock() {
277*7c3d14c8STreehugger Robot uptr prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
278*7c3d14c8STreehugger Robot (void)prev;
279*7c3d14c8STreehugger Robot DCHECK_EQ(prev & kWriteLock, 0);
280*7c3d14c8STreehugger Robot DCHECK_GT(prev & ~kWriteLock, 0);
281*7c3d14c8STreehugger Robot #if SANITIZER_DEBUG && !SANITIZER_GO
282*7c3d14c8STreehugger Robot cur_thread()->internal_deadlock_detector.Unlock(type_);
283*7c3d14c8STreehugger Robot #endif
284*7c3d14c8STreehugger Robot }
285*7c3d14c8STreehugger Robot
CheckLocked()286*7c3d14c8STreehugger Robot void Mutex::CheckLocked() {
287*7c3d14c8STreehugger Robot CHECK_NE(atomic_load(&state_, memory_order_relaxed), 0);
288*7c3d14c8STreehugger Robot }
289*7c3d14c8STreehugger Robot
290*7c3d14c8STreehugger Robot } // namespace __tsan
291