2013-02-04 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libsanitizer / tsan / tsan_rtl_mutex.cc
blobdb97e1d9853f42cd4f5f542306f28129d6585e09
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 //===----------------------------------------------------------------------===//
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"
19 namespace __tsan {
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();
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 Lock l(&ctx->thread_mtx);
57 ScopedReport rep(ReportTypeMutexDestroyLocked);
58 rep.AddMutex(s);
59 StackTrace trace;
60 trace.ObtainCurrent(thr, pc);
61 rep.AddStack(&trace);
62 FastState last(s->last_lock);
63 RestoreStack(last.tid(), last.epoch(), &trace, 0);
64 rep.AddStack(&trace);
65 rep.AddLocation(s->addr, 1);
66 OutputReport(ctx, rep);
68 thr->mset.Remove(s->GetId());
69 DestroyAndFree(s);
72 void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
73 CHECK_GT(thr->in_rtl, 0);
74 DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
75 if (IsAppMem(addr))
76 MemoryRead1Byte(thr, pc, addr);
77 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
78 thr->fast_state.IncrementEpoch();
79 TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
80 if (s->owner_tid == SyncVar::kInvalidTid) {
81 CHECK_EQ(s->recursion, 0);
82 s->owner_tid = thr->tid;
83 s->last_lock = thr->fast_state.raw();
84 } else if (s->owner_tid == thr->tid) {
85 CHECK_GT(s->recursion, 0);
86 } else {
87 Printf("ThreadSanitizer WARNING: double lock\n");
88 PrintCurrentStack(thr, pc);
90 if (s->recursion == 0) {
91 StatInc(thr, StatMutexLock);
92 thr->clock.set(thr->tid, thr->fast_state.epoch());
93 thr->clock.acquire(&s->clock);
94 StatInc(thr, StatSyncAcquire);
95 thr->clock.acquire(&s->read_clock);
96 StatInc(thr, StatSyncAcquire);
97 } else if (!s->is_recursive) {
98 StatInc(thr, StatMutexRecLock);
100 s->recursion++;
101 thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
102 s->mtx.Unlock();
105 void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
106 CHECK_GT(thr->in_rtl, 0);
107 DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
108 if (IsAppMem(addr))
109 MemoryRead1Byte(thr, pc, addr);
110 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
111 thr->fast_state.IncrementEpoch();
112 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
113 if (s->recursion == 0) {
114 if (!s->is_broken) {
115 s->is_broken = true;
116 Printf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
117 PrintCurrentStack(thr, pc);
119 } else if (s->owner_tid != thr->tid) {
120 if (!s->is_broken) {
121 s->is_broken = true;
122 Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
123 PrintCurrentStack(thr, pc);
125 } else {
126 s->recursion--;
127 if (s->recursion == 0) {
128 StatInc(thr, StatMutexUnlock);
129 s->owner_tid = SyncVar::kInvalidTid;
130 thr->clock.set(thr->tid, thr->fast_state.epoch());
131 thr->fast_synch_epoch = thr->fast_state.epoch();
132 thr->clock.ReleaseStore(&s->clock);
133 StatInc(thr, StatSyncRelease);
134 } else {
135 StatInc(thr, StatMutexRecUnlock);
138 thr->mset.Del(s->GetId(), true);
139 s->mtx.Unlock();
142 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
143 CHECK_GT(thr->in_rtl, 0);
144 DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
145 StatInc(thr, StatMutexReadLock);
146 if (IsAppMem(addr))
147 MemoryRead1Byte(thr, pc, addr);
148 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
149 thr->fast_state.IncrementEpoch();
150 TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
151 if (s->owner_tid != SyncVar::kInvalidTid) {
152 Printf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
153 PrintCurrentStack(thr, pc);
155 thr->clock.set(thr->tid, thr->fast_state.epoch());
156 thr->clock.acquire(&s->clock);
157 s->last_lock = thr->fast_state.raw();
158 StatInc(thr, StatSyncAcquire);
159 thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
160 s->mtx.ReadUnlock();
163 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
164 CHECK_GT(thr->in_rtl, 0);
165 DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
166 StatInc(thr, StatMutexReadUnlock);
167 if (IsAppMem(addr))
168 MemoryRead1Byte(thr, pc, addr);
169 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
170 thr->fast_state.IncrementEpoch();
171 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
172 if (s->owner_tid != SyncVar::kInvalidTid) {
173 Printf("ThreadSanitizer WARNING: read unlock of a write "
174 "locked mutex\n");
175 PrintCurrentStack(thr, pc);
177 thr->clock.set(thr->tid, thr->fast_state.epoch());
178 thr->fast_synch_epoch = thr->fast_state.epoch();
179 thr->clock.release(&s->read_clock);
180 StatInc(thr, StatSyncRelease);
181 s->mtx.Unlock();
182 thr->mset.Del(s->GetId(), false);
185 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
186 CHECK_GT(thr->in_rtl, 0);
187 DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
188 if (IsAppMem(addr))
189 MemoryRead1Byte(thr, pc, addr);
190 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
191 bool write = true;
192 if (s->owner_tid == SyncVar::kInvalidTid) {
193 // Seems to be read unlock.
194 write = false;
195 StatInc(thr, StatMutexReadUnlock);
196 thr->fast_state.IncrementEpoch();
197 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
198 thr->clock.set(thr->tid, thr->fast_state.epoch());
199 thr->fast_synch_epoch = thr->fast_state.epoch();
200 thr->clock.release(&s->read_clock);
201 StatInc(thr, StatSyncRelease);
202 } else if (s->owner_tid == thr->tid) {
203 // Seems to be write unlock.
204 thr->fast_state.IncrementEpoch();
205 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
206 CHECK_GT(s->recursion, 0);
207 s->recursion--;
208 if (s->recursion == 0) {
209 StatInc(thr, StatMutexUnlock);
210 s->owner_tid = SyncVar::kInvalidTid;
211 // FIXME: Refactor me, plz.
212 // The sequence of events is quite tricky and doubled in several places.
213 // First, it's a bug to increment the epoch w/o writing to the trace.
214 // Then, the acquire/release logic can be factored out as well.
215 thr->clock.set(thr->tid, thr->fast_state.epoch());
216 thr->fast_synch_epoch = thr->fast_state.epoch();
217 thr->clock.ReleaseStore(&s->clock);
218 StatInc(thr, StatSyncRelease);
219 } else {
220 StatInc(thr, StatMutexRecUnlock);
222 } else if (!s->is_broken) {
223 s->is_broken = true;
224 Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
225 PrintCurrentStack(thr, pc);
227 thr->mset.Del(s->GetId(), write);
228 s->mtx.Unlock();
231 void Acquire(ThreadState *thr, uptr pc, uptr addr) {
232 CHECK_GT(thr->in_rtl, 0);
233 DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
234 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
235 thr->clock.set(thr->tid, thr->fast_state.epoch());
236 thr->clock.acquire(&s->clock);
237 StatInc(thr, StatSyncAcquire);
238 s->mtx.ReadUnlock();
241 void AcquireGlobal(ThreadState *thr, uptr pc) {
242 Context *ctx = CTX();
243 Lock l(&ctx->thread_mtx);
244 for (unsigned i = 0; i < kMaxTid; i++) {
245 ThreadContext *tctx = ctx->threads[i];
246 if (tctx == 0)
247 continue;
248 if (tctx->status == ThreadStatusRunning)
249 thr->clock.set(i, tctx->thr->fast_state.epoch());
250 else
251 thr->clock.set(i, tctx->epoch1);
255 void Release(ThreadState *thr, uptr pc, uptr addr) {
256 CHECK_GT(thr->in_rtl, 0);
257 DPrintf("#%d: Release %zx\n", thr->tid, addr);
258 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
259 thr->clock.set(thr->tid, thr->fast_state.epoch());
260 thr->clock.release(&s->clock);
261 StatInc(thr, StatSyncRelease);
262 s->mtx.Unlock();
265 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
266 CHECK_GT(thr->in_rtl, 0);
267 DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
268 SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
269 thr->clock.set(thr->tid, thr->fast_state.epoch());
270 thr->clock.ReleaseStore(&s->clock);
271 StatInc(thr, StatSyncRelease);
272 s->mtx.Unlock();
275 #ifndef TSAN_GO
276 void AfterSleep(ThreadState *thr, uptr pc) {
277 Context *ctx = CTX();
278 thr->last_sleep_stack_id = CurrentStackId(thr, pc);
279 Lock l(&ctx->thread_mtx);
280 for (unsigned i = 0; i < kMaxTid; i++) {
281 ThreadContext *tctx = ctx->threads[i];
282 if (tctx == 0)
283 continue;
284 if (tctx->status == ThreadStatusRunning)
285 thr->last_sleep_clock.set(i, tctx->thr->fast_state.epoch());
286 else
287 thr->last_sleep_clock.set(i, tctx->epoch1);
290 #endif
292 } // namespace __tsan