//===-- tsan_mutexset.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file is a part of ThreadSanitizer (TSan), a race detector. // //===----------------------------------------------------------------------===// #include "tsan_mutexset.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "tsan_rtl.h" namespace __tsan { MutexSet::MutexSet() { } 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_].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_++; } 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::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]; size_--; } uptr MutexSet::Size() const { return size_; } MutexSet::Desc MutexSet::Get(uptr i) const { CHECK_LT(i, size_); return descs_[i]; } DynamicMutexSet::DynamicMutexSet() : ptr_(New()) {} DynamicMutexSet::~DynamicMutexSet() { DestroyAndFree(ptr_); } } // namespace __tsan