xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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