diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutexset.h b/compiler-rt/lib/tsan/rtl/tsan_mutexset.h --- a/compiler-rt/lib/tsan/rtl/tsan_mutexset.h +++ b/compiler-rt/lib/tsan/rtl/tsan_mutexset.h @@ -23,9 +23,12 @@ // 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 @@ 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 @@ 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 diff --git a/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp b/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp @@ -17,7 +17,6 @@ const uptr MutexSet::kMaxSize; MutexSet::MutexSet() { - size_ = 0; internal_memset(&descs_, 0, sizeof(descs_)); } @@ -44,9 +43,12 @@ 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::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];