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