1 //===-- tsan_rtl_mutex.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of ThreadSanitizer (TSan), a race detector. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include <sanitizer_common/sanitizer_deadlock_detector_interface.h> 14 #include <sanitizer_common/sanitizer_stackdepot.h> 15 16 #include "tsan_rtl.h" 17 #include "tsan_flags.h" 18 #include "tsan_sync.h" 19 #include "tsan_report.h" 20 #include "tsan_symbolize.h" 21 #include "tsan_platform.h" 22 23 namespace __tsan { 24 25 void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r); 26 27 struct Callback final : public DDCallback { 28 ThreadState *thr; 29 uptr pc; 30 31 Callback(ThreadState *thr, uptr pc) 32 : thr(thr) 33 , pc(pc) { 34 DDCallback::pt = thr->proc()->dd_pt; 35 DDCallback::lt = thr->dd_lt; 36 } 37 38 StackID Unwind() override { return CurrentStackId(thr, pc); } 39 int UniqueTid() override { return thr->unique_id; } 40 }; 41 42 void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) { 43 Callback cb(thr, pc); 44 ctx->dd->MutexInit(&cb, &s->dd); 45 s->dd.ctx = s->GetId(); 46 } 47 48 static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ, 49 uptr addr, u64 mid) { 50 // In Go, these misuses are either impossible, or detected by std lib, 51 // or false positives (e.g. unlock in a different thread). 52 if (SANITIZER_GO) 53 return; 54 if (!ShouldReport(thr, typ)) 55 return; 56 ThreadRegistryLock l(&ctx->thread_registry); 57 ScopedReport rep(typ); 58 rep.AddMutex(mid); 59 VarSizeStackTrace trace; 60 ObtainCurrentStack(thr, pc, &trace); 61 rep.AddStack(trace, true); 62 rep.AddLocation(addr, 1); 63 OutputReport(thr, rep); 64 } 65 66 void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 67 DPrintf("#%d: MutexCreate %zx flagz=0x%x\n", thr->tid, addr, flagz); 68 if (!(flagz & MutexFlagLinkerInit) && IsAppMem(addr)) { 69 CHECK(!thr->is_freeing); 70 thr->is_freeing = true; 71 MemoryAccess(thr, pc, addr, 1, kAccessWrite); 72 thr->is_freeing = false; 73 } 74 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 75 Lock l(&s->mtx); 76 s->SetFlags(flagz & MutexCreationFlagMask); 77 // Save stack in the case the sync object was created before as atomic. 78 if (!SANITIZER_GO && s->creation_stack_id == 0) 79 s->creation_stack_id = CurrentStackId(thr, pc); 80 } 81 82 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 83 DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); 84 bool unlock_locked = false; 85 u64 mid = 0; 86 u64 last_lock = 0; 87 { 88 SyncVar *s = ctx->metamap.GetSyncIfExists(addr); 89 if (s == 0) 90 return; 91 Lock l(&s->mtx); 92 if ((flagz & MutexFlagLinkerInit) || s->IsFlagSet(MutexFlagLinkerInit) || 93 ((flagz & MutexFlagNotStatic) && !s->IsFlagSet(MutexFlagNotStatic))) { 94 // Destroy is no-op for linker-initialized mutexes. 95 return; 96 } 97 if (common_flags()->detect_deadlocks) { 98 Callback cb(thr, pc); 99 ctx->dd->MutexDestroy(&cb, &s->dd); 100 ctx->dd->MutexInit(&cb, &s->dd); 101 } 102 if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid && 103 !s->IsFlagSet(MutexFlagBroken)) { 104 s->SetFlags(MutexFlagBroken); 105 unlock_locked = true; 106 } 107 mid = s->GetId(); 108 last_lock = s->last_lock; 109 if (!unlock_locked) 110 s->Reset(thr->proc()); // must not reset it before the report is printed 111 } 112 if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) { 113 ThreadRegistryLock l(&ctx->thread_registry); 114 ScopedReport rep(ReportTypeMutexDestroyLocked); 115 rep.AddMutex(mid); 116 VarSizeStackTrace trace; 117 ObtainCurrentStack(thr, pc, &trace); 118 rep.AddStack(trace, true); 119 FastState last(last_lock); 120 RestoreStack(last.tid(), last.epoch(), &trace, 0); 121 rep.AddStack(trace, true); 122 rep.AddLocation(addr, 1); 123 OutputReport(thr, rep); 124 125 SyncVar *s = ctx->metamap.GetSyncIfExists(addr); 126 if (s != 0) { 127 Lock l(&s->mtx); 128 s->Reset(thr->proc()); 129 } 130 } 131 thr->mset.Remove(mid); 132 // Imitate a memory write to catch unlock-destroy races. 133 // Do this outside of sync mutex, because it can report a race which locks 134 // sync mutexes. 135 if (IsAppMem(addr)) 136 MemoryAccess(thr, pc, addr, 1, kAccessWrite | kAccessFree); 137 // s will be destroyed and freed in MetaMap::FreeBlock. 138 } 139 140 void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 141 DPrintf("#%d: MutexPreLock %zx flagz=0x%x\n", thr->tid, addr, flagz); 142 if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { 143 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 144 { 145 ReadLock l(&s->mtx); 146 s->UpdateFlags(flagz); 147 if (s->owner_tid != thr->tid) { 148 Callback cb(thr, pc); 149 ctx->dd->MutexBeforeLock(&cb, &s->dd, true); 150 } 151 } 152 Callback cb(thr, pc); 153 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 154 } 155 } 156 157 void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) { 158 DPrintf("#%d: MutexPostLock %zx flag=0x%x rec=%d\n", 159 thr->tid, addr, flagz, rec); 160 if (flagz & MutexFlagRecursiveLock) 161 CHECK_GT(rec, 0); 162 else 163 rec = 1; 164 if (IsAppMem(addr)) 165 MemoryAccess(thr, pc, addr, 1, kAccessRead | kAccessAtomic); 166 u64 mid = 0; 167 bool pre_lock = false; 168 bool first = false; 169 bool report_double_lock = false; 170 { 171 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 172 Lock l(&s->mtx); 173 s->UpdateFlags(flagz); 174 thr->fast_state.IncrementEpoch(); 175 TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); 176 if (s->owner_tid == kInvalidTid) { 177 CHECK_EQ(s->recursion, 0); 178 s->owner_tid = thr->tid; 179 s->last_lock = thr->fast_state.raw(); 180 } else if (s->owner_tid == thr->tid) { 181 CHECK_GT(s->recursion, 0); 182 } else if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 183 s->SetFlags(MutexFlagBroken); 184 report_double_lock = true; 185 } 186 first = s->recursion == 0; 187 s->recursion += rec; 188 if (first) { 189 AcquireImpl(thr, pc, &s->clock); 190 AcquireImpl(thr, pc, &s->read_clock); 191 } else if (!s->IsFlagSet(MutexFlagWriteReentrant)) { 192 } 193 thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); 194 if (first && common_flags()->detect_deadlocks) { 195 pre_lock = 196 (flagz & MutexFlagDoPreLockOnPostLock) && !(flagz & MutexFlagTryLock); 197 Callback cb(thr, pc); 198 if (pre_lock) 199 ctx->dd->MutexBeforeLock(&cb, &s->dd, true); 200 ctx->dd->MutexAfterLock(&cb, &s->dd, true, flagz & MutexFlagTryLock); 201 } 202 mid = s->GetId(); 203 } 204 if (report_double_lock) 205 ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); 206 if (first && pre_lock && common_flags()->detect_deadlocks) { 207 Callback cb(thr, pc); 208 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 209 } 210 } 211 212 int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 213 DPrintf("#%d: MutexUnlock %zx flagz=0x%x\n", thr->tid, addr, flagz); 214 if (IsAppMem(addr)) 215 MemoryAccess(thr, pc, addr, 1, kAccessRead | kAccessAtomic); 216 u64 mid = 0; 217 bool report_bad_unlock = false; 218 int rec = 0; 219 { 220 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 221 Lock l(&s->mtx); 222 thr->fast_state.IncrementEpoch(); 223 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); 224 if (!SANITIZER_GO && (s->recursion == 0 || s->owner_tid != thr->tid)) { 225 if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 226 s->SetFlags(MutexFlagBroken); 227 report_bad_unlock = true; 228 } 229 } else { 230 rec = (flagz & MutexFlagRecursiveUnlock) ? s->recursion : 1; 231 s->recursion -= rec; 232 if (s->recursion == 0) { 233 s->owner_tid = kInvalidTid; 234 ReleaseStoreImpl(thr, pc, &s->clock); 235 } else { 236 } 237 } 238 thr->mset.Del(s->GetId(), true); 239 if (common_flags()->detect_deadlocks && s->recursion == 0 && 240 !report_bad_unlock) { 241 Callback cb(thr, pc); 242 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); 243 } 244 mid = s->GetId(); 245 } 246 if (report_bad_unlock) 247 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); 248 if (common_flags()->detect_deadlocks && !report_bad_unlock) { 249 Callback cb(thr, pc); 250 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 251 } 252 return rec; 253 } 254 255 void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 256 DPrintf("#%d: MutexPreReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); 257 if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { 258 { 259 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 260 ReadLock l(&s->mtx); 261 s->UpdateFlags(flagz); 262 Callback cb(thr, pc); 263 ctx->dd->MutexBeforeLock(&cb, &s->dd, false); 264 } 265 Callback cb(thr, pc); 266 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 267 } 268 } 269 270 void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 271 DPrintf("#%d: MutexPostReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); 272 if (IsAppMem(addr)) 273 MemoryAccess(thr, pc, addr, 1, kAccessRead | kAccessAtomic); 274 u64 mid = 0; 275 bool report_bad_lock = false; 276 bool pre_lock = false; 277 { 278 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 279 ReadLock l(&s->mtx); 280 s->UpdateFlags(flagz); 281 thr->fast_state.IncrementEpoch(); 282 TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); 283 if (s->owner_tid != kInvalidTid) { 284 if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 285 s->SetFlags(MutexFlagBroken); 286 report_bad_lock = true; 287 } 288 } 289 AcquireImpl(thr, pc, &s->clock); 290 s->last_lock = thr->fast_state.raw(); 291 thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); 292 if (common_flags()->detect_deadlocks) { 293 pre_lock = 294 (flagz & MutexFlagDoPreLockOnPostLock) && !(flagz & MutexFlagTryLock); 295 Callback cb(thr, pc); 296 if (pre_lock) 297 ctx->dd->MutexBeforeLock(&cb, &s->dd, false); 298 ctx->dd->MutexAfterLock(&cb, &s->dd, false, flagz & MutexFlagTryLock); 299 } 300 mid = s->GetId(); 301 } 302 if (report_bad_lock) 303 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); 304 if (pre_lock && common_flags()->detect_deadlocks) { 305 Callback cb(thr, pc); 306 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 307 } 308 } 309 310 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { 311 DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr); 312 if (IsAppMem(addr)) 313 MemoryAccess(thr, pc, addr, 1, kAccessRead | kAccessAtomic); 314 u64 mid = 0; 315 bool report_bad_unlock = false; 316 { 317 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 318 Lock l(&s->mtx); 319 thr->fast_state.IncrementEpoch(); 320 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); 321 if (s->owner_tid != kInvalidTid) { 322 if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 323 s->SetFlags(MutexFlagBroken); 324 report_bad_unlock = true; 325 } 326 } 327 ReleaseImpl(thr, pc, &s->read_clock); 328 if (common_flags()->detect_deadlocks && s->recursion == 0) { 329 Callback cb(thr, pc); 330 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false); 331 } 332 mid = s->GetId(); 333 } 334 thr->mset.Del(mid, false); 335 if (report_bad_unlock) 336 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid); 337 if (common_flags()->detect_deadlocks) { 338 Callback cb(thr, pc); 339 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 340 } 341 } 342 343 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { 344 DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); 345 if (IsAppMem(addr)) 346 MemoryAccess(thr, pc, addr, 1, kAccessRead | kAccessAtomic); 347 u64 mid = 0; 348 bool report_bad_unlock = false; 349 { 350 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 351 Lock l(&s->mtx); 352 bool write = true; 353 if (s->owner_tid == kInvalidTid) { 354 // Seems to be read unlock. 355 write = false; 356 thr->fast_state.IncrementEpoch(); 357 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); 358 ReleaseImpl(thr, pc, &s->read_clock); 359 } else if (s->owner_tid == thr->tid) { 360 // Seems to be write unlock. 361 thr->fast_state.IncrementEpoch(); 362 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); 363 CHECK_GT(s->recursion, 0); 364 s->recursion--; 365 if (s->recursion == 0) { 366 s->owner_tid = kInvalidTid; 367 ReleaseStoreImpl(thr, pc, &s->clock); 368 } else { 369 } 370 } else if (!s->IsFlagSet(MutexFlagBroken)) { 371 s->SetFlags(MutexFlagBroken); 372 report_bad_unlock = true; 373 } 374 thr->mset.Del(s->GetId(), write); 375 if (common_flags()->detect_deadlocks && s->recursion == 0) { 376 Callback cb(thr, pc); 377 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write); 378 } 379 mid = s->GetId(); 380 } 381 if (report_bad_unlock) 382 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); 383 if (common_flags()->detect_deadlocks) { 384 Callback cb(thr, pc); 385 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 386 } 387 } 388 389 void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { 390 DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); 391 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 392 Lock l(&s->mtx); 393 s->owner_tid = kInvalidTid; 394 s->recursion = 0; 395 } 396 397 void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr) { 398 DPrintf("#%d: MutexInvalidAccess %zx\n", thr->tid, addr); 399 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, true); 400 ReportMutexMisuse(thr, pc, ReportTypeMutexInvalidAccess, addr, s->GetId()); 401 } 402 403 void Acquire(ThreadState *thr, uptr pc, uptr addr) { 404 DPrintf("#%d: Acquire %zx\n", thr->tid, addr); 405 if (thr->ignore_sync) 406 return; 407 SyncVar *s = ctx->metamap.GetSyncIfExists(addr); 408 if (!s) 409 return; 410 ReadLock l(&s->mtx); 411 AcquireImpl(thr, pc, &s->clock); 412 } 413 414 static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) { 415 ThreadState *thr = reinterpret_cast<ThreadState*>(arg); 416 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 417 u64 epoch = tctx->epoch1; 418 if (tctx->status == ThreadStatusRunning) { 419 epoch = tctx->thr->fast_state.epoch(); 420 tctx->thr->clock.NoteGlobalAcquire(epoch); 421 } 422 thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); 423 } 424 425 void AcquireGlobal(ThreadState *thr) { 426 DPrintf("#%d: AcquireGlobal\n", thr->tid); 427 if (thr->ignore_sync) 428 return; 429 ThreadRegistryLock l(&ctx->thread_registry); 430 ctx->thread_registry.RunCallbackForEachThreadLocked(UpdateClockCallback, thr); 431 } 432 433 void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) { 434 DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr); 435 if (thr->ignore_sync) 436 return; 437 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, false); 438 Lock l(&s->mtx); 439 thr->fast_state.IncrementEpoch(); 440 // Can't increment epoch w/o writing to the trace as well. 441 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 442 ReleaseStoreAcquireImpl(thr, pc, &s->clock); 443 } 444 445 void Release(ThreadState *thr, uptr pc, uptr addr) { 446 DPrintf("#%d: Release %zx\n", thr->tid, addr); 447 if (thr->ignore_sync) 448 return; 449 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, false); 450 Lock l(&s->mtx); 451 thr->fast_state.IncrementEpoch(); 452 // Can't increment epoch w/o writing to the trace as well. 453 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 454 ReleaseImpl(thr, pc, &s->clock); 455 } 456 457 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { 458 DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); 459 if (thr->ignore_sync) 460 return; 461 SyncVar *s = ctx->metamap.GetSyncOrCreate(thr, pc, addr, false); 462 Lock l(&s->mtx); 463 thr->fast_state.IncrementEpoch(); 464 // Can't increment epoch w/o writing to the trace as well. 465 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 466 ReleaseStoreImpl(thr, pc, &s->clock); 467 } 468 469 #if !SANITIZER_GO 470 static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) { 471 ThreadState *thr = reinterpret_cast<ThreadState*>(arg); 472 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 473 u64 epoch = tctx->epoch1; 474 if (tctx->status == ThreadStatusRunning) 475 epoch = tctx->thr->fast_state.epoch(); 476 thr->last_sleep_clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); 477 } 478 479 void AfterSleep(ThreadState *thr, uptr pc) { 480 DPrintf("#%d: AfterSleep\n", thr->tid); 481 if (thr->ignore_sync) 482 return; 483 thr->last_sleep_stack_id = CurrentStackId(thr, pc); 484 ThreadRegistryLock l(&ctx->thread_registry); 485 ctx->thread_registry.RunCallbackForEachThreadLocked(UpdateSleepClockCallback, 486 thr); 487 } 488 #endif 489 490 void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { 491 if (thr->ignore_sync) 492 return; 493 thr->clock.set(thr->fast_state.epoch()); 494 thr->clock.acquire(&thr->proc()->clock_cache, c); 495 } 496 497 void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { 498 if (thr->ignore_sync) 499 return; 500 thr->clock.set(thr->fast_state.epoch()); 501 thr->fast_synch_epoch = thr->fast_state.epoch(); 502 thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c); 503 } 504 505 void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { 506 if (thr->ignore_sync) 507 return; 508 thr->clock.set(thr->fast_state.epoch()); 509 thr->fast_synch_epoch = thr->fast_state.epoch(); 510 thr->clock.release(&thr->proc()->clock_cache, c); 511 } 512 513 void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { 514 if (thr->ignore_sync) 515 return; 516 thr->clock.set(thr->fast_state.epoch()); 517 thr->fast_synch_epoch = thr->fast_state.epoch(); 518 thr->clock.ReleaseStore(&thr->proc()->clock_cache, c); 519 } 520 521 void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { 522 if (thr->ignore_sync) 523 return; 524 thr->clock.set(thr->fast_state.epoch()); 525 thr->fast_synch_epoch = thr->fast_state.epoch(); 526 thr->clock.acq_rel(&thr->proc()->clock_cache, c); 527 } 528 529 void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { 530 if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock)) 531 return; 532 ThreadRegistryLock l(&ctx->thread_registry); 533 ScopedReport rep(ReportTypeDeadlock); 534 for (int i = 0; i < r->n; i++) { 535 rep.AddMutex(r->loop[i].mtx_ctx0); 536 rep.AddUniqueTid((int)r->loop[i].thr_ctx); 537 rep.AddThread((int)r->loop[i].thr_ctx); 538 } 539 uptr dummy_pc = 0x42; 540 for (int i = 0; i < r->n; i++) { 541 for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { 542 u32 stk = r->loop[i].stk[j]; 543 if (stk && stk != 0xffffffff) { 544 rep.AddStack(StackDepotGet(stk), true); 545 } else { 546 // Sometimes we fail to extract the stack trace (FIXME: investigate), 547 // but we should still produce some stack trace in the report. 548 rep.AddStack(StackTrace(&dummy_pc, 1), true); 549 } 550 } 551 } 552 OutputReport(thr, rep); 553 } 554 555 } // namespace __tsan 556