blob: 62ab7aa6b2b497827b0cfc2077a595c775a72e33 [file] [log] [blame]
Alexey Samsonov603c4be2012-06-04 13:55:19 +00001//===-- tsan_rtl_mutex.cc -------------------------------------------------===//
Kostya Serebryany7ac41482012-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
Stephen Hines2d1fdb22014-05-28 23:58:16 -070014#include <sanitizer_common/sanitizer_deadlock_detector_interface.h>
15#include <sanitizer_common/sanitizer_stackdepot.h>
16
Kostya Serebryany7ac41482012-05-10 13:48:04 +000017#include "tsan_rtl.h"
Dmitry Vyukovfd513902012-08-16 15:12:35 +000018#include "tsan_flags.h"
Kostya Serebryany7ac41482012-05-10 13:48:04 +000019#include "tsan_sync.h"
20#include "tsan_report.h"
21#include "tsan_symbolize.h"
Dmitry Vyukov9adce672012-08-31 20:02:33 +000022#include "tsan_platform.h"
Kostya Serebryany7ac41482012-05-10 13:48:04 +000023
24namespace __tsan {
25
Stephen Hines2d1fdb22014-05-28 23:58:16 -070026void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r);
27
28struct Callback : DDCallback {
29 ThreadState *thr;
30 uptr pc;
31
32 Callback(ThreadState *thr, uptr pc)
33 : thr(thr)
34 , pc(pc) {
35 DDCallback::pt = thr->dd_pt;
36 DDCallback::lt = thr->dd_lt;
37 }
38
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070039 u32 Unwind() override { return CurrentStackId(thr, pc); }
40 int UniqueTid() override { return thr->unique_id; }
Stephen Hines2d1fdb22014-05-28 23:58:16 -070041};
42
43void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
44 Callback cb(thr, pc);
45 ctx->dd->MutexInit(&cb, &s->dd);
46 s->dd.ctx = s->GetId();
47}
48
49static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
50 uptr addr, u64 mid) {
Stephen Hines6a211c52014-07-21 00:49:56 -070051 // In Go, these misuses are either impossible, or detected by std lib,
52 // or false positives (e.g. unlock in a different thread).
53 if (kGoMode)
54 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -070055 ThreadRegistryLock l(ctx->thread_registry);
56 ScopedReport rep(typ);
57 rep.AddMutex(mid);
Stephen Hines6d186232014-11-26 17:56:19 -080058 VarSizeStackTrace trace;
59 ObtainCurrentStack(thr, pc, &trace);
60 rep.AddStack(trace, true);
Stephen Hines2d1fdb22014-05-28 23:58:16 -070061 rep.AddLocation(addr, 1);
Stephen Hines6a211c52014-07-21 00:49:56 -070062 OutputReport(thr, rep);
Stephen Hines2d1fdb22014-05-28 23:58:16 -070063}
64
Kostya Serebryany7ac41482012-05-10 13:48:04 +000065void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
Dmitry Vyukovc20e9ba2012-08-16 13:29:41 +000066 bool rw, bool recursive, bool linker_init) {
Alexey Samsonove9541012012-06-06 13:11:29 +000067 DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000068 StatInc(thr, StatMutexCreate);
Dmitry Vyukov32858662013-02-01 14:41:58 +000069 if (!linker_init && IsAppMem(addr)) {
70 CHECK(!thr->is_freeing);
71 thr->is_freeing = true;
Dmitry Vyukov334553e2013-02-01 09:42:06 +000072 MemoryWrite(thr, pc, addr, kSizeLog1);
Dmitry Vyukov32858662013-02-01 14:41:58 +000073 thr->is_freeing = false;
74 }
Stephen Hines6a211c52014-07-21 00:49:56 -070075 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000076 s->is_rw = rw;
77 s->is_recursive = recursive;
Dmitry Vyukov2e933fc2012-08-16 14:21:09 +000078 s->is_linker_init = linker_init;
Stephen Hines6a211c52014-07-21 00:49:56 -070079 if (kCppMode && s->creation_stack_id == 0)
80 s->creation_stack_id = CurrentStackId(thr, pc);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000081 s->mtx.Unlock();
82}
83
84void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
Alexey Samsonove9541012012-06-06 13:11:29 +000085 DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
Kostya Serebryany7ac41482012-05-10 13:48:04 +000086 StatInc(thr, StatMutexDestroy);
Stephen Hines86277eb2015-03-23 12:06:32 -070087#ifndef SANITIZER_GO
Dmitry Vyukov0c2feef2012-09-07 18:08:02 +000088 // Global mutexes not marked as LINKER_INITIALIZED
89 // cause tons of not interesting reports, so just ignore it.
90 if (IsGlobalVar(addr))
91 return;
92#endif
Dmitry Vyukov32858662013-02-01 14:41:58 +000093 if (IsAppMem(addr)) {
94 CHECK(!thr->is_freeing);
95 thr->is_freeing = true;
Dmitry Vyukov334553e2013-02-01 09:42:06 +000096 MemoryWrite(thr, pc, addr, kSizeLog1);
Dmitry Vyukov32858662013-02-01 14:41:58 +000097 thr->is_freeing = false;
98 }
Stephen Hines6a211c52014-07-21 00:49:56 -070099 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
100 if (s == 0)
101 return;
Stephen Hines6d186232014-11-26 17:56:19 -0800102 if (common_flags()->detect_deadlocks) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700103 Callback cb(thr, pc);
104 ctx->dd->MutexDestroy(&cb, &s->dd);
105 ctx->dd->MutexInit(&cb, &s->dd);
106 }
107 bool unlock_locked = false;
Dmitry Vyukov55e711e2012-08-18 11:49:00 +0000108 if (flags()->report_destroy_locked
109 && s->owner_tid != SyncVar::kInvalidTid
110 && !s->is_broken) {
111 s->is_broken = true;
Stephen Hines6a211c52014-07-21 00:49:56 -0700112 unlock_locked = true;
113 }
114 u64 mid = s->GetId();
115 u32 last_lock = s->last_lock;
116 if (!unlock_locked)
Stephen Hines6d186232014-11-26 17:56:19 -0800117 s->Reset(thr); // must not reset it before the report is printed
Stephen Hines6a211c52014-07-21 00:49:56 -0700118 s->mtx.Unlock();
119 if (unlock_locked) {
Alexey Samsonov2bbd8be2013-03-15 13:48:44 +0000120 ThreadRegistryLock l(ctx->thread_registry);
Dmitry Vyukov55e711e2012-08-18 11:49:00 +0000121 ScopedReport rep(ReportTypeMutexDestroyLocked);
Stephen Hines6a211c52014-07-21 00:49:56 -0700122 rep.AddMutex(mid);
Stephen Hines6d186232014-11-26 17:56:19 -0800123 VarSizeStackTrace trace;
124 ObtainCurrentStack(thr, pc, &trace);
125 rep.AddStack(trace);
Stephen Hines6a211c52014-07-21 00:49:56 -0700126 FastState last(last_lock);
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000127 RestoreStack(last.tid(), last.epoch(), &trace, 0);
Stephen Hines6d186232014-11-26 17:56:19 -0800128 rep.AddStack(trace, true);
Stephen Hines6a211c52014-07-21 00:49:56 -0700129 rep.AddLocation(addr, 1);
130 OutputReport(thr, rep);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000131 }
Stephen Hines6a211c52014-07-21 00:49:56 -0700132 if (unlock_locked) {
133 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
134 if (s != 0) {
Stephen Hines6d186232014-11-26 17:56:19 -0800135 s->Reset(thr);
Stephen Hines6a211c52014-07-21 00:49:56 -0700136 s->mtx.Unlock();
137 }
138 }
139 thr->mset.Remove(mid);
140 // s will be destroyed and freed in MetaMap::FreeBlock.
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000141}
142
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700143void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000144 DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
145 CHECK_GT(rec, 0);
Dmitry Vyukov9adce672012-08-31 20:02:33 +0000146 if (IsAppMem(addr))
Dmitry Vyukov334553e2013-02-01 09:42:06 +0000147 MemoryReadAtomic(thr, pc, addr, kSizeLog1);
Stephen Hines6a211c52014-07-21 00:49:56 -0700148 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000149 thr->fast_state.IncrementEpoch();
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000150 TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700151 bool report_double_lock = false;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000152 if (s->owner_tid == SyncVar::kInvalidTid) {
153 CHECK_EQ(s->recursion, 0);
154 s->owner_tid = thr->tid;
Dmitry Vyukov332c62b2012-08-16 15:08:49 +0000155 s->last_lock = thr->fast_state.raw();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000156 } else if (s->owner_tid == thr->tid) {
157 CHECK_GT(s->recursion, 0);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700158 } else if (flags()->report_mutex_bugs && !s->is_broken) {
159 s->is_broken = true;
160 report_double_lock = true;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000161 }
162 if (s->recursion == 0) {
163 StatInc(thr, StatMutexLock);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000164 AcquireImpl(thr, pc, &s->clock);
165 AcquireImpl(thr, pc, &s->read_clock);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000166 } else if (!s->is_recursive) {
167 StatInc(thr, StatMutexRecLock);
168 }
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000169 s->recursion += rec;
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000170 thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
Stephen Hines6d186232014-11-26 17:56:19 -0800171 if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700172 Callback cb(thr, pc);
173 if (!try_lock)
174 ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
175 ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
176 }
177 u64 mid = s->GetId();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000178 s->mtx.Unlock();
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700179 // Can't touch s after this point.
180 if (report_double_lock)
181 ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
Stephen Hines6d186232014-11-26 17:56:19 -0800182 if (common_flags()->detect_deadlocks) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700183 Callback cb(thr, pc);
184 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
185 }
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000186}
187
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000188int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000189 DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
Dmitry Vyukov9adce672012-08-31 20:02:33 +0000190 if (IsAppMem(addr))
Dmitry Vyukov334553e2013-02-01 09:42:06 +0000191 MemoryReadAtomic(thr, pc, addr, kSizeLog1);
Stephen Hines6a211c52014-07-21 00:49:56 -0700192 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000193 thr->fast_state.IncrementEpoch();
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000194 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000195 int rec = 0;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700196 bool report_bad_unlock = false;
Stephen Hines6a211c52014-07-21 00:49:56 -0700197 if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700198 if (flags()->report_mutex_bugs && !s->is_broken) {
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000199 s->is_broken = true;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700200 report_bad_unlock = true;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000201 }
202 } else {
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000203 rec = all ? s->recursion : 1;
204 s->recursion -= rec;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000205 if (s->recursion == 0) {
206 StatInc(thr, StatMutexUnlock);
207 s->owner_tid = SyncVar::kInvalidTid;
Dmitry Vyukov117699d2013-10-10 16:03:24 +0000208 ReleaseStoreImpl(thr, pc, &s->clock);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000209 } else {
210 StatInc(thr, StatMutexRecUnlock);
211 }
212 }
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000213 thr->mset.Del(s->GetId(), true);
Stephen Hines6d186232014-11-26 17:56:19 -0800214 if (common_flags()->detect_deadlocks && s->recursion == 0 &&
215 !report_bad_unlock) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700216 Callback cb(thr, pc);
217 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true);
218 }
219 u64 mid = s->GetId();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000220 s->mtx.Unlock();
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700221 // Can't touch s after this point.
222 if (report_bad_unlock)
223 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
Stephen Hines6d186232014-11-26 17:56:19 -0800224 if (common_flags()->detect_deadlocks && !report_bad_unlock) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700225 Callback cb(thr, pc);
226 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
227 }
Dmitry Vyukov8354fae2013-05-17 12:03:46 +0000228 return rec;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000229}
230
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700231void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
Alexey Samsonove9541012012-06-06 13:11:29 +0000232 DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000233 StatInc(thr, StatMutexReadLock);
Dmitry Vyukov9adce672012-08-31 20:02:33 +0000234 if (IsAppMem(addr))
Dmitry Vyukov334553e2013-02-01 09:42:06 +0000235 MemoryReadAtomic(thr, pc, addr, kSizeLog1);
Stephen Hines6a211c52014-07-21 00:49:56 -0700236 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000237 thr->fast_state.IncrementEpoch();
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000238 TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700239 bool report_bad_lock = false;
Dmitry Vyukov1da10562012-09-01 12:13:18 +0000240 if (s->owner_tid != SyncVar::kInvalidTid) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700241 if (flags()->report_mutex_bugs && !s->is_broken) {
242 s->is_broken = true;
243 report_bad_lock = true;
244 }
Dmitry Vyukov1da10562012-09-01 12:13:18 +0000245 }
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000246 AcquireImpl(thr, pc, &s->clock);
Dmitry Vyukov332c62b2012-08-16 15:08:49 +0000247 s->last_lock = thr->fast_state.raw();
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000248 thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
Stephen Hines6d186232014-11-26 17:56:19 -0800249 if (common_flags()->detect_deadlocks && s->recursion == 0) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700250 Callback cb(thr, pc);
251 if (!trylock)
252 ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
253 ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
254 }
255 u64 mid = s->GetId();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000256 s->mtx.ReadUnlock();
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700257 // Can't touch s after this point.
258 if (report_bad_lock)
259 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
Stephen Hines6d186232014-11-26 17:56:19 -0800260 if (common_flags()->detect_deadlocks) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700261 Callback cb(thr, pc);
262 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
263 }
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000264}
265
266void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
Alexey Samsonove9541012012-06-06 13:11:29 +0000267 DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000268 StatInc(thr, StatMutexReadUnlock);
Dmitry Vyukov9adce672012-08-31 20:02:33 +0000269 if (IsAppMem(addr))
Dmitry Vyukov334553e2013-02-01 09:42:06 +0000270 MemoryReadAtomic(thr, pc, addr, kSizeLog1);
Stephen Hines6a211c52014-07-21 00:49:56 -0700271 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000272 thr->fast_state.IncrementEpoch();
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000273 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700274 bool report_bad_unlock = false;
Dmitry Vyukov1da10562012-09-01 12:13:18 +0000275 if (s->owner_tid != SyncVar::kInvalidTid) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700276 if (flags()->report_mutex_bugs && !s->is_broken) {
277 s->is_broken = true;
278 report_bad_unlock = true;
279 }
Dmitry Vyukov1da10562012-09-01 12:13:18 +0000280 }
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000281 ReleaseImpl(thr, pc, &s->read_clock);
Stephen Hines6d186232014-11-26 17:56:19 -0800282 if (common_flags()->detect_deadlocks && s->recursion == 0) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700283 Callback cb(thr, pc);
284 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false);
285 }
286 u64 mid = s->GetId();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000287 s->mtx.Unlock();
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700288 // Can't touch s after this point.
289 thr->mset.Del(mid, false);
290 if (report_bad_unlock)
291 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
Stephen Hines6d186232014-11-26 17:56:19 -0800292 if (common_flags()->detect_deadlocks) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700293 Callback cb(thr, pc);
294 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
295 }
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000296}
297
298void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
Alexey Samsonove9541012012-06-06 13:11:29 +0000299 DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
Dmitry Vyukov9adce672012-08-31 20:02:33 +0000300 if (IsAppMem(addr))
Dmitry Vyukov334553e2013-02-01 09:42:06 +0000301 MemoryReadAtomic(thr, pc, addr, kSizeLog1);
Stephen Hines6a211c52014-07-21 00:49:56 -0700302 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000303 bool write = true;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700304 bool report_bad_unlock = false;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000305 if (s->owner_tid == SyncVar::kInvalidTid) {
306 // Seems to be read unlock.
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000307 write = false;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000308 StatInc(thr, StatMutexReadUnlock);
309 thr->fast_state.IncrementEpoch();
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000310 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000311 ReleaseImpl(thr, pc, &s->read_clock);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000312 } else if (s->owner_tid == thr->tid) {
313 // Seems to be write unlock.
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000314 thr->fast_state.IncrementEpoch();
315 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000316 CHECK_GT(s->recursion, 0);
317 s->recursion--;
318 if (s->recursion == 0) {
319 StatInc(thr, StatMutexUnlock);
320 s->owner_tid = SyncVar::kInvalidTid;
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000321 ReleaseImpl(thr, pc, &s->clock);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000322 } else {
323 StatInc(thr, StatMutexRecUnlock);
324 }
325 } else if (!s->is_broken) {
326 s->is_broken = true;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700327 report_bad_unlock = true;
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000328 }
Dmitry Vyukovad9da372012-12-06 12:16:15 +0000329 thr->mset.Del(s->GetId(), write);
Stephen Hines6d186232014-11-26 17:56:19 -0800330 if (common_flags()->detect_deadlocks && s->recursion == 0) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700331 Callback cb(thr, pc);
332 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write);
333 }
334 u64 mid = s->GetId();
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000335 s->mtx.Unlock();
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700336 // Can't touch s after this point.
337 if (report_bad_unlock)
338 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
Stephen Hines6d186232014-11-26 17:56:19 -0800339 if (common_flags()->detect_deadlocks) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700340 Callback cb(thr, pc);
341 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
342 }
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000343}
344
Dmitry Vyukov11f53092013-11-15 16:58:12 +0000345void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
Dmitry Vyukov11f53092013-11-15 16:58:12 +0000346 DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
Stephen Hines6a211c52014-07-21 00:49:56 -0700347 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Dmitry Vyukov11f53092013-11-15 16:58:12 +0000348 s->owner_tid = SyncVar::kInvalidTid;
349 s->recursion = 0;
350 s->mtx.Unlock();
351}
352
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000353void Acquire(ThreadState *thr, uptr pc, uptr addr) {
Alexey Samsonove9541012012-06-06 13:11:29 +0000354 DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000355 if (thr->ignore_sync)
356 return;
Stephen Hines6a211c52014-07-21 00:49:56 -0700357 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000358 AcquireImpl(thr, pc, &s->clock);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000359 s->mtx.ReadUnlock();
360}
361
Alexey Samsonov2bbd8be2013-03-15 13:48:44 +0000362static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
363 ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
364 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
365 if (tctx->status == ThreadStatusRunning)
366 thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch());
367 else
368 thr->clock.set(tctx->tid, tctx->epoch1);
369}
370
Dmitry Vyukov538f1ba2012-11-07 15:08:20 +0000371void AcquireGlobal(ThreadState *thr, uptr pc) {
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000372 DPrintf("#%d: AcquireGlobal\n", thr->tid);
373 if (thr->ignore_sync)
374 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700375 ThreadRegistryLock l(ctx->thread_registry);
376 ctx->thread_registry->RunCallbackForEachThreadLocked(
Alexey Samsonov2bbd8be2013-03-15 13:48:44 +0000377 UpdateClockCallback, thr);
Dmitry Vyukov538f1ba2012-11-07 15:08:20 +0000378}
379
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000380void Release(ThreadState *thr, uptr pc, uptr addr) {
Alexey Samsonove9541012012-06-06 13:11:29 +0000381 DPrintf("#%d: Release %zx\n", thr->tid, addr);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000382 if (thr->ignore_sync)
383 return;
Stephen Hines6a211c52014-07-21 00:49:56 -0700384 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000385 thr->fast_state.IncrementEpoch();
386 // Can't increment epoch w/o writing to the trace as well.
387 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
388 ReleaseImpl(thr, pc, &s->clock);
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000389 s->mtx.Unlock();
390}
391
Dmitry Vyukov9d150bd2012-07-28 15:27:41 +0000392void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
Dmitry Vyukov9d150bd2012-07-28 15:27:41 +0000393 DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000394 if (thr->ignore_sync)
395 return;
Stephen Hines6a211c52014-07-21 00:49:56 -0700396 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000397 thr->fast_state.IncrementEpoch();
398 // Can't increment epoch w/o writing to the trace as well.
399 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
400 ReleaseStoreImpl(thr, pc, &s->clock);
Dmitry Vyukov9d150bd2012-07-28 15:27:41 +0000401 s->mtx.Unlock();
402}
403
Stephen Hines86277eb2015-03-23 12:06:32 -0700404#ifndef SANITIZER_GO
Alexey Samsonov2bbd8be2013-03-15 13:48:44 +0000405static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
406 ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
407 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
408 if (tctx->status == ThreadStatusRunning)
409 thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch());
410 else
411 thr->last_sleep_clock.set(tctx->tid, tctx->epoch1);
412}
413
Dmitry Vyukov84853112012-08-31 17:27:49 +0000414void AfterSleep(ThreadState *thr, uptr pc) {
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000415 DPrintf("#%d: AfterSleep %zx\n", thr->tid);
416 if (thr->ignore_sync)
417 return;
Dmitry Vyukov84853112012-08-31 17:27:49 +0000418 thr->last_sleep_stack_id = CurrentStackId(thr, pc);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700419 ThreadRegistryLock l(ctx->thread_registry);
420 ctx->thread_registry->RunCallbackForEachThreadLocked(
Alexey Samsonov2bbd8be2013-03-15 13:48:44 +0000421 UpdateSleepClockCallback, thr);
Dmitry Vyukov84853112012-08-31 17:27:49 +0000422}
423#endif
424
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000425void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
426 if (thr->ignore_sync)
427 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700428 thr->clock.set(thr->fast_state.epoch());
Stephen Hines6d186232014-11-26 17:56:19 -0800429 thr->clock.acquire(&thr->clock_cache, c);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000430 StatInc(thr, StatSyncAcquire);
431}
432
433void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
434 if (thr->ignore_sync)
435 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700436 thr->clock.set(thr->fast_state.epoch());
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000437 thr->fast_synch_epoch = thr->fast_state.epoch();
Stephen Hines6d186232014-11-26 17:56:19 -0800438 thr->clock.release(&thr->clock_cache, c);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000439 StatInc(thr, StatSyncRelease);
440}
441
442void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
443 if (thr->ignore_sync)
444 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700445 thr->clock.set(thr->fast_state.epoch());
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000446 thr->fast_synch_epoch = thr->fast_state.epoch();
Stephen Hines6d186232014-11-26 17:56:19 -0800447 thr->clock.ReleaseStore(&thr->clock_cache, c);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000448 StatInc(thr, StatSyncRelease);
449}
450
451void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
452 if (thr->ignore_sync)
453 return;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700454 thr->clock.set(thr->fast_state.epoch());
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000455 thr->fast_synch_epoch = thr->fast_state.epoch();
Stephen Hines6d186232014-11-26 17:56:19 -0800456 thr->clock.acq_rel(&thr->clock_cache, c);
Dmitry Vyukove1ddbf92013-10-10 15:58:12 +0000457 StatInc(thr, StatSyncAcquire);
458 StatInc(thr, StatSyncRelease);
459}
460
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700461void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
462 if (r == 0)
463 return;
464 ThreadRegistryLock l(ctx->thread_registry);
465 ScopedReport rep(ReportTypeDeadlock);
466 for (int i = 0; i < r->n; i++) {
467 rep.AddMutex(r->loop[i].mtx_ctx0);
468 rep.AddUniqueTid((int)r->loop[i].thr_ctx);
469 rep.AddThread((int)r->loop[i].thr_ctx);
470 }
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700471 uptr dummy_pc = 0x42;
472 for (int i = 0; i < r->n; i++) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700473 for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
474 u32 stk = r->loop[i].stk[j];
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800475 if (stk && stk != 0xffffffff) {
Stephen Hines6d186232014-11-26 17:56:19 -0800476 rep.AddStack(StackDepotGet(stk), true);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700477 } else {
478 // Sometimes we fail to extract the stack trace (FIXME: investigate),
479 // but we should still produce some stack trace in the report.
Stephen Hines6d186232014-11-26 17:56:19 -0800480 rep.AddStack(StackTrace(&dummy_pc, 1), true);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700481 }
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700482 }
483 }
Stephen Hines6a211c52014-07-21 00:49:56 -0700484 OutputReport(thr, rep);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700485}
486
Kostya Serebryany7ac41482012-05-10 13:48:04 +0000487} // namespace __tsan