1162852Sdes//===-- tsan_rtl_mutex.cc -------------------------------------------------===// 298937Sdes// 398937Sdes// This file is distributed under the University of Illinois Open Source 498937Sdes// License. See LICENSE.TXT for details. 598937Sdes// 698937Sdes//===----------------------------------------------------------------------===// 798937Sdes// 898937Sdes// This file is a part of ThreadSanitizer (TSan), a race detector. 998937Sdes// 1098937Sdes//===----------------------------------------------------------------------===// 1198937Sdes 1298937Sdes#include <sanitizer_common/sanitizer_deadlock_detector_interface.h> 1398937Sdes#include <sanitizer_common/sanitizer_stackdepot.h> 1498937Sdes 1598937Sdes#include "tsan_rtl.h" 1698937Sdes#include "tsan_flags.h" 1798937Sdes#include "tsan_sync.h" 1898937Sdes#include "tsan_report.h" 19162852Sdes#include "tsan_symbolize.h" 2098937Sdes#include "tsan_platform.h" 21157016Sdes 2298937Sdesnamespace __tsan { 23162852Sdes 2498937Sdesvoid ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r); 2598937Sdes 2698937Sdesstruct Callback : DDCallback { 2798937Sdes ThreadState *thr; 2898937Sdes uptr pc; 2998937Sdes 3098937Sdes Callback(ThreadState *thr, uptr pc) 3198937Sdes : thr(thr) 3298937Sdes , pc(pc) { 3398937Sdes DDCallback::pt = thr->dd_pt; 3498937Sdes DDCallback::lt = thr->dd_lt; 3598937Sdes } 3698937Sdes 3798937Sdes virtual u32 Unwind() { 3898937Sdes return CurrentStackId(thr, pc); 3998937Sdes } 4098937Sdes virtual int UniqueTid() { 4198937Sdes return thr->unique_id; 4298937Sdes } 43}; 44 45void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) { 46 Callback cb(thr, pc); 47 ctx->dd->MutexInit(&cb, &s->dd); 48 s->dd.ctx = s->GetId(); 49} 50 51static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, 52 uptr addr, u64 mid) { 53 // In Go, these misuses are either impossible, or detected by std lib, 54 // or false positives (e.g. unlock in a different thread). 55 if (kGoMode) 56 return; 57 ThreadRegistryLock l(ctx->thread_registry); 58 ScopedReport rep(typ); 59 rep.AddMutex(mid); 60 VarSizeStackTrace trace; 61 ObtainCurrentStack(thr, pc, &trace); 62 rep.AddStack(trace, true); 63 rep.AddLocation(addr, 1); 64 OutputReport(thr, rep); 65} 66 67void MutexCreate(ThreadState *thr, uptr pc, uptr addr, 68 bool rw, bool recursive, bool linker_init) { 69 DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr); 70 StatInc(thr, StatMutexCreate); 71 if (!linker_init && IsAppMem(addr)) { 72 CHECK(!thr->is_freeing); 73 thr->is_freeing = true; 74 MemoryWrite(thr, pc, addr, kSizeLog1); 75 thr->is_freeing = false; 76 } 77 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 78 s->is_rw = rw; 79 s->is_recursive = recursive; 80 s->is_linker_init = linker_init; 81 if (kCppMode && s->creation_stack_id == 0) 82 s->creation_stack_id = CurrentStackId(thr, pc); 83 s->mtx.Unlock(); 84} 85 86void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { 87 DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); 88 StatInc(thr, StatMutexDestroy); 89#ifndef TSAN_GO 90 // Global mutexes not marked as LINKER_INITIALIZED 91 // cause tons of not interesting reports, so just ignore it. 92 if (IsGlobalVar(addr)) 93 return; 94#endif 95 if (IsAppMem(addr)) { 96 CHECK(!thr->is_freeing); 97 thr->is_freeing = true; 98 MemoryWrite(thr, pc, addr, kSizeLog1); 99 thr->is_freeing = false; 100 } 101 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); 102 if (s == 0) 103 return; 104 if (common_flags()->detect_deadlocks) { 105 Callback cb(thr, pc); 106 ctx->dd->MutexDestroy(&cb, &s->dd); 107 ctx->dd->MutexInit(&cb, &s->dd); 108 } 109 bool unlock_locked = false; 110 if (flags()->report_destroy_locked 111 && s->owner_tid != SyncVar::kInvalidTid 112 && !s->is_broken) { 113 s->is_broken = true; 114 unlock_locked = true; 115 } 116 u64 mid = s->GetId(); 117 u32 last_lock = s->last_lock; 118 if (!unlock_locked) 119 s->Reset(thr); // must not reset it before the report is printed 120 s->mtx.Unlock(); 121 if (unlock_locked) { 122 ThreadRegistryLock l(ctx->thread_registry); 123 ScopedReport rep(ReportTypeMutexDestroyLocked); 124 rep.AddMutex(mid); 125 VarSizeStackTrace trace; 126 ObtainCurrentStack(thr, pc, &trace); 127 rep.AddStack(trace); 128 FastState last(last_lock); 129 RestoreStack(last.tid(), last.epoch(), &trace, 0); 130 rep.AddStack(trace, true); 131 rep.AddLocation(addr, 1); 132 OutputReport(thr, rep); 133 } 134 if (unlock_locked) { 135 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr); 136 if (s != 0) { 137 s->Reset(thr); 138 s->mtx.Unlock(); 139 } 140 } 141 thr->mset.Remove(mid); 142 // s will be destroyed and freed in MetaMap::FreeBlock. 143} 144 145void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) { 146 DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec); 147 CHECK_GT(rec, 0); 148 if (IsAppMem(addr)) 149 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 150 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 151 thr->fast_state.IncrementEpoch(); 152 TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); 153 bool report_double_lock = false; 154 if (s->owner_tid == SyncVar::kInvalidTid) { 155 CHECK_EQ(s->recursion, 0); 156 s->owner_tid = thr->tid; 157 s->last_lock = thr->fast_state.raw(); 158 } else if (s->owner_tid == thr->tid) { 159 CHECK_GT(s->recursion, 0); 160 } else if (flags()->report_mutex_bugs && !s->is_broken) { 161 s->is_broken = true; 162 report_double_lock = true; 163 } 164 if (s->recursion == 0) { 165 StatInc(thr, StatMutexLock); 166 AcquireImpl(thr, pc, &s->clock); 167 AcquireImpl(thr, pc, &s->read_clock); 168 } else if (!s->is_recursive) { 169 StatInc(thr, StatMutexRecLock); 170 } 171 s->recursion += rec; 172 thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); 173 if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) { 174 Callback cb(thr, pc); 175 if (!try_lock) 176 ctx->dd->MutexBeforeLock(&cb, &s->dd, true); 177 ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock); 178 } 179 u64 mid = s->GetId(); 180 s->mtx.Unlock(); 181 // Can't touch s after this point. 182 if (report_double_lock) 183 ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); 184 if (common_flags()->detect_deadlocks) { 185 Callback cb(thr, pc); 186 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 187 } 188} 189 190int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { 191 DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all); 192 if (IsAppMem(addr)) 193 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 194 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 195 thr->fast_state.IncrementEpoch(); 196 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); 197 int rec = 0; 198 bool report_bad_unlock = false; 199 if (kCppMode && (s->recursion == 0 || s->owner_tid != thr->tid)) { 200 if (flags()->report_mutex_bugs && !s->is_broken) { 201 s->is_broken = true; 202 report_bad_unlock = true; 203 } 204 } else { 205 rec = all ? s->recursion : 1; 206 s->recursion -= rec; 207 if (s->recursion == 0) { 208 StatInc(thr, StatMutexUnlock); 209 s->owner_tid = SyncVar::kInvalidTid; 210 ReleaseStoreImpl(thr, pc, &s->clock); 211 } else { 212 StatInc(thr, StatMutexRecUnlock); 213 } 214 } 215 thr->mset.Del(s->GetId(), true); 216 if (common_flags()->detect_deadlocks && s->recursion == 0 && 217 !report_bad_unlock) { 218 Callback cb(thr, pc); 219 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); 220 } 221 u64 mid = s->GetId(); 222 s->mtx.Unlock(); 223 // Can't touch s after this point. 224 if (report_bad_unlock) 225 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); 226 if (common_flags()->detect_deadlocks && !report_bad_unlock) { 227 Callback cb(thr, pc); 228 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 229 } 230 return rec; 231} 232 233void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) { 234 DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr); 235 StatInc(thr, StatMutexReadLock); 236 if (IsAppMem(addr)) 237 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 238 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); 239 thr->fast_state.IncrementEpoch(); 240 TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); 241 bool report_bad_lock = false; 242 if (s->owner_tid != SyncVar::kInvalidTid) { 243 if (flags()->report_mutex_bugs && !s->is_broken) { 244 s->is_broken = true; 245 report_bad_lock = true; 246 } 247 } 248 AcquireImpl(thr, pc, &s->clock); 249 s->last_lock = thr->fast_state.raw(); 250 thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); 251 if (common_flags()->detect_deadlocks && s->recursion == 0) { 252 Callback cb(thr, pc); 253 if (!trylock) 254 ctx->dd->MutexBeforeLock(&cb, &s->dd, false); 255 ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock); 256 } 257 u64 mid = s->GetId(); 258 s->mtx.ReadUnlock(); 259 // Can't touch s after this point. 260 if (report_bad_lock) 261 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); 262 if (common_flags()->detect_deadlocks) { 263 Callback cb(thr, pc); 264 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 265 } 266} 267 268void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { 269 DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr); 270 StatInc(thr, StatMutexReadUnlock); 271 if (IsAppMem(addr)) 272 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 273 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 274 thr->fast_state.IncrementEpoch(); 275 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); 276 bool report_bad_unlock = false; 277 if (s->owner_tid != SyncVar::kInvalidTid) { 278 if (flags()->report_mutex_bugs && !s->is_broken) { 279 s->is_broken = true; 280 report_bad_unlock = true; 281 } 282 } 283 ReleaseImpl(thr, pc, &s->read_clock); 284 if (common_flags()->detect_deadlocks && s->recursion == 0) { 285 Callback cb(thr, pc); 286 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false); 287 } 288 u64 mid = s->GetId(); 289 s->mtx.Unlock(); 290 // Can't touch s after this point. 291 thr->mset.Del(mid, false); 292 if (report_bad_unlock) 293 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid); 294 if (common_flags()->detect_deadlocks) { 295 Callback cb(thr, pc); 296 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 297 } 298} 299 300void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { 301 DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); 302 if (IsAppMem(addr)) 303 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 304 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 305 bool write = true; 306 bool report_bad_unlock = false; 307 if (s->owner_tid == SyncVar::kInvalidTid) { 308 // Seems to be read unlock. 309 write = false; 310 StatInc(thr, StatMutexReadUnlock); 311 thr->fast_state.IncrementEpoch(); 312 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); 313 ReleaseImpl(thr, pc, &s->read_clock); 314 } else if (s->owner_tid == thr->tid) { 315 // Seems to be write unlock. 316 thr->fast_state.IncrementEpoch(); 317 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); 318 CHECK_GT(s->recursion, 0); 319 s->recursion--; 320 if (s->recursion == 0) { 321 StatInc(thr, StatMutexUnlock); 322 s->owner_tid = SyncVar::kInvalidTid; 323 ReleaseImpl(thr, pc, &s->clock); 324 } else { 325 StatInc(thr, StatMutexRecUnlock); 326 } 327 } else if (!s->is_broken) { 328 s->is_broken = true; 329 report_bad_unlock = true; 330 } 331 thr->mset.Del(s->GetId(), write); 332 if (common_flags()->detect_deadlocks && s->recursion == 0) { 333 Callback cb(thr, pc); 334 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write); 335 } 336 u64 mid = s->GetId(); 337 s->mtx.Unlock(); 338 // Can't touch s after this point. 339 if (report_bad_unlock) 340 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); 341 if (common_flags()->detect_deadlocks) { 342 Callback cb(thr, pc); 343 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 344 } 345} 346 347void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { 348 DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); 349 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 350 s->owner_tid = SyncVar::kInvalidTid; 351 s->recursion = 0; 352 s->mtx.Unlock(); 353} 354 355void Acquire(ThreadState *thr, uptr pc, uptr addr) { 356 DPrintf("#%d: Acquire %zx\n", thr->tid, addr); 357 if (thr->ignore_sync) 358 return; 359 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); 360 AcquireImpl(thr, pc, &s->clock); 361 s->mtx.ReadUnlock(); 362} 363 364static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) { 365 ThreadState *thr = reinterpret_cast<ThreadState*>(arg); 366 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 367 if (tctx->status == ThreadStatusRunning) 368 thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch()); 369 else 370 thr->clock.set(tctx->tid, tctx->epoch1); 371} 372 373void AcquireGlobal(ThreadState *thr, uptr pc) { 374 DPrintf("#%d: AcquireGlobal\n", thr->tid); 375 if (thr->ignore_sync) 376 return; 377 ThreadRegistryLock l(ctx->thread_registry); 378 ctx->thread_registry->RunCallbackForEachThreadLocked( 379 UpdateClockCallback, thr); 380} 381 382void Release(ThreadState *thr, uptr pc, uptr addr) { 383 DPrintf("#%d: Release %zx\n", thr->tid, addr); 384 if (thr->ignore_sync) 385 return; 386 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 387 thr->fast_state.IncrementEpoch(); 388 // Can't increment epoch w/o writing to the trace as well. 389 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 390 ReleaseImpl(thr, pc, &s->clock); 391 s->mtx.Unlock(); 392} 393 394void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { 395 DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); 396 if (thr->ignore_sync) 397 return; 398 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 399 thr->fast_state.IncrementEpoch(); 400 // Can't increment epoch w/o writing to the trace as well. 401 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 402 ReleaseStoreImpl(thr, pc, &s->clock); 403 s->mtx.Unlock(); 404} 405 406#ifndef TSAN_GO 407static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) { 408 ThreadState *thr = reinterpret_cast<ThreadState*>(arg); 409 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 410 if (tctx->status == ThreadStatusRunning) 411 thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch()); 412 else 413 thr->last_sleep_clock.set(tctx->tid, tctx->epoch1); 414} 415 416void AfterSleep(ThreadState *thr, uptr pc) { 417 DPrintf("#%d: AfterSleep %zx\n", thr->tid); 418 if (thr->ignore_sync) 419 return; 420 thr->last_sleep_stack_id = CurrentStackId(thr, pc); 421 ThreadRegistryLock l(ctx->thread_registry); 422 ctx->thread_registry->RunCallbackForEachThreadLocked( 423 UpdateSleepClockCallback, thr); 424} 425#endif 426 427void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { 428 if (thr->ignore_sync) 429 return; 430 thr->clock.set(thr->fast_state.epoch()); 431 thr->clock.acquire(&thr->clock_cache, c); 432 StatInc(thr, StatSyncAcquire); 433} 434 435void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { 436 if (thr->ignore_sync) 437 return; 438 thr->clock.set(thr->fast_state.epoch()); 439 thr->fast_synch_epoch = thr->fast_state.epoch(); 440 thr->clock.release(&thr->clock_cache, c); 441 StatInc(thr, StatSyncRelease); 442} 443 444void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { 445 if (thr->ignore_sync) 446 return; 447 thr->clock.set(thr->fast_state.epoch()); 448 thr->fast_synch_epoch = thr->fast_state.epoch(); 449 thr->clock.ReleaseStore(&thr->clock_cache, c); 450 StatInc(thr, StatSyncRelease); 451} 452 453void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { 454 if (thr->ignore_sync) 455 return; 456 thr->clock.set(thr->fast_state.epoch()); 457 thr->fast_synch_epoch = thr->fast_state.epoch(); 458 thr->clock.acq_rel(&thr->clock_cache, c); 459 StatInc(thr, StatSyncAcquire); 460 StatInc(thr, StatSyncRelease); 461} 462 463void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { 464 if (r == 0) 465 return; 466 ThreadRegistryLock l(ctx->thread_registry); 467 ScopedReport rep(ReportTypeDeadlock); 468 for (int i = 0; i < r->n; i++) { 469 rep.AddMutex(r->loop[i].mtx_ctx0); 470 rep.AddUniqueTid((int)r->loop[i].thr_ctx); 471 rep.AddThread((int)r->loop[i].thr_ctx); 472 } 473 uptr dummy_pc = 0x42; 474 for (int i = 0; i < r->n; i++) { 475 for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { 476 u32 stk = r->loop[i].stk[j]; 477 if (stk) { 478 rep.AddStack(StackDepotGet(stk), true); 479 } else { 480 // Sometimes we fail to extract the stack trace (FIXME: investigate), 481 // but we should still produce some stack trace in the report. 482 rep.AddStack(StackTrace(&dummy_pc, 1), true); 483 } 484 } 485 } 486 OutputReport(thr, rep); 487} 488 489} // namespace __tsan 490