//===-- tsan_mutexset.cc --------------------------------------------------===// // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "tsan_mutexset.h" #include "tsan_rtl.h" namespace __tsan { const uptr MutexSet::kMaxSize; MutexSet::MutexSet() { size_ = 0; internal_memset(&descs_, 0, sizeof(descs_)); } void MutexSet::Add(u64 id, bool write, u64 epoch) { // Look up existing mutex with the same id. for (uptr i = 0; i < size_; i++) { if (descs_[i].id == id) { descs_[i].count++; descs_[i].epoch = epoch; return; } } // On overflow, find the oldest mutex and drop it. if (size_ == kMaxSize) { u64 minepoch = (u64)-1; u64 mini = (u64)-1; for (uptr i = 0; i < size_; i++) { if (descs_[i].epoch < minepoch) { minepoch = descs_[i].epoch; mini = i; } } RemovePos(mini); CHECK_EQ(size_, kMaxSize - 1); } // Add new mutex descriptor. descs_[size_].id = id; descs_[size_].write = write; descs_[size_].epoch = epoch; descs_[size_].count = 1; size_++; } void MutexSet::Del(u64 id, bool write) { for (uptr i = 0; i < size_; i++) { if (descs_[i].id == id) { if (--descs_[i].count == 0) RemovePos(i); return; } } } void MutexSet::Remove(u64 id) { for (uptr i = 0; i < size_; i++) { if (descs_[i].id == id) { RemovePos(i); return; } } } void MutexSet::RemovePos(uptr i) { CHECK_LT(i, size_); descs_[i] = descs_[size_ - 1]; size_--; } uptr MutexSet::Size() const { return size_; } MutexSet::Desc MutexSet::Get(uptr i) const { CHECK_LT(i, size_); return descs_[i]; } } // namespace __tsan