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