168d75effSDimitry Andric //===-- tsan_mutexset.cpp -------------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector. 1068d75effSDimitry Andric // 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric #include "tsan_mutexset.h" 13*349cc55cSDimitry Andric 14*349cc55cSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 1568d75effSDimitry Andric #include "tsan_rtl.h" 1668d75effSDimitry Andric 1768d75effSDimitry Andric namespace __tsan { 1868d75effSDimitry Andric 1968d75effSDimitry Andric MutexSet::MutexSet() { 2068d75effSDimitry Andric } 2168d75effSDimitry Andric 2268d75effSDimitry Andric void MutexSet::Add(u64 id, bool write, u64 epoch) { 2368d75effSDimitry Andric // Look up existing mutex with the same id. 2468d75effSDimitry Andric for (uptr i = 0; i < size_; i++) { 2568d75effSDimitry Andric if (descs_[i].id == id) { 2668d75effSDimitry Andric descs_[i].count++; 2768d75effSDimitry Andric descs_[i].epoch = epoch; 2868d75effSDimitry Andric return; 2968d75effSDimitry Andric } 3068d75effSDimitry Andric } 3168d75effSDimitry Andric // On overflow, find the oldest mutex and drop it. 3268d75effSDimitry Andric if (size_ == kMaxSize) { 3368d75effSDimitry Andric u64 minepoch = (u64)-1; 3468d75effSDimitry Andric u64 mini = (u64)-1; 3568d75effSDimitry Andric for (uptr i = 0; i < size_; i++) { 3668d75effSDimitry Andric if (descs_[i].epoch < minepoch) { 3768d75effSDimitry Andric minepoch = descs_[i].epoch; 3868d75effSDimitry Andric mini = i; 3968d75effSDimitry Andric } 4068d75effSDimitry Andric } 4168d75effSDimitry Andric RemovePos(mini); 4268d75effSDimitry Andric CHECK_EQ(size_, kMaxSize - 1); 4368d75effSDimitry Andric } 4468d75effSDimitry Andric // Add new mutex descriptor. 45*349cc55cSDimitry Andric descs_[size_].addr = 0; 46*349cc55cSDimitry Andric descs_[size_].stack_id = kInvalidStackID; 4768d75effSDimitry Andric descs_[size_].id = id; 4868d75effSDimitry Andric descs_[size_].write = write; 4968d75effSDimitry Andric descs_[size_].epoch = epoch; 50*349cc55cSDimitry Andric descs_[size_].seq = seq_++; 5168d75effSDimitry Andric descs_[size_].count = 1; 5268d75effSDimitry Andric size_++; 5368d75effSDimitry Andric } 5468d75effSDimitry Andric 5568d75effSDimitry Andric void MutexSet::Del(u64 id, bool write) { 5668d75effSDimitry Andric for (uptr i = 0; i < size_; i++) { 5768d75effSDimitry Andric if (descs_[i].id == id) { 5868d75effSDimitry Andric if (--descs_[i].count == 0) 5968d75effSDimitry Andric RemovePos(i); 6068d75effSDimitry Andric return; 6168d75effSDimitry Andric } 6268d75effSDimitry Andric } 6368d75effSDimitry Andric } 6468d75effSDimitry Andric 6568d75effSDimitry Andric void MutexSet::Remove(u64 id) { 6668d75effSDimitry Andric for (uptr i = 0; i < size_; i++) { 6768d75effSDimitry Andric if (descs_[i].id == id) { 6868d75effSDimitry Andric RemovePos(i); 6968d75effSDimitry Andric return; 7068d75effSDimitry Andric } 7168d75effSDimitry Andric } 7268d75effSDimitry Andric } 7368d75effSDimitry Andric 74*349cc55cSDimitry Andric void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) { 75*349cc55cSDimitry Andric // Look up existing mutex with the same id. 76*349cc55cSDimitry Andric for (uptr i = 0; i < size_; i++) { 77*349cc55cSDimitry Andric if (descs_[i].addr == addr) { 78*349cc55cSDimitry Andric descs_[i].count++; 79*349cc55cSDimitry Andric descs_[i].seq = seq_++; 80*349cc55cSDimitry Andric return; 81*349cc55cSDimitry Andric } 82*349cc55cSDimitry Andric } 83*349cc55cSDimitry Andric // On overflow, find the oldest mutex and drop it. 84*349cc55cSDimitry Andric if (size_ == kMaxSize) { 85*349cc55cSDimitry Andric uptr min = 0; 86*349cc55cSDimitry Andric for (uptr i = 0; i < size_; i++) { 87*349cc55cSDimitry Andric if (descs_[i].seq < descs_[min].seq) 88*349cc55cSDimitry Andric min = i; 89*349cc55cSDimitry Andric } 90*349cc55cSDimitry Andric RemovePos(min); 91*349cc55cSDimitry Andric CHECK_EQ(size_, kMaxSize - 1); 92*349cc55cSDimitry Andric } 93*349cc55cSDimitry Andric // Add new mutex descriptor. 94*349cc55cSDimitry Andric descs_[size_].addr = addr; 95*349cc55cSDimitry Andric descs_[size_].stack_id = stack_id; 96*349cc55cSDimitry Andric descs_[size_].id = 0; 97*349cc55cSDimitry Andric descs_[size_].write = write; 98*349cc55cSDimitry Andric descs_[size_].epoch = 0; 99*349cc55cSDimitry Andric descs_[size_].seq = seq_++; 100*349cc55cSDimitry Andric descs_[size_].count = 1; 101*349cc55cSDimitry Andric size_++; 102*349cc55cSDimitry Andric } 103*349cc55cSDimitry Andric 104*349cc55cSDimitry Andric void MutexSet::DelAddr(uptr addr, bool destroy) { 105*349cc55cSDimitry Andric for (uptr i = 0; i < size_; i++) { 106*349cc55cSDimitry Andric if (descs_[i].addr == addr) { 107*349cc55cSDimitry Andric if (destroy || --descs_[i].count == 0) 108*349cc55cSDimitry Andric RemovePos(i); 109*349cc55cSDimitry Andric return; 110*349cc55cSDimitry Andric } 111*349cc55cSDimitry Andric } 112*349cc55cSDimitry Andric } 113*349cc55cSDimitry Andric 11468d75effSDimitry Andric void MutexSet::RemovePos(uptr i) { 11568d75effSDimitry Andric CHECK_LT(i, size_); 11668d75effSDimitry Andric descs_[i] = descs_[size_ - 1]; 11768d75effSDimitry Andric size_--; 11868d75effSDimitry Andric } 11968d75effSDimitry Andric 12068d75effSDimitry Andric uptr MutexSet::Size() const { 12168d75effSDimitry Andric return size_; 12268d75effSDimitry Andric } 12368d75effSDimitry Andric 12468d75effSDimitry Andric MutexSet::Desc MutexSet::Get(uptr i) const { 12568d75effSDimitry Andric CHECK_LT(i, size_); 12668d75effSDimitry Andric return descs_[i]; 12768d75effSDimitry Andric } 12868d75effSDimitry Andric 129*349cc55cSDimitry Andric DynamicMutexSet::DynamicMutexSet() : ptr_(New<MutexSet>()) {} 130*349cc55cSDimitry Andric DynamicMutexSet::~DynamicMutexSet() { DestroyAndFree(ptr_); } 131*349cc55cSDimitry Andric 13268d75effSDimitry Andric } // namespace __tsan 133