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 u32 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 StatInc(thr, StatMutexCreate); 69 if (!(flagz & MutexFlagLinkerInit) && IsAppMem(addr)) { 70 CHECK(!thr->is_freeing); 71 thr->is_freeing = true; 72 MemoryWrite(thr, pc, addr, kSizeLog1); 73 thr->is_freeing = false; 74 } 75 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 76 s->SetFlags(flagz & MutexCreationFlagMask); 77 if (!SANITIZER_GO && s->creation_stack_id == 0) 78 s->creation_stack_id = CurrentStackId(thr, pc); 79 s->mtx.Unlock(); 80 } 81 82 void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 83 DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); 84 StatInc(thr, StatMutexDestroy); 85 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); 86 if (s == 0) 87 return; 88 if ((flagz & MutexFlagLinkerInit) 89 || s->IsFlagSet(MutexFlagLinkerInit) 90 || ((flagz & MutexFlagNotStatic) && !s->IsFlagSet(MutexFlagNotStatic))) { 91 // Destroy is no-op for linker-initialized mutexes. 92 s->mtx.Unlock(); 93 return; 94 } 95 if (common_flags()->detect_deadlocks) { 96 Callback cb(thr, pc); 97 ctx->dd->MutexDestroy(&cb, &s->dd); 98 ctx->dd->MutexInit(&cb, &s->dd); 99 } 100 bool unlock_locked = false; 101 if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid && 102 !s->IsFlagSet(MutexFlagBroken)) { 103 s->SetFlags(MutexFlagBroken); 104 unlock_locked = true; 105 } 106 u64 mid = s->GetId(); 107 u64 last_lock = s->last_lock; 108 if (!unlock_locked) 109 s->Reset(thr->proc()); // must not reset it before the report is printed 110 s->mtx.Unlock(); 111 if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) { 112 ThreadRegistryLock l(ctx->thread_registry); 113 ScopedReport rep(ReportTypeMutexDestroyLocked); 114 rep.AddMutex(mid); 115 VarSizeStackTrace trace; 116 ObtainCurrentStack(thr, pc, &trace); 117 rep.AddStack(trace, true); 118 FastState last(last_lock); 119 RestoreStack(last.tid(), last.epoch(), &trace, 0); 120 rep.AddStack(trace, true); 121 rep.AddLocation(addr, 1); 122 OutputReport(thr, rep); 123 124 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); 125 if (s != 0) { 126 s->Reset(thr->proc()); 127 s->mtx.Unlock(); 128 } 129 } 130 thr->mset.Remove(mid); 131 // Imitate a memory write to catch unlock-destroy races. 132 // Do this outside of sync mutex, because it can report a race which locks 133 // sync mutexes. 134 if (IsAppMem(addr)) { 135 CHECK(!thr->is_freeing); 136 thr->is_freeing = true; 137 MemoryWrite(thr, pc, addr, kSizeLog1); 138 thr->is_freeing = false; 139 } 140 // s will be destroyed and freed in MetaMap::FreeBlock. 141 } 142 143 void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 144 DPrintf("#%d: MutexPreLock %zx flagz=0x%x\n", thr->tid, addr, flagz); 145 if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { 146 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); 147 s->UpdateFlags(flagz); 148 if (s->owner_tid != thr->tid) { 149 Callback cb(thr, pc); 150 ctx->dd->MutexBeforeLock(&cb, &s->dd, true); 151 s->mtx.ReadUnlock(); 152 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 153 } else { 154 s->mtx.ReadUnlock(); 155 } 156 } 157 } 158 159 void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) { 160 DPrintf("#%d: MutexPostLock %zx flag=0x%x rec=%d\n", 161 thr->tid, addr, flagz, rec); 162 if (flagz & MutexFlagRecursiveLock) 163 CHECK_GT(rec, 0); 164 else 165 rec = 1; 166 if (IsAppMem(addr)) 167 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 168 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 169 s->UpdateFlags(flagz); 170 thr->fast_state.IncrementEpoch(); 171 TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId()); 172 bool report_double_lock = false; 173 if (s->owner_tid == kInvalidTid) { 174 CHECK_EQ(s->recursion, 0); 175 s->owner_tid = thr->tid; 176 s->last_lock = thr->fast_state.raw(); 177 } else if (s->owner_tid == thr->tid) { 178 CHECK_GT(s->recursion, 0); 179 } else if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 180 s->SetFlags(MutexFlagBroken); 181 report_double_lock = true; 182 } 183 const bool first = s->recursion == 0; 184 s->recursion += rec; 185 if (first) { 186 StatInc(thr, StatMutexLock); 187 AcquireImpl(thr, pc, &s->clock); 188 AcquireImpl(thr, pc, &s->read_clock); 189 } else if (!s->IsFlagSet(MutexFlagWriteReentrant)) { 190 StatInc(thr, StatMutexRecLock); 191 } 192 thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); 193 bool pre_lock = false; 194 if (first && common_flags()->detect_deadlocks) { 195 pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) && 196 !(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 u64 mid = s->GetId(); 203 s->mtx.Unlock(); 204 // Can't touch s after this point. 205 s = 0; 206 if (report_double_lock) 207 ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid); 208 if (first && pre_lock && common_flags()->detect_deadlocks) { 209 Callback cb(thr, pc); 210 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 211 } 212 } 213 214 int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 215 DPrintf("#%d: MutexUnlock %zx flagz=0x%x\n", thr->tid, addr, flagz); 216 if (IsAppMem(addr)) 217 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 218 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 219 thr->fast_state.IncrementEpoch(); 220 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); 221 int rec = 0; 222 bool report_bad_unlock = false; 223 if (!SANITIZER_GO && (s->recursion == 0 || s->owner_tid != thr->tid)) { 224 if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 225 s->SetFlags(MutexFlagBroken); 226 report_bad_unlock = true; 227 } 228 } else { 229 rec = (flagz & MutexFlagRecursiveUnlock) ? s->recursion : 1; 230 s->recursion -= rec; 231 if (s->recursion == 0) { 232 StatInc(thr, StatMutexUnlock); 233 s->owner_tid = kInvalidTid; 234 ReleaseStoreImpl(thr, pc, &s->clock); 235 } else { 236 StatInc(thr, StatMutexRecUnlock); 237 } 238 } 239 thr->mset.Del(s->GetId(), true); 240 if (common_flags()->detect_deadlocks && s->recursion == 0 && 241 !report_bad_unlock) { 242 Callback cb(thr, pc); 243 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); 244 } 245 u64 mid = s->GetId(); 246 s->mtx.Unlock(); 247 // Can't touch s after this point. 248 if (report_bad_unlock) 249 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); 250 if (common_flags()->detect_deadlocks && !report_bad_unlock) { 251 Callback cb(thr, pc); 252 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 253 } 254 return rec; 255 } 256 257 void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 258 DPrintf("#%d: MutexPreReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); 259 if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) { 260 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); 261 s->UpdateFlags(flagz); 262 Callback cb(thr, pc); 263 ctx->dd->MutexBeforeLock(&cb, &s->dd, false); 264 s->mtx.ReadUnlock(); 265 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 266 } 267 } 268 269 void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { 270 DPrintf("#%d: MutexPostReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz); 271 StatInc(thr, StatMutexReadLock); 272 if (IsAppMem(addr)) 273 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 274 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false); 275 s->UpdateFlags(flagz); 276 thr->fast_state.IncrementEpoch(); 277 TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId()); 278 bool report_bad_lock = false; 279 if (s->owner_tid != kInvalidTid) { 280 if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 281 s->SetFlags(MutexFlagBroken); 282 report_bad_lock = true; 283 } 284 } 285 AcquireImpl(thr, pc, &s->clock); 286 s->last_lock = thr->fast_state.raw(); 287 thr->mset.Add(s->GetId(), false, thr->fast_state.epoch()); 288 bool pre_lock = false; 289 if (common_flags()->detect_deadlocks) { 290 pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) && 291 !(flagz & MutexFlagTryLock); 292 Callback cb(thr, pc); 293 if (pre_lock) 294 ctx->dd->MutexBeforeLock(&cb, &s->dd, false); 295 ctx->dd->MutexAfterLock(&cb, &s->dd, false, flagz & MutexFlagTryLock); 296 } 297 u64 mid = s->GetId(); 298 s->mtx.ReadUnlock(); 299 // Can't touch s after this point. 300 s = 0; 301 if (report_bad_lock) 302 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid); 303 if (pre_lock && common_flags()->detect_deadlocks) { 304 Callback cb(thr, pc); 305 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 306 } 307 } 308 309 void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { 310 DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr); 311 StatInc(thr, StatMutexReadUnlock); 312 if (IsAppMem(addr)) 313 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 314 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 315 thr->fast_state.IncrementEpoch(); 316 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); 317 bool report_bad_unlock = false; 318 if (s->owner_tid != kInvalidTid) { 319 if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) { 320 s->SetFlags(MutexFlagBroken); 321 report_bad_unlock = true; 322 } 323 } 324 ReleaseImpl(thr, pc, &s->read_clock); 325 if (common_flags()->detect_deadlocks && s->recursion == 0) { 326 Callback cb(thr, pc); 327 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, false); 328 } 329 u64 mid = s->GetId(); 330 s->mtx.Unlock(); 331 // Can't touch s after this point. 332 thr->mset.Del(mid, false); 333 if (report_bad_unlock) 334 ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid); 335 if (common_flags()->detect_deadlocks) { 336 Callback cb(thr, pc); 337 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 338 } 339 } 340 341 void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { 342 DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); 343 if (IsAppMem(addr)) 344 MemoryReadAtomic(thr, pc, addr, kSizeLog1); 345 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 346 bool write = true; 347 bool report_bad_unlock = false; 348 if (s->owner_tid == kInvalidTid) { 349 // Seems to be read unlock. 350 write = false; 351 StatInc(thr, StatMutexReadUnlock); 352 thr->fast_state.IncrementEpoch(); 353 TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId()); 354 ReleaseImpl(thr, pc, &s->read_clock); 355 } else if (s->owner_tid == thr->tid) { 356 // Seems to be write unlock. 357 thr->fast_state.IncrementEpoch(); 358 TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); 359 CHECK_GT(s->recursion, 0); 360 s->recursion--; 361 if (s->recursion == 0) { 362 StatInc(thr, StatMutexUnlock); 363 s->owner_tid = kInvalidTid; 364 ReleaseStoreImpl(thr, pc, &s->clock); 365 } else { 366 StatInc(thr, StatMutexRecUnlock); 367 } 368 } else if (!s->IsFlagSet(MutexFlagBroken)) { 369 s->SetFlags(MutexFlagBroken); 370 report_bad_unlock = true; 371 } 372 thr->mset.Del(s->GetId(), write); 373 if (common_flags()->detect_deadlocks && s->recursion == 0) { 374 Callback cb(thr, pc); 375 ctx->dd->MutexBeforeUnlock(&cb, &s->dd, write); 376 } 377 u64 mid = s->GetId(); 378 s->mtx.Unlock(); 379 // Can't touch s after this point. 380 if (report_bad_unlock) 381 ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid); 382 if (common_flags()->detect_deadlocks) { 383 Callback cb(thr, pc); 384 ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); 385 } 386 } 387 388 void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { 389 DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); 390 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 391 s->owner_tid = kInvalidTid; 392 s->recursion = 0; 393 s->mtx.Unlock(); 394 } 395 396 void MutexInvalidAccess(ThreadState *thr, uptr pc, uptr addr) { 397 DPrintf("#%d: MutexInvalidAccess %zx\n", thr->tid, addr); 398 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 399 u64 mid = s->GetId(); 400 s->mtx.Unlock(); 401 ReportMutexMisuse(thr, pc, ReportTypeMutexInvalidAccess, addr, mid); 402 } 403 404 void Acquire(ThreadState *thr, uptr pc, uptr addr) { 405 DPrintf("#%d: Acquire %zx\n", thr->tid, addr); 406 if (thr->ignore_sync) 407 return; 408 SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, false); 409 if (!s) 410 return; 411 AcquireImpl(thr, pc, &s->clock); 412 s->mtx.ReadUnlock(); 413 } 414 415 static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) { 416 ThreadState *thr = reinterpret_cast<ThreadState*>(arg); 417 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 418 u64 epoch = tctx->epoch1; 419 if (tctx->status == ThreadStatusRunning) { 420 epoch = tctx->thr->fast_state.epoch(); 421 tctx->thr->clock.NoteGlobalAcquire(epoch); 422 } 423 thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); 424 } 425 426 void AcquireGlobal(ThreadState *thr, uptr pc) { 427 DPrintf("#%d: AcquireGlobal\n", thr->tid); 428 if (thr->ignore_sync) 429 return; 430 ThreadRegistryLock l(ctx->thread_registry); 431 ctx->thread_registry->RunCallbackForEachThreadLocked( 432 UpdateClockCallback, thr); 433 } 434 435 void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) { 436 DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr); 437 if (thr->ignore_sync) 438 return; 439 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 440 thr->fast_state.IncrementEpoch(); 441 // Can't increment epoch w/o writing to the trace as well. 442 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 443 ReleaseStoreAcquireImpl(thr, pc, &s->clock); 444 s->mtx.Unlock(); 445 } 446 447 void Release(ThreadState *thr, uptr pc, uptr addr) { 448 DPrintf("#%d: Release %zx\n", thr->tid, addr); 449 if (thr->ignore_sync) 450 return; 451 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 452 thr->fast_state.IncrementEpoch(); 453 // Can't increment epoch w/o writing to the trace as well. 454 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 455 ReleaseImpl(thr, pc, &s->clock); 456 s->mtx.Unlock(); 457 } 458 459 void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { 460 DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); 461 if (thr->ignore_sync) 462 return; 463 SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); 464 thr->fast_state.IncrementEpoch(); 465 // Can't increment epoch w/o writing to the trace as well. 466 TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); 467 ReleaseStoreImpl(thr, pc, &s->clock); 468 s->mtx.Unlock(); 469 } 470 471 #if !SANITIZER_GO 472 static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) { 473 ThreadState *thr = reinterpret_cast<ThreadState*>(arg); 474 ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base); 475 u64 epoch = tctx->epoch1; 476 if (tctx->status == ThreadStatusRunning) 477 epoch = tctx->thr->fast_state.epoch(); 478 thr->last_sleep_clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); 479 } 480 481 void AfterSleep(ThreadState *thr, uptr pc) { 482 DPrintf("#%d: AfterSleep %zx\n", thr->tid); 483 if (thr->ignore_sync) 484 return; 485 thr->last_sleep_stack_id = CurrentStackId(thr, pc); 486 ThreadRegistryLock l(ctx->thread_registry); 487 ctx->thread_registry->RunCallbackForEachThreadLocked( 488 UpdateSleepClockCallback, thr); 489 } 490 #endif 491 492 void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { 493 if (thr->ignore_sync) 494 return; 495 thr->clock.set(thr->fast_state.epoch()); 496 thr->clock.acquire(&thr->proc()->clock_cache, c); 497 StatInc(thr, StatSyncAcquire); 498 } 499 500 void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { 501 if (thr->ignore_sync) 502 return; 503 thr->clock.set(thr->fast_state.epoch()); 504 thr->fast_synch_epoch = thr->fast_state.epoch(); 505 thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c); 506 StatInc(thr, StatSyncReleaseStoreAcquire); 507 } 508 509 void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { 510 if (thr->ignore_sync) 511 return; 512 thr->clock.set(thr->fast_state.epoch()); 513 thr->fast_synch_epoch = thr->fast_state.epoch(); 514 thr->clock.release(&thr->proc()->clock_cache, c); 515 StatInc(thr, StatSyncRelease); 516 } 517 518 void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) { 519 if (thr->ignore_sync) 520 return; 521 thr->clock.set(thr->fast_state.epoch()); 522 thr->fast_synch_epoch = thr->fast_state.epoch(); 523 thr->clock.ReleaseStore(&thr->proc()->clock_cache, c); 524 StatInc(thr, StatSyncRelease); 525 } 526 527 void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { 528 if (thr->ignore_sync) 529 return; 530 thr->clock.set(thr->fast_state.epoch()); 531 thr->fast_synch_epoch = thr->fast_state.epoch(); 532 thr->clock.acq_rel(&thr->proc()->clock_cache, c); 533 StatInc(thr, StatSyncAcquire); 534 StatInc(thr, StatSyncRelease); 535 } 536 537 void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { 538 if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock)) 539 return; 540 ThreadRegistryLock l(ctx->thread_registry); 541 ScopedReport rep(ReportTypeDeadlock); 542 for (int i = 0; i < r->n; i++) { 543 rep.AddMutex(r->loop[i].mtx_ctx0); 544 rep.AddUniqueTid((int)r->loop[i].thr_ctx); 545 rep.AddThread((int)r->loop[i].thr_ctx); 546 } 547 uptr dummy_pc = 0x42; 548 for (int i = 0; i < r->n; i++) { 549 for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) { 550 u32 stk = r->loop[i].stk[j]; 551 if (stk && stk != 0xffffffff) { 552 rep.AddStack(StackDepotGet(stk), true); 553 } else { 554 // Sometimes we fail to extract the stack trace (FIXME: investigate), 555 // but we should still produce some stack trace in the report. 556 rep.AddStack(StackTrace(&dummy_pc, 1), true); 557 } 558 } 559 } 560 OutputReport(thr, rep); 561 } 562 563 } // namespace __tsan 564