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 + u32 seq_; uptr size_; 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,6 +17,7 @@ const uptr MutexSet::kMaxSize; MutexSet::MutexSet() { + seq_ = 0; size_ = 0; internal_memset(&descs_, 0, sizeof(descs_)); } @@ -44,9 +45,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 +74,49 @@ } } +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) { + u32 min_seq = (u32)-1; + uptr min_index = (uptr)-1; + for (uptr i = 0; i < size_; i++) { + if (descs_[i].seq < min_seq) { + min_seq = descs_[i].seq; + min_index = i; + } + } + RemovePos(min_index); + 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];