blob: 012b06fb9761c4965688a031981b8f78d68db43d [file] [log] [blame]
Alexey Samsonov3b2f9f42012-06-04 13:55:19 +00001//===-- tsan_mutex.cc -----------------------------------------------------===//
Kostya Serebryany4ad375f2012-05-10 13:48:04 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer (TSan), a race detector.
11//
12//===----------------------------------------------------------------------===//
13#include "tsan_mutex.h"
14#include "tsan_platform.h"
15#include "tsan_rtl.h"
16
17namespace __tsan {
18
19// Simple reader-writer spin-mutex. Optimized for not-so-contended case.
20// Readers have preference, can possibly starvate writers.
21
22// The table fixes what mutexes can be locked under what mutexes.
23// E.g. if the row for MutexTypeThreads contains MutexTypeReport,
24// then Report mutex can be locked while under Threads mutex.
25// The leaf mutexes can be locked under any other mutexes.
26// Recursive locking is not supported.
27const MutexType MutexTypeLeaf = (MutexType)-1;
28static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
29 /*0 MutexTypeInvalid*/ {},
30 /*1 MutexTypeTrace*/ {MutexTypeLeaf},
31 /*2 MutexTypeThreads*/ {MutexTypeReport},
32 /*3 MutexTypeReport*/ {},
33 /*4 MutexTypeSyncVar*/ {},
34 /*5 MutexTypeSyncTab*/ {MutexTypeSyncVar},
35 /*6 MutexTypeSlab*/ {MutexTypeLeaf},
36 /*7 MutexTypeAnnotations*/ {},
37 /*8 MutexTypeAtExit*/ {MutexTypeSyncTab},
38};
39
40static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
41
42void InitializeMutex() {
43 // Build the "can lock" adjacency matrix.
44 // If [i][j]==true, then one can lock mutex j while under mutex i.
45 const int N = MutexTypeCount;
46 int cnt[N] = {};
47 bool leaf[N] = {};
48 for (int i = 1; i < N; i++) {
49 for (int j = 0; j < N; j++) {
50 int z = CanLockTab[i][j];
51 if (z == MutexTypeInvalid)
52 continue;
53 if (z == MutexTypeLeaf) {
54 CHECK(!leaf[i]);
55 leaf[i] = true;
56 continue;
57 }
58 CHECK(!CanLockAdj[i][z]);
59 CanLockAdj[i][z] = true;
60 cnt[i]++;
61 }
62 }
63 for (int i = 0; i < N; i++) {
64 CHECK(!leaf[i] || cnt[i] == 0);
65 }
66 // Add leaf mutexes.
67 for (int i = 0; i < N; i++) {
68 if (!leaf[i])
69 continue;
70 for (int j = 0; j < N; j++) {
71 if (i == j || leaf[j] || j == MutexTypeInvalid)
72 continue;
73 CHECK(!CanLockAdj[j][i]);
74 CanLockAdj[j][i] = true;
75 }
76 }
77 // Build the transitive closure.
78 bool CanLockAdj2[MutexTypeCount][MutexTypeCount];
79 for (int i = 0; i < N; i++) {
80 for (int j = 0; j < N; j++) {
81 CanLockAdj2[i][j] = CanLockAdj[i][j];
82 }
83 }
84 for (int k = 0; k < N; k++) {
85 for (int i = 0; i < N; i++) {
86 for (int j = 0; j < N; j++) {
87 if (CanLockAdj2[i][k] && CanLockAdj2[k][j]) {
88 CanLockAdj2[i][j] = true;
89 }
90 }
91 }
92 }
93#if 0
Alexey Samsonovac4c2902012-06-06 10:13:27 +000094 TsanPrintf("Can lock graph:\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000095 for (int i = 0; i < N; i++) {
96 for (int j = 0; j < N; j++) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +000097 TsanPrintf("%d ", CanLockAdj[i][j]);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000098 }
Alexey Samsonovac4c2902012-06-06 10:13:27 +000099 TsanPrintf("\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000100 }
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000101 TsanPrintf("Can lock graph closure:\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000102 for (int i = 0; i < N; i++) {
103 for (int j = 0; j < N; j++) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000104 TsanPrintf("%d ", CanLockAdj2[i][j]);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000105 }
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000106 TsanPrintf("\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000107 }
108#endif
109 // Verify that the graph is acyclic.
110 for (int i = 0; i < N; i++) {
111 if (CanLockAdj2[i][i]) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000112 TsanPrintf("Mutex %d participates in a cycle\n", i);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000113 Die();
114 }
115 }
116}
117
118DeadlockDetector::DeadlockDetector() {
119 // Rely on zero initialization because some mutexes can be locked before ctor.
120}
121
122void DeadlockDetector::Lock(MutexType t) {
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000123 // TsanPrintf("LOCK %d @%zu\n", t, seq_ + 1);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000124 u64 max_seq = 0;
125 u64 max_idx = MutexTypeInvalid;
126 for (int i = 0; i != MutexTypeCount; i++) {
127 if (locked_[i] == 0)
128 continue;
129 CHECK_NE(locked_[i], max_seq);
130 if (max_seq < locked_[i]) {
131 max_seq = locked_[i];
132 max_idx = i;
133 }
134 }
135 locked_[t] = ++seq_;
136 if (max_idx == MutexTypeInvalid)
137 return;
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000138 // TsanPrintf(" last %d @%zu\n", max_idx, max_seq);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000139 if (!CanLockAdj[max_idx][t]) {
Alexey Samsonovac4c2902012-06-06 10:13:27 +0000140 TsanPrintf("ThreadSanitizer: internal deadlock detected\n");
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000141 TsanPrintf("ThreadSanitizer: can't lock %d while under %zu\n",
142 t, (uptr)max_idx);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000143 Die();
144 }
145}
146
147void DeadlockDetector::Unlock(MutexType t) {
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000148 // TsanPrintf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000149 CHECK(locked_[t]);
150 locked_[t] = 0;
151}
152
153const uptr kUnlocked = 0;
154const uptr kWriteLock = 1;
155const uptr kReadLock = 2;
156
157class Backoff {
158 public:
159 Backoff()
160 : iter_() {
161 }
162
163 bool Do() {
164 if (iter_++ < kActiveSpinIters)
165 proc_yield(kActiveSpinCnt);
166 else
Dmitry Vyukov15710c92012-05-22 11:33:03 +0000167 internal_yield();
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000168 return true;
169 }
170
171 u64 Contention() const {
172 u64 active = iter_ % kActiveSpinIters;
173 u64 passive = iter_ - active;
174 return active + 10 * passive;
175 }
176
177 private:
178 int iter_;
179 static const int kActiveSpinIters = 10;
180 static const int kActiveSpinCnt = 20;
181};
182
183Mutex::Mutex(MutexType type, StatType stat_type) {
184 CHECK_GT(type, MutexTypeInvalid);
185 CHECK_LT(type, MutexTypeCount);
186#if TSAN_DEBUG
187 type_ = type;
188#endif
189#if TSAN_COLLECT_STATS
190 stat_type_ = stat_type;
191#endif
192 atomic_store(&state_, kUnlocked, memory_order_relaxed);
193}
194
195Mutex::~Mutex() {
196 CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
197}
198
199void Mutex::Lock() {
200#if TSAN_DEBUG
201 cur_thread()->deadlock_detector.Lock(type_);
202#endif
203 uptr cmp = kUnlocked;
204 if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
205 memory_order_acquire))
206 return;
207 for (Backoff backoff; backoff.Do();) {
208 if (atomic_load(&state_, memory_order_relaxed) == kUnlocked) {
209 cmp = kUnlocked;
210 if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
211 memory_order_acquire)) {
212#if TSAN_COLLECT_STATS
213 StatInc(cur_thread(), stat_type_, backoff.Contention());
214#endif
215 return;
216 }
217 }
218 }
219}
220
221void Mutex::Unlock() {
222 uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
223 (void)prev;
224 DCHECK_NE(prev & kWriteLock, 0);
225#if TSAN_DEBUG
226 cur_thread()->deadlock_detector.Unlock(type_);
227#endif
228}
229
230void Mutex::ReadLock() {
231#if TSAN_DEBUG
232 cur_thread()->deadlock_detector.Lock(type_);
233#endif
234 uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
235 if ((prev & kWriteLock) == 0)
236 return;
237 for (Backoff backoff; backoff.Do();) {
238 prev = atomic_load(&state_, memory_order_acquire);
239 if ((prev & kWriteLock) == 0) {
240#if TSAN_COLLECT_STATS
241 StatInc(cur_thread(), stat_type_, backoff.Contention());
242#endif
243 return;
244 }
245 }
246}
247
248void Mutex::ReadUnlock() {
249 uptr prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
250 (void)prev;
251 DCHECK_EQ(prev & kWriteLock, 0);
252 DCHECK_GT(prev & ~kWriteLock, 0);
253#if TSAN_DEBUG
254 cur_thread()->deadlock_detector.Unlock(type_);
255#endif
256}
257
258Lock::Lock(Mutex *m)
259 : m_(m) {
260 m_->Lock();
261}
262
263Lock::~Lock() {
264 m_->Unlock();
265}
266
267ReadLock::ReadLock(Mutex *m)
268 : m_(m) {
269 m_->ReadLock();
270}
271
272ReadLock::~ReadLock() {
273 m_->ReadUnlock();
274}
275
276} // namespace __tsan