]> git.ipfire.org Git - thirdparty/gcc.git/blob - libsanitizer/tsan/tsan_rtl_mutex.cc
libsanitizer mege from upstream r171973
[thirdparty/gcc.git] / libsanitizer / tsan / tsan_rtl_mutex.cc
1 //===-- tsan_rtl_mutex.cc -------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #include "tsan_rtl.h"
13 #include "tsan_flags.h"
14 #include "tsan_sync.h"
15 #include "tsan_report.h"
16 #include "tsan_symbolize.h"
17 #include "tsan_platform.h"
18
19 namespace __tsan {
20
21 void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
22 bool rw, bool recursive, bool linker_init) {
23 Context *ctx = CTX();
24 CHECK_GT(thr->in_rtl, 0);
25 DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
26 StatInc(thr, StatMutexCreate);
27 if (!linker_init && IsAppMem(addr))
28 MemoryWrite1Byte(thr, pc, addr);
29 SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
30 s->is_rw = rw;
31 s->is_recursive = recursive;
32 s->is_linker_init = linker_init;
33 s->mtx.Unlock();
34 }
35
36 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
37 Context *ctx = CTX();
38 CHECK_GT(thr->in_rtl, 0);
39 DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
40 StatInc(thr, StatMutexDestroy);
41 #ifndef TSAN_GO
42 // Global mutexes not marked as LINKER_INITIALIZED
43 // cause tons of not interesting reports, so just ignore it.
44 if (IsGlobalVar(addr))
45 return;
46 #endif
47 SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
48 if (s == 0)
49 return;
50 if (IsAppMem(addr))
51 MemoryWrite1Byte(thr, pc, addr);
52 if (flags()->report_destroy_locked
53 && s->owner_tid != SyncVar::kInvalidTid
54 && !s->is_broken) {
55 s->is_broken = true;
56 ScopedReport rep(ReportTypeMutexDestroyLocked);
57 rep.AddMutex(s);
58 StackTrace trace;
59 trace.ObtainCurrent(thr, pc);
60 rep.AddStack(&trace);
61 FastState last(s->last_lock);
62 RestoreStack(last.tid(), last.epoch(), &trace, 0);
63 rep.AddStack(&trace);
64 rep.AddLocation(s->addr, 1);
65 OutputReport(ctx, rep);
66 }
67 thr->mset.Remove(s->GetId());
68 DestroyAndFree(s);
69 }
70
71 void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
72 CHECK_GT(thr->in_rtl, 0);
73 DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
74 if (IsAppMem(addr))
75 MemoryRead1Byte(thr, pc, addr);
76 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
77 thr->fast_state.IncrementEpoch();
78 TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
79 if (s->owner_tid == SyncVar::kInvalidTid) {
80 CHECK_EQ(s->recursion, 0);
81 s->owner_tid = thr->tid;
82 s->last_lock = thr->fast_state.raw();
83 } else if (s->owner_tid == thr->tid) {
84 CHECK_GT(s->recursion, 0);
85 } else {
86 Printf("ThreadSanitizer WARNING: double lock\n");
87 PrintCurrentStack(thr, pc);
88 }
89 if (s->recursion == 0) {
90 StatInc(thr, StatMutexLock);
91 thr->clock.set(thr->tid, thr->fast_state.epoch());
92 thr->clock.acquire(&s->clock);
93 StatInc(thr, StatSyncAcquire);
94 thr->clock.acquire(&s->read_clock);
95 StatInc(thr, StatSyncAcquire);
96 } else if (!s->is_recursive) {
97 StatInc(thr, StatMutexRecLock);
98 }
99 s->recursion++;
100 thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
101 s->mtx.Unlock();
102 }
103
104 void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
105 CHECK_GT(thr->in_rtl, 0);
106 DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
107 if (IsAppMem(addr))
108 MemoryRead1Byte(thr, pc, addr);
109 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
110 thr->fast_state.IncrementEpoch();
111 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
112 if (s->recursion == 0) {
113 if (!s->is_broken) {
114 s->is_broken = true;
115 Printf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
116 PrintCurrentStack(thr, pc);
117 }
118 } else if (s->owner_tid != thr->tid) {
119 if (!s->is_broken) {
120 s->is_broken = true;
121 Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
122 PrintCurrentStack(thr, pc);
123 }
124 } else {
125 s->recursion--;
126 if (s->recursion == 0) {
127 StatInc(thr, StatMutexUnlock);
128 s->owner_tid = SyncVar::kInvalidTid;
129 thr->clock.set(thr->tid, thr->fast_state.epoch());
130 thr->fast_synch_epoch = thr->fast_state.epoch();
131 thr->clock.ReleaseStore(&s->clock);
132 StatInc(thr, StatSyncRelease);
133 } else {
134 StatInc(thr, StatMutexRecUnlock);
135 }
136 }
137 thr->mset.Del(s->GetId(), true);
138 s->mtx.Unlock();
139 }
140
141 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
142 CHECK_GT(thr->in_rtl, 0);
143 DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
144 StatInc(thr, StatMutexReadLock);
145 if (IsAppMem(addr))
146 MemoryRead1Byte(thr, pc, addr);
147 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
148 thr->fast_state.IncrementEpoch();
149 TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
150 if (s->owner_tid != SyncVar::kInvalidTid) {
151 Printf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
152 PrintCurrentStack(thr, pc);
153 }
154 thr->clock.set(thr->tid, thr->fast_state.epoch());
155 thr->clock.acquire(&s->clock);
156 s->last_lock = thr->fast_state.raw();
157 StatInc(thr, StatSyncAcquire);
158 thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
159 s->mtx.ReadUnlock();
160 }
161
162 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
163 CHECK_GT(thr->in_rtl, 0);
164 DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
165 StatInc(thr, StatMutexReadUnlock);
166 if (IsAppMem(addr))
167 MemoryRead1Byte(thr, pc, addr);
168 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
169 thr->fast_state.IncrementEpoch();
170 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
171 if (s->owner_tid != SyncVar::kInvalidTid) {
172 Printf("ThreadSanitizer WARNING: read unlock of a write "
173 "locked mutex\n");
174 PrintCurrentStack(thr, pc);
175 }
176 thr->clock.set(thr->tid, thr->fast_state.epoch());
177 thr->fast_synch_epoch = thr->fast_state.epoch();
178 thr->clock.release(&s->read_clock);
179 StatInc(thr, StatSyncRelease);
180 s->mtx.Unlock();
181 thr->mset.Del(s->GetId(), false);
182 }
183
184 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
185 CHECK_GT(thr->in_rtl, 0);
186 DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
187 if (IsAppMem(addr))
188 MemoryRead1Byte(thr, pc, addr);
189 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
190 bool write = true;
191 if (s->owner_tid == SyncVar::kInvalidTid) {
192 // Seems to be read unlock.
193 write = false;
194 StatInc(thr, StatMutexReadUnlock);
195 thr->fast_state.IncrementEpoch();
196 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
197 thr->clock.set(thr->tid, thr->fast_state.epoch());
198 thr->fast_synch_epoch = thr->fast_state.epoch();
199 thr->clock.release(&s->read_clock);
200 StatInc(thr, StatSyncRelease);
201 } else if (s->owner_tid == thr->tid) {
202 // Seems to be write unlock.
203 thr->fast_state.IncrementEpoch();
204 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
205 CHECK_GT(s->recursion, 0);
206 s->recursion--;
207 if (s->recursion == 0) {
208 StatInc(thr, StatMutexUnlock);
209 s->owner_tid = SyncVar::kInvalidTid;
210 // FIXME: Refactor me, plz.
211 // The sequence of events is quite tricky and doubled in several places.
212 // First, it's a bug to increment the epoch w/o writing to the trace.
213 // Then, the acquire/release logic can be factored out as well.
214 thr->clock.set(thr->tid, thr->fast_state.epoch());
215 thr->fast_synch_epoch = thr->fast_state.epoch();
216 thr->clock.ReleaseStore(&s->clock);
217 StatInc(thr, StatSyncRelease);
218 } else {
219 StatInc(thr, StatMutexRecUnlock);
220 }
221 } else if (!s->is_broken) {
222 s->is_broken = true;
223 Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
224 PrintCurrentStack(thr, pc);
225 }
226 thr->mset.Del(s->GetId(), write);
227 s->mtx.Unlock();
228 }
229
230 void Acquire(ThreadState *thr, uptr pc, uptr addr) {
231 CHECK_GT(thr->in_rtl, 0);
232 DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
233 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
234 thr->clock.set(thr->tid, thr->fast_state.epoch());
235 thr->clock.acquire(&s->clock);
236 StatInc(thr, StatSyncAcquire);
237 s->mtx.ReadUnlock();
238 }
239
240 void AcquireGlobal(ThreadState *thr, uptr pc) {
241 Context *ctx = CTX();
242 Lock l(&ctx->thread_mtx);
243 for (unsigned i = 0; i < kMaxTid; i++) {
244 ThreadContext *tctx = ctx->threads[i];
245 if (tctx == 0)
246 continue;
247 if (tctx->status == ThreadStatusRunning)
248 thr->clock.set(i, tctx->thr->fast_state.epoch());
249 else
250 thr->clock.set(i, tctx->epoch1);
251 }
252 }
253
254 void Release(ThreadState *thr, uptr pc, uptr addr) {
255 CHECK_GT(thr->in_rtl, 0);
256 DPrintf("#%d: Release %zx\n", thr->tid, addr);
257 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
258 thr->clock.set(thr->tid, thr->fast_state.epoch());
259 thr->clock.release(&s->clock);
260 StatInc(thr, StatSyncRelease);
261 s->mtx.Unlock();
262 }
263
264 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
265 CHECK_GT(thr->in_rtl, 0);
266 DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
267 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
268 thr->clock.set(thr->tid, thr->fast_state.epoch());
269 thr->clock.ReleaseStore(&s->clock);
270 StatInc(thr, StatSyncRelease);
271 s->mtx.Unlock();
272 }
273
274 #ifndef TSAN_GO
275 void AfterSleep(ThreadState *thr, uptr pc) {
276 Context *ctx = CTX();
277 thr->last_sleep_stack_id = CurrentStackId(thr, pc);
278 Lock l(&ctx->thread_mtx);
279 for (unsigned i = 0; i < kMaxTid; i++) {
280 ThreadContext *tctx = ctx->threads[i];
281 if (tctx == 0)
282 continue;
283 if (tctx->status == ThreadStatusRunning)
284 thr->last_sleep_clock.set(i, tctx->thr->fast_state.epoch());
285 else
286 thr->last_sleep_clock.set(i, tctx->epoch1);
287 }
288 }
289 #endif
290
291 } // namespace __tsan