xref: /freebsd/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_mutexset.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
1 //===-- tsan_mutexset.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "tsan_mutexset.h"
13 
14 #include "sanitizer_common/sanitizer_placement_new.h"
15 #include "tsan_rtl.h"
16 
17 namespace __tsan {
18 
19 MutexSet::MutexSet() {
20 }
21 
22 void MutexSet::Add(u64 id, bool write, u64 epoch) {
23   // Look up existing mutex with the same id.
24   for (uptr i = 0; i < size_; i++) {
25     if (descs_[i].id == id) {
26       descs_[i].count++;
27       descs_[i].epoch = epoch;
28       return;
29     }
30   }
31   // On overflow, find the oldest mutex and drop it.
32   if (size_ == kMaxSize) {
33     u64 minepoch = (u64)-1;
34     u64 mini = (u64)-1;
35     for (uptr i = 0; i < size_; i++) {
36       if (descs_[i].epoch < minepoch) {
37         minepoch = descs_[i].epoch;
38         mini = i;
39       }
40     }
41     RemovePos(mini);
42     CHECK_EQ(size_, kMaxSize - 1);
43   }
44   // Add new mutex descriptor.
45   descs_[size_].addr = 0;
46   descs_[size_].stack_id = kInvalidStackID;
47   descs_[size_].id = id;
48   descs_[size_].write = write;
49   descs_[size_].epoch = epoch;
50   descs_[size_].seq = seq_++;
51   descs_[size_].count = 1;
52   size_++;
53 }
54 
55 void MutexSet::Del(u64 id, bool write) {
56   for (uptr i = 0; i < size_; i++) {
57     if (descs_[i].id == id) {
58       if (--descs_[i].count == 0)
59         RemovePos(i);
60       return;
61     }
62   }
63 }
64 
65 void MutexSet::Remove(u64 id) {
66   for (uptr i = 0; i < size_; i++) {
67     if (descs_[i].id == id) {
68       RemovePos(i);
69       return;
70     }
71   }
72 }
73 
74 void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {
75   // Look up existing mutex with the same id.
76   for (uptr i = 0; i < size_; i++) {
77     if (descs_[i].addr == addr) {
78       descs_[i].count++;
79       descs_[i].seq = seq_++;
80       return;
81     }
82   }
83   // On overflow, find the oldest mutex and drop it.
84   if (size_ == kMaxSize) {
85     uptr min = 0;
86     for (uptr i = 0; i < size_; i++) {
87       if (descs_[i].seq < descs_[min].seq)
88         min = i;
89     }
90     RemovePos(min);
91     CHECK_EQ(size_, kMaxSize - 1);
92   }
93   // Add new mutex descriptor.
94   descs_[size_].addr = addr;
95   descs_[size_].stack_id = stack_id;
96   descs_[size_].id = 0;
97   descs_[size_].write = write;
98   descs_[size_].epoch = 0;
99   descs_[size_].seq = seq_++;
100   descs_[size_].count = 1;
101   size_++;
102 }
103 
104 void MutexSet::DelAddr(uptr addr, bool destroy) {
105   for (uptr i = 0; i < size_; i++) {
106     if (descs_[i].addr == addr) {
107       if (destroy || --descs_[i].count == 0)
108         RemovePos(i);
109       return;
110     }
111   }
112 }
113 
114 void MutexSet::RemovePos(uptr i) {
115   CHECK_LT(i, size_);
116   descs_[i] = descs_[size_ - 1];
117   size_--;
118 }
119 
120 uptr MutexSet::Size() const {
121   return size_;
122 }
123 
124 MutexSet::Desc MutexSet::Get(uptr i) const {
125   CHECK_LT(i, size_);
126   return descs_[i];
127 }
128 
129 DynamicMutexSet::DynamicMutexSet() : ptr_(New<MutexSet>()) {}
130 DynamicMutexSet::~DynamicMutexSet() { DestroyAndFree(ptr_); }
131 
132 }  // namespace __tsan
133