blob: 335ca2211d13264f4a2012c2ce0471d07b3af9c2 [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//===----------------------------------------------------------------------===//
Alexey Samsonov58a3c582012-06-18 08:44:30 +000013#include "sanitizer_common/sanitizer_libc.h"
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000014#include "tsan_mutex.h"
15#include "tsan_platform.h"
16#include "tsan_rtl.h"
17
18namespace __tsan {
19
20// Simple reader-writer spin-mutex. Optimized for not-so-contended case.
21// Readers have preference, can possibly starvate writers.
22
23// The table fixes what mutexes can be locked under what mutexes.
24// E.g. if the row for MutexTypeThreads contains MutexTypeReport,
25// then Report mutex can be locked while under Threads mutex.
26// The leaf mutexes can be locked under any other mutexes.
27// Recursive locking is not supported.
Dmitry Vyukov3533f762012-12-13 09:22:11 +000028#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000029const MutexType MutexTypeLeaf = (MutexType)-1;
30static MutexType CanLockTab[MutexTypeCount][MutexTypeCount] = {
Dmitry Vyukov22be55e2012-12-21 11:30:14 +000031 /*0 MutexTypeInvalid*/ {},
32 /*1 MutexTypeTrace*/ {MutexTypeLeaf},
33 /*2 MutexTypeThreads*/ {MutexTypeReport},
34 /*3 MutexTypeReport*/ {MutexTypeSyncTab, MutexTypeMBlock,
35 MutexTypeJavaMBlock},
36 /*4 MutexTypeSyncVar*/ {},
37 /*5 MutexTypeSyncTab*/ {MutexTypeSyncVar},
38 /*6 MutexTypeSlab*/ {MutexTypeLeaf},
39 /*7 MutexTypeAnnotations*/ {},
40 /*8 MutexTypeAtExit*/ {MutexTypeSyncTab},
41 /*9 MutexTypeMBlock*/ {MutexTypeSyncVar},
42 /*10 MutexTypeJavaMBlock*/ {MutexTypeSyncVar},
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000043};
44
45static bool CanLockAdj[MutexTypeCount][MutexTypeCount];
Dmitry Vyukov3533f762012-12-13 09:22:11 +000046#endif
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000047
48void InitializeMutex() {
Dmitry Vyukov3533f762012-12-13 09:22:11 +000049#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000050 // Build the "can lock" adjacency matrix.
51 // If [i][j]==true, then one can lock mutex j while under mutex i.
52 const int N = MutexTypeCount;
53 int cnt[N] = {};
54 bool leaf[N] = {};
55 for (int i = 1; i < N; i++) {
56 for (int j = 0; j < N; j++) {
Alexey Samsonov046248c2012-09-13 11:54:41 +000057 MutexType z = CanLockTab[i][j];
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000058 if (z == MutexTypeInvalid)
59 continue;
60 if (z == MutexTypeLeaf) {
61 CHECK(!leaf[i]);
62 leaf[i] = true;
63 continue;
64 }
Alexey Samsonov046248c2012-09-13 11:54:41 +000065 CHECK(!CanLockAdj[i][(int)z]);
66 CanLockAdj[i][(int)z] = true;
Kostya Serebryany4ad375f2012-05-10 13:48:04 +000067 cnt[i]++;
68 }
69 }
70 for (int i = 0; i < N; i++) {
71 CHECK(!leaf[i] || cnt[i] == 0);
72 }
73 // Add leaf mutexes.
74 for (int i = 0; i < N; i++) {
75 if (!leaf[i])
76 continue;
77 for (int j = 0; j < N; j++) {
78 if (i == j || leaf[j] || j == MutexTypeInvalid)
79 continue;
80 CHECK(!CanLockAdj[j][i]);
81 CanLockAdj[j][i] = true;
82 }
83 }
84 // Build the transitive closure.
85 bool CanLockAdj2[MutexTypeCount][MutexTypeCount];
86 for (int i = 0; i < N; i++) {
87 for (int j = 0; j < N; j++) {
88 CanLockAdj2[i][j] = CanLockAdj[i][j];
89 }
90 }
91 for (int k = 0; k < N; k++) {
92 for (int i = 0; i < N; i++) {
93 for (int j = 0; j < N; j++) {
94 if (CanLockAdj2[i][k] && CanLockAdj2[k][j]) {
95 CanLockAdj2[i][j] = true;
96 }
97 }
98 }
99 }
100#if 0
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000101 Printf("Can lock graph:\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 Samsonovad9d65f2012-11-02 12:17:51 +0000104 Printf("%d ", CanLockAdj[i][j]);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000105 }
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000106 Printf("\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000107 }
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000108 Printf("Can lock graph closure:\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000109 for (int i = 0; i < N; i++) {
110 for (int j = 0; j < N; j++) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000111 Printf("%d ", CanLockAdj2[i][j]);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000112 }
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000113 Printf("\n");
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000114 }
115#endif
116 // Verify that the graph is acyclic.
117 for (int i = 0; i < N; i++) {
118 if (CanLockAdj2[i][i]) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000119 Printf("Mutex %d participates in a cycle\n", i);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000120 Die();
121 }
122 }
Dmitry Vyukov3533f762012-12-13 09:22:11 +0000123#endif
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000124}
125
126DeadlockDetector::DeadlockDetector() {
127 // Rely on zero initialization because some mutexes can be locked before ctor.
128}
129
Dmitry Vyukov3533f762012-12-13 09:22:11 +0000130#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000131void DeadlockDetector::Lock(MutexType t) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000132 // Printf("LOCK %d @%zu\n", t, seq_ + 1);
Dmitry Vyukovfd5ebcd2012-12-06 12:16:15 +0000133 CHECK_GT(t, MutexTypeInvalid);
134 CHECK_LT(t, MutexTypeCount);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000135 u64 max_seq = 0;
136 u64 max_idx = MutexTypeInvalid;
137 for (int i = 0; i != MutexTypeCount; i++) {
138 if (locked_[i] == 0)
139 continue;
140 CHECK_NE(locked_[i], max_seq);
141 if (max_seq < locked_[i]) {
142 max_seq = locked_[i];
143 max_idx = i;
144 }
145 }
146 locked_[t] = ++seq_;
147 if (max_idx == MutexTypeInvalid)
148 return;
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000149 // Printf(" last %d @%zu\n", max_idx, max_seq);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000150 if (!CanLockAdj[max_idx][t]) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000151 Printf("ThreadSanitizer: internal deadlock detected\n");
152 Printf("ThreadSanitizer: can't lock %d while under %zu\n",
Alexey Samsonov51ae9832012-06-06 13:11:29 +0000153 t, (uptr)max_idx);
Dmitry Vyukov191f2f72012-08-30 13:02:30 +0000154 CHECK(0);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000155 }
156}
157
158void DeadlockDetector::Unlock(MutexType t) {
Alexey Samsonovad9d65f2012-11-02 12:17:51 +0000159 // Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000160 CHECK(locked_[t]);
161 locked_[t] = 0;
162}
Dmitry Vyukov3533f762012-12-13 09:22:11 +0000163#endif
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000164
165const uptr kUnlocked = 0;
166const uptr kWriteLock = 1;
167const uptr kReadLock = 2;
168
169class Backoff {
170 public:
171 Backoff()
172 : iter_() {
173 }
174
175 bool Do() {
176 if (iter_++ < kActiveSpinIters)
177 proc_yield(kActiveSpinCnt);
178 else
Alexey Samsonov58a3c582012-06-18 08:44:30 +0000179 internal_sched_yield();
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000180 return true;
181 }
182
183 u64 Contention() const {
184 u64 active = iter_ % kActiveSpinIters;
185 u64 passive = iter_ - active;
186 return active + 10 * passive;
187 }
188
189 private:
190 int iter_;
191 static const int kActiveSpinIters = 10;
192 static const int kActiveSpinCnt = 20;
193};
194
195Mutex::Mutex(MutexType type, StatType stat_type) {
196 CHECK_GT(type, MutexTypeInvalid);
197 CHECK_LT(type, MutexTypeCount);
198#if TSAN_DEBUG
199 type_ = type;
200#endif
201#if TSAN_COLLECT_STATS
202 stat_type_ = stat_type;
203#endif
204 atomic_store(&state_, kUnlocked, memory_order_relaxed);
205}
206
207Mutex::~Mutex() {
208 CHECK_EQ(atomic_load(&state_, memory_order_relaxed), kUnlocked);
209}
210
211void Mutex::Lock() {
Dmitry Vyukov03d32ec2012-07-05 16:18:28 +0000212#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000213 cur_thread()->deadlock_detector.Lock(type_);
214#endif
215 uptr cmp = kUnlocked;
216 if (atomic_compare_exchange_strong(&state_, &cmp, kWriteLock,
217 memory_order_acquire))
218 return;
219 for (Backoff backoff; backoff.Do();) {
220 if (atomic_load(&state_, memory_order_relaxed) == kUnlocked) {
221 cmp = kUnlocked;
222 if (atomic_compare_exchange_weak(&state_, &cmp, kWriteLock,
223 memory_order_acquire)) {
224#if TSAN_COLLECT_STATS
225 StatInc(cur_thread(), stat_type_, backoff.Contention());
226#endif
227 return;
228 }
229 }
230 }
231}
232
233void Mutex::Unlock() {
234 uptr prev = atomic_fetch_sub(&state_, kWriteLock, memory_order_release);
235 (void)prev;
236 DCHECK_NE(prev & kWriteLock, 0);
Dmitry Vyukov03d32ec2012-07-05 16:18:28 +0000237#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000238 cur_thread()->deadlock_detector.Unlock(type_);
239#endif
240}
241
242void Mutex::ReadLock() {
Dmitry Vyukov03d32ec2012-07-05 16:18:28 +0000243#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000244 cur_thread()->deadlock_detector.Lock(type_);
245#endif
246 uptr prev = atomic_fetch_add(&state_, kReadLock, memory_order_acquire);
247 if ((prev & kWriteLock) == 0)
248 return;
249 for (Backoff backoff; backoff.Do();) {
250 prev = atomic_load(&state_, memory_order_acquire);
251 if ((prev & kWriteLock) == 0) {
252#if TSAN_COLLECT_STATS
253 StatInc(cur_thread(), stat_type_, backoff.Contention());
254#endif
255 return;
256 }
257 }
258}
259
260void Mutex::ReadUnlock() {
261 uptr prev = atomic_fetch_sub(&state_, kReadLock, memory_order_release);
262 (void)prev;
263 DCHECK_EQ(prev & kWriteLock, 0);
264 DCHECK_GT(prev & ~kWriteLock, 0);
Dmitry Vyukov03d32ec2012-07-05 16:18:28 +0000265#if TSAN_DEBUG && !TSAN_GO
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000266 cur_thread()->deadlock_detector.Unlock(type_);
267#endif
268}
269
Dmitry Vyukov191f2f72012-08-30 13:02:30 +0000270void Mutex::CheckLocked() {
271 CHECK_NE(atomic_load(&state_, memory_order_relaxed), 0);
272}
273
Kostya Serebryany4ad375f2012-05-10 13:48:04 +0000274} // namespace __tsan