Alexey Samsonov | 603c4be | 2012-06-04 13:55:19 +0000 | [diff] [blame] | 1 | //===-- tsan_rtl_mutex.cc -------------------------------------------------===// |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 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 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 14 | #include <sanitizer_common/sanitizer_deadlock_detector_interface.h> |
| 15 | #include <sanitizer_common/sanitizer_stackdepot.h> |
| 16 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 17 | #include "tsan_rtl.h" |
Dmitry Vyukov | fd51390 | 2012-08-16 15:12:35 +0000 | [diff] [blame] | 18 | #include "tsan_flags.h" |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 19 | #include "tsan_sync.h" |
| 20 | #include "tsan_report.h" |
| 21 | #include "tsan_symbolize.h" |
Dmitry Vyukov | 9adce67 | 2012-08-31 20:02:33 +0000 | [diff] [blame] | 22 | #include "tsan_platform.h" |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 23 | |
| 24 | namespace __tsan { |
| 25 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 26 | void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r); |
| 27 | |
| 28 | struct 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 Nainar | 259f706 | 2015-05-06 11:49:53 -0700 | [diff] [blame] | 39 | u32 Unwind() override { return CurrentStackId(thr, pc); } |
| 40 | int UniqueTid() override { return thr->unique_id; } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 41 | }; |
| 42 | |
| 43 | void 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 | |
| 49 | static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, |
| 50 | uptr addr, u64 mid) { |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 51 | // 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 Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 55 | ThreadRegistryLock l(ctx->thread_registry); |
| 56 | ScopedReport rep(typ); |
| 57 | rep.AddMutex(mid); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 58 | VarSizeStackTrace trace; |
| 59 | ObtainCurrentStack(thr, pc, &trace); |
| 60 | rep.AddStack(trace, true); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 61 | rep.AddLocation(addr, 1); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 62 | OutputReport(thr, rep); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 63 | } |
| 64 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 65 | void MutexCreate(ThreadState *thr, uptr pc, uptr addr, |
Dmitry Vyukov | c20e9ba | 2012-08-16 13:29:41 +0000 | [diff] [blame] | 66 | bool rw, bool recursive, bool linker_init) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 67 | DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 68 | StatInc(thr, StatMutexCreate); |
Dmitry Vyukov | 3285866 | 2013-02-01 14:41:58 +0000 | [diff] [blame] | 69 | if (!linker_init && IsAppMem(addr)) { |
| 70 | CHECK(!thr->is_freeing); |
| 71 | thr->is_freeing = true; |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 72 | MemoryWrite(thr, pc, addr, kSizeLog1); |
Dmitry Vyukov | 3285866 | 2013-02-01 14:41:58 +0000 | [diff] [blame] | 73 | thr->is_freeing = false; |
| 74 | } |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 75 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 76 | s->is_rw = rw; |
| 77 | s->is_recursive = recursive; |
Dmitry Vyukov | 2e933fc | 2012-08-16 14:21:09 +0000 | [diff] [blame] | 78 | s->is_linker_init = linker_init; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 79 | if (kCppMode && s->creation_stack_id == 0) |
| 80 | s->creation_stack_id = CurrentStackId(thr, pc); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 81 | s->mtx.Unlock(); |
| 82 | } |
| 83 | |
| 84 | void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 85 | DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 86 | StatInc(thr, StatMutexDestroy); |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 87 | #ifndef SANITIZER_GO |
Dmitry Vyukov | 0c2feef | 2012-09-07 18:08:02 +0000 | [diff] [blame] | 88 | // 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 Vyukov | 3285866 | 2013-02-01 14:41:58 +0000 | [diff] [blame] | 93 | if (IsAppMem(addr)) { |
| 94 | CHECK(!thr->is_freeing); |
| 95 | thr->is_freeing = true; |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 96 | MemoryWrite(thr, pc, addr, kSizeLog1); |
Dmitry Vyukov | 3285866 | 2013-02-01 14:41:58 +0000 | [diff] [blame] | 97 | thr->is_freeing = false; |
| 98 | } |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 99 | SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); |
| 100 | if (s == 0) |
| 101 | return; |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 102 | if (common_flags()->detect_deadlocks) { |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 103 | 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 Vyukov | 55e711e | 2012-08-18 11:49:00 +0000 | [diff] [blame] | 108 | if (flags()->report_destroy_locked |
| 109 | && s->owner_tid != SyncVar::kInvalidTid |
| 110 | && !s->is_broken) { |
| 111 | s->is_broken = true; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 112 | unlock_locked = true; |
| 113 | } |
| 114 | u64 mid = s->GetId(); |
| 115 | u32 last_lock = s->last_lock; |
| 116 | if (!unlock_locked) |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 117 | s->Reset(thr); // must not reset it before the report is printed |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 118 | s->mtx.Unlock(); |
| 119 | if (unlock_locked) { |
Alexey Samsonov | 2bbd8be | 2013-03-15 13:48:44 +0000 | [diff] [blame] | 120 | ThreadRegistryLock l(ctx->thread_registry); |
Dmitry Vyukov | 55e711e | 2012-08-18 11:49:00 +0000 | [diff] [blame] | 121 | ScopedReport rep(ReportTypeMutexDestroyLocked); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 122 | rep.AddMutex(mid); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 123 | VarSizeStackTrace trace; |
| 124 | ObtainCurrentStack(thr, pc, &trace); |
| 125 | rep.AddStack(trace); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 126 | FastState last(last_lock); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 127 | RestoreStack(last.tid(), last.epoch(), &trace, 0); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 128 | rep.AddStack(trace, true); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 129 | rep.AddLocation(addr, 1); |
| 130 | OutputReport(thr, rep); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 131 | } |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 132 | if (unlock_locked) { |
| 133 | SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); |
| 134 | if (s != 0) { |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 135 | s->Reset(thr); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 136 | s->mtx.Unlock(); |
| 137 | } |
| 138 | } |
| 139 | thr->mset.Remove(mid); |
| 140 | // s will be destroyed and freed in MetaMap::FreeBlock. |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 141 | } |
| 142 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 143 | void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 144 | DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec); |
| 145 | CHECK_GT(rec, 0); |
Dmitry Vyukov | 9adce67 | 2012-08-31 20:02:33 +0000 | [diff] [blame] | 146 | if (IsAppMem(addr)) |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 147 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 148 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 149 | thr->fast_state.IncrementEpoch(); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 150 | TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 151 | bool report_double_lock = false; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 152 | if (s->owner_tid == SyncVar::kInvalidTid) { |
| 153 | CHECK_EQ(s->recursion, 0); |
| 154 | s->owner_tid = thr->tid; |
Dmitry Vyukov | 332c62b | 2012-08-16 15:08:49 +0000 | [diff] [blame] | 155 | s->last_lock = thr->fast_state.raw(); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 156 | } else if (s->owner_tid == thr->tid) { |
| 157 | CHECK_GT(s->recursion, 0); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 158 | } else if (flags()->report_mutex_bugs && !s->is_broken) { |
| 159 | s->is_broken = true; |
| 160 | report_double_lock = true; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 161 | } |
| 162 | if (s->recursion == 0) { |
| 163 | StatInc(thr, StatMutexLock); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 164 | AcquireImpl(thr, pc, &s->clock); |
| 165 | AcquireImpl(thr, pc, &s->read_clock); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 166 | } else if (!s->is_recursive) { |
| 167 | StatInc(thr, StatMutexRecLock); |
| 168 | } |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 169 | s->recursion += rec; |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 170 | thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 171 | if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 172 | 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 Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 178 | s->mtx.Unlock(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 179 | // Can't touch s after this point. |
| 180 | if (report_double_lock) |
| 181 | ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 182 | if (common_flags()->detect_deadlocks) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 183 | Callback cb(thr, pc); |
| 184 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); |
| 185 | } |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 186 | } |
| 187 | |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 188 | int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 189 | DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all); |
Dmitry Vyukov | 9adce67 | 2012-08-31 20:02:33 +0000 | [diff] [blame] | 190 | if (IsAppMem(addr)) |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 191 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 192 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 193 | thr->fast_state.IncrementEpoch(); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 194 | TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 195 | int rec = 0; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 196 | bool report_bad_unlock = false; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 197 | if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 198 | if (flags()->report_mutex_bugs && !s->is_broken) { |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 199 | s->is_broken = true; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 200 | report_bad_unlock = true; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 201 | } |
| 202 | } else { |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 203 | rec = all ? s->recursion : 1; |
| 204 | s->recursion -= rec; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 205 | if (s->recursion == 0) { |
| 206 | StatInc(thr, StatMutexUnlock); |
| 207 | s->owner_tid = SyncVar::kInvalidTid; |
Dmitry Vyukov | 117699d | 2013-10-10 16:03:24 +0000 | [diff] [blame] | 208 | ReleaseStoreImpl(thr, pc, &s->clock); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 209 | } else { |
| 210 | StatInc(thr, StatMutexRecUnlock); |
| 211 | } |
| 212 | } |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 213 | thr->mset.Del(s->GetId(), true); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 214 | if (common_flags()->detect_deadlocks && s->recursion == 0 && |
| 215 | !report_bad_unlock) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 216 | Callback cb(thr, pc); |
| 217 | ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); |
| 218 | } |
| 219 | u64 mid = s->GetId(); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 220 | s->mtx.Unlock(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 221 | // Can't touch s after this point. |
| 222 | if (report_bad_unlock) |
| 223 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 224 | if (common_flags()->detect_deadlocks && !report_bad_unlock) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 225 | Callback cb(thr, pc); |
| 226 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); |
| 227 | } |
Dmitry Vyukov | 8354fae | 2013-05-17 12:03:46 +0000 | [diff] [blame] | 228 | return rec; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 229 | } |
| 230 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 231 | void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 232 | DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 233 | StatInc(thr, StatMutexReadLock); |
Dmitry Vyukov | 9adce67 | 2012-08-31 20:02:33 +0000 | [diff] [blame] | 234 | if (IsAppMem(addr)) |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 235 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 236 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 237 | thr->fast_state.IncrementEpoch(); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 238 | TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 239 | bool report_bad_lock = false; |
Dmitry Vyukov | 1da1056 | 2012-09-01 12:13:18 +0000 | [diff] [blame] | 240 | if (s->owner_tid != SyncVar::kInvalidTid) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 241 | if (flags()->report_mutex_bugs && !s->is_broken) { |
| 242 | s->is_broken = true; |
| 243 | report_bad_lock = true; |
| 244 | } |
Dmitry Vyukov | 1da1056 | 2012-09-01 12:13:18 +0000 | [diff] [blame] | 245 | } |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 246 | AcquireImpl(thr, pc, &s->clock); |
Dmitry Vyukov | 332c62b | 2012-08-16 15:08:49 +0000 | [diff] [blame] | 247 | s->last_lock = thr->fast_state.raw(); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 248 | thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 249 | if (common_flags()->detect_deadlocks && s->recursion == 0) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 250 | 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 Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 256 | s->mtx.ReadUnlock(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 257 | // Can't touch s after this point. |
| 258 | if (report_bad_lock) |
| 259 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 260 | if (common_flags()->detect_deadlocks) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 261 | Callback cb(thr, pc); |
| 262 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); |
| 263 | } |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 264 | } |
| 265 | |
| 266 | void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 267 | DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 268 | StatInc(thr, StatMutexReadUnlock); |
Dmitry Vyukov | 9adce67 | 2012-08-31 20:02:33 +0000 | [diff] [blame] | 269 | if (IsAppMem(addr)) |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 270 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 271 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 272 | thr->fast_state.IncrementEpoch(); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 273 | TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 274 | bool report_bad_unlock = false; |
Dmitry Vyukov | 1da1056 | 2012-09-01 12:13:18 +0000 | [diff] [blame] | 275 | if (s->owner_tid != SyncVar::kInvalidTid) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 276 | if (flags()->report_mutex_bugs && !s->is_broken) { |
| 277 | s->is_broken = true; |
| 278 | report_bad_unlock = true; |
| 279 | } |
Dmitry Vyukov | 1da1056 | 2012-09-01 12:13:18 +0000 | [diff] [blame] | 280 | } |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 281 | ReleaseImpl(thr, pc, &s->read_clock); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 282 | if (common_flags()->detect_deadlocks && s->recursion == 0) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 283 | Callback cb(thr, pc); |
| 284 | ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false); |
| 285 | } |
| 286 | u64 mid = s->GetId(); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 287 | s->mtx.Unlock(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 288 | // 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 Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 292 | if (common_flags()->detect_deadlocks) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 293 | Callback cb(thr, pc); |
| 294 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); |
| 295 | } |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 299 | DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); |
Dmitry Vyukov | 9adce67 | 2012-08-31 20:02:33 +0000 | [diff] [blame] | 300 | if (IsAppMem(addr)) |
Dmitry Vyukov | 334553e | 2013-02-01 09:42:06 +0000 | [diff] [blame] | 301 | MemoryReadAtomic(thr, pc, addr, kSizeLog1); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 302 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 303 | bool write = true; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 304 | bool report_bad_unlock = false; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 305 | if (s->owner_tid == SyncVar::kInvalidTid) { |
| 306 | // Seems to be read unlock. |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 307 | write = false; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 308 | StatInc(thr, StatMutexReadUnlock); |
| 309 | thr->fast_state.IncrementEpoch(); |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 310 | TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 311 | ReleaseImpl(thr, pc, &s->read_clock); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 312 | } else if (s->owner_tid == thr->tid) { |
| 313 | // Seems to be write unlock. |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 314 | thr->fast_state.IncrementEpoch(); |
| 315 | TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 316 | CHECK_GT(s->recursion, 0); |
| 317 | s->recursion--; |
| 318 | if (s->recursion == 0) { |
| 319 | StatInc(thr, StatMutexUnlock); |
| 320 | s->owner_tid = SyncVar::kInvalidTid; |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 321 | ReleaseImpl(thr, pc, &s->clock); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 322 | } else { |
| 323 | StatInc(thr, StatMutexRecUnlock); |
| 324 | } |
| 325 | } else if (!s->is_broken) { |
| 326 | s->is_broken = true; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 327 | report_bad_unlock = true; |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 328 | } |
Dmitry Vyukov | ad9da37 | 2012-12-06 12:16:15 +0000 | [diff] [blame] | 329 | thr->mset.Del(s->GetId(), write); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 330 | if (common_flags()->detect_deadlocks && s->recursion == 0) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 331 | Callback cb(thr, pc); |
| 332 | ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write); |
| 333 | } |
| 334 | u64 mid = s->GetId(); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 335 | s->mtx.Unlock(); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 336 | // Can't touch s after this point. |
| 337 | if (report_bad_unlock) |
| 338 | ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 339 | if (common_flags()->detect_deadlocks) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 340 | Callback cb(thr, pc); |
| 341 | ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); |
| 342 | } |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 343 | } |
| 344 | |
Dmitry Vyukov | 11f5309 | 2013-11-15 16:58:12 +0000 | [diff] [blame] | 345 | void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { |
Dmitry Vyukov | 11f5309 | 2013-11-15 16:58:12 +0000 | [diff] [blame] | 346 | DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 347 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Dmitry Vyukov | 11f5309 | 2013-11-15 16:58:12 +0000 | [diff] [blame] | 348 | s->owner_tid = SyncVar::kInvalidTid; |
| 349 | s->recursion = 0; |
| 350 | s->mtx.Unlock(); |
| 351 | } |
| 352 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 353 | void Acquire(ThreadState *thr, uptr pc, uptr addr) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 354 | DPrintf("#%d: Acquire %zx\n", thr->tid, addr); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 355 | if (thr->ignore_sync) |
| 356 | return; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 357 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 358 | AcquireImpl(thr, pc, &s->clock); |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 359 | s->mtx.ReadUnlock(); |
| 360 | } |
| 361 | |
Alexey Samsonov | 2bbd8be | 2013-03-15 13:48:44 +0000 | [diff] [blame] | 362 | static 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 Vyukov | 538f1ba | 2012-11-07 15:08:20 +0000 | [diff] [blame] | 371 | void AcquireGlobal(ThreadState *thr, uptr pc) { |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 372 | DPrintf("#%d: AcquireGlobal\n", thr->tid); |
| 373 | if (thr->ignore_sync) |
| 374 | return; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 375 | ThreadRegistryLock l(ctx->thread_registry); |
| 376 | ctx->thread_registry->RunCallbackForEachThreadLocked( |
Alexey Samsonov | 2bbd8be | 2013-03-15 13:48:44 +0000 | [diff] [blame] | 377 | UpdateClockCallback, thr); |
Dmitry Vyukov | 538f1ba | 2012-11-07 15:08:20 +0000 | [diff] [blame] | 378 | } |
| 379 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 380 | void Release(ThreadState *thr, uptr pc, uptr addr) { |
Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 381 | DPrintf("#%d: Release %zx\n", thr->tid, addr); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 382 | if (thr->ignore_sync) |
| 383 | return; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 384 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 385 | 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 Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 389 | s->mtx.Unlock(); |
| 390 | } |
| 391 | |
Dmitry Vyukov | 9d150bd | 2012-07-28 15:27:41 +0000 | [diff] [blame] | 392 | void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { |
Dmitry Vyukov | 9d150bd | 2012-07-28 15:27:41 +0000 | [diff] [blame] | 393 | DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 394 | if (thr->ignore_sync) |
| 395 | return; |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 396 | SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 397 | 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 Vyukov | 9d150bd | 2012-07-28 15:27:41 +0000 | [diff] [blame] | 401 | s->mtx.Unlock(); |
| 402 | } |
| 403 | |
Stephen Hines | 86277eb | 2015-03-23 12:06:32 -0700 | [diff] [blame] | 404 | #ifndef SANITIZER_GO |
Alexey Samsonov | 2bbd8be | 2013-03-15 13:48:44 +0000 | [diff] [blame] | 405 | static 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 Vyukov | 8485311 | 2012-08-31 17:27:49 +0000 | [diff] [blame] | 414 | void AfterSleep(ThreadState *thr, uptr pc) { |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 415 | DPrintf("#%d: AfterSleep %zx\n", thr->tid); |
| 416 | if (thr->ignore_sync) |
| 417 | return; |
Dmitry Vyukov | 8485311 | 2012-08-31 17:27:49 +0000 | [diff] [blame] | 418 | thr->last_sleep_stack_id = CurrentStackId(thr, pc); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 419 | ThreadRegistryLock l(ctx->thread_registry); |
| 420 | ctx->thread_registry->RunCallbackForEachThreadLocked( |
Alexey Samsonov | 2bbd8be | 2013-03-15 13:48:44 +0000 | [diff] [blame] | 421 | UpdateSleepClockCallback, thr); |
Dmitry Vyukov | 8485311 | 2012-08-31 17:27:49 +0000 | [diff] [blame] | 422 | } |
| 423 | #endif |
| 424 | |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 425 | void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { |
| 426 | if (thr->ignore_sync) |
| 427 | return; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 428 | thr->clock.set(thr->fast_state.epoch()); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 429 | thr->clock.acquire(&thr->clock_cache, c); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 430 | StatInc(thr, StatSyncAcquire); |
| 431 | } |
| 432 | |
| 433 | void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { |
| 434 | if (thr->ignore_sync) |
| 435 | return; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 436 | thr->clock.set(thr->fast_state.epoch()); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 437 | thr->fast_synch_epoch = thr->fast_state.epoch(); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 438 | thr->clock.release(&thr->clock_cache, c); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 439 | StatInc(thr, StatSyncRelease); |
| 440 | } |
| 441 | |
| 442 | void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { |
| 443 | if (thr->ignore_sync) |
| 444 | return; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 445 | thr->clock.set(thr->fast_state.epoch()); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 446 | thr->fast_synch_epoch = thr->fast_state.epoch(); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 447 | thr->clock.ReleaseStore(&thr->clock_cache, c); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 448 | StatInc(thr, StatSyncRelease); |
| 449 | } |
| 450 | |
| 451 | void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { |
| 452 | if (thr->ignore_sync) |
| 453 | return; |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 454 | thr->clock.set(thr->fast_state.epoch()); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 455 | thr->fast_synch_epoch = thr->fast_state.epoch(); |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 456 | thr->clock.acq_rel(&thr->clock_cache, c); |
Dmitry Vyukov | e1ddbf9 | 2013-10-10 15:58:12 +0000 | [diff] [blame] | 457 | StatInc(thr, StatSyncAcquire); |
| 458 | StatInc(thr, StatSyncRelease); |
| 459 | } |
| 460 | |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 461 | void 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 Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 471 | uptr dummy_pc = 0x42; |
| 472 | for (int i = 0; i < r->n; i++) { |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 473 | for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { |
| 474 | u32 stk = r->loop[i].stk[j]; |
Pirama Arumuga Nainar | 799172d | 2016-03-03 15:50:30 -0800 | [diff] [blame^] | 475 | if (stk && stk != 0xffffffff) { |
Stephen Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 476 | rep.AddStack(StackDepotGet(stk), true); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 477 | } 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 Hines | 6d18623 | 2014-11-26 17:56:19 -0800 | [diff] [blame] | 480 | rep.AddStack(StackTrace(&dummy_pc, 1), true); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 481 | } |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 482 | } |
| 483 | } |
Stephen Hines | 6a211c5 | 2014-07-21 00:49:56 -0700 | [diff] [blame] | 484 | OutputReport(thr, rep); |
Stephen Hines | 2d1fdb2 | 2014-05-28 23:58:16 -0700 | [diff] [blame] | 485 | } |
| 486 | |
Kostya Serebryany | 7ac4148 | 2012-05-10 13:48:04 +0000 | [diff] [blame] | 487 | } // namespace __tsan |