From d9afba9000a73ea4b800cb748114c821a2ca0394 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 10 Aug 2021 20:19:58 +0200 Subject: [PATCH] tsan: extend MutexSet to memorize mutex address/stack_id We currently memorize u64 id + epoch for each mutex. The new tsan runtime will memorize address + stack_id instead. But switching to address + stack_id requires new trace, which in turn requires new MutexSet and some other changes. Extend MutexSet to support both new and old info to break the dependency cycles. The plan is to remove the old info/methods after switching to the new runtime. Reviewed By: vitalybuka, melver Differential Revision: https://reviews.llvm.org/D107910 --- compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp | 44 +++++++++++++++++++++++++++++- compiler-rt/lib/tsan/rtl/tsan_mutexset.h | 17 ++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp b/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp index 813fa3b..d76febf 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp @@ -17,7 +17,6 @@ namespace __tsan { const uptr MutexSet::kMaxSize; MutexSet::MutexSet() { - size_ = 0; internal_memset(&descs_, 0, sizeof(descs_)); } @@ -44,9 +43,12 @@ void MutexSet::Add(u64 id, bool write, u64 epoch) { CHECK_EQ(size_, kMaxSize - 1); } // Add new mutex descriptor. + descs_[size_].addr = 0; + descs_[size_].stack_id = kInvalidStackID; descs_[size_].id = id; descs_[size_].write = write; descs_[size_].epoch = epoch; + descs_[size_].seq = seq_++; descs_[size_].count = 1; size_++; } @@ -70,6 +72,46 @@ void MutexSet::Remove(u64 id) { } } +void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) { + // Look up existing mutex with the same id. + for (uptr i = 0; i < size_; i++) { + if (descs_[i].addr == addr) { + descs_[i].count++; + descs_[i].seq = seq_++; + return; + } + } + // On overflow, find the oldest mutex and drop it. + if (size_ == kMaxSize) { + uptr min = 0; + for (uptr i = 0; i < size_; i++) { + if (descs_[i].seq < descs_[min].seq) + min = i; + } + RemovePos(min); + CHECK_EQ(size_, kMaxSize - 1); + } + // Add new mutex descriptor. + descs_[size_].addr = addr; + descs_[size_].stack_id = stack_id; + descs_[size_].id = 0; + descs_[size_].write = write; + descs_[size_].epoch = 0; + descs_[size_].seq = seq_++; + descs_[size_].count = 1; + size_++; +} + +void MutexSet::DelAddr(uptr addr, bool destroy) { + for (uptr i = 0; i < size_; i++) { + if (descs_[i].addr == addr) { + if (destroy || --descs_[i].count == 0) + RemovePos(i); + return; + } + } +} + void MutexSet::RemovePos(uptr i) { CHECK_LT(i, size_); descs_[i] = descs_[size_ - 1]; diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutexset.h b/compiler-rt/lib/tsan/rtl/tsan_mutexset.h index d63881f..606106f 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_mutexset.h +++ b/compiler-rt/lib/tsan/rtl/tsan_mutexset.h @@ -23,9 +23,12 @@ class MutexSet { // The oldest mutexes are discarded on overflow. static const uptr kMaxSize = 16; struct Desc { + uptr addr; + StackID stack_id; u64 id; u64 epoch; - int count; + u32 seq; + u32 count; bool write; }; @@ -34,21 +37,24 @@ class MutexSet { void Add(u64 id, bool write, u64 epoch); void Del(u64 id, bool write); void Remove(u64 id); // Removes the mutex completely (if it's destroyed). + void AddAddr(uptr addr, StackID stack_id, bool write); + void DelAddr(uptr addr, bool destroy = false); uptr Size() const; Desc Get(uptr i) const; + MutexSet(const MutexSet& other) { *this = other; } void operator=(const MutexSet &other) { internal_memcpy(this, &other, sizeof(*this)); } private: #if !SANITIZER_GO - uptr size_; + u32 seq_ = 0; + uptr size_ = 0; Desc descs_[kMaxSize]; -#endif void RemovePos(uptr i); - MutexSet(const MutexSet&); +#endif }; // Go does not have mutexes, so do not spend memory and time. @@ -59,7 +65,8 @@ MutexSet::MutexSet() {} void MutexSet::Add(u64 id, bool write, u64 epoch) {} void MutexSet::Del(u64 id, bool write) {} void MutexSet::Remove(u64 id) {} -void MutexSet::RemovePos(uptr i) {} +void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {} +void MutexSet::DelAddr(uptr addr, bool destroy) {} uptr MutexSet::Size() const { return 0; } MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); } #endif -- 2.7.4