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::Reset() { internal_memset(this, 0, sizeof(*this)); }
23 
24 void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {
25   // Look up existing mutex with the same id.
26   for (uptr i = 0; i < size_; i++) {
27     if (descs_[i].addr == addr) {
28       descs_[i].count++;
29       descs_[i].seq = seq_++;
30       return;
31     }
32   }
33   // On overflow, find the oldest mutex and drop it.
34   if (size_ == kMaxSize) {
35     uptr min = 0;
36     for (uptr i = 0; i < size_; i++) {
37       if (descs_[i].seq < descs_[min].seq)
38         min = i;
39     }
40     RemovePos(min);
41     CHECK_EQ(size_, kMaxSize - 1);
42   }
43   // Add new mutex descriptor.
44   descs_[size_].addr = addr;
45   descs_[size_].stack_id = stack_id;
46   descs_[size_].write = write;
47   descs_[size_].seq = seq_++;
48   descs_[size_].count = 1;
49   size_++;
50 }
51 
52 void MutexSet::DelAddr(uptr addr, bool destroy) {
53   for (uptr i = 0; i < size_; i++) {
54     if (descs_[i].addr == addr) {
55       if (destroy || --descs_[i].count == 0)
56         RemovePos(i);
57       return;
58     }
59   }
60 }
61 
62 void MutexSet::RemovePos(uptr i) {
63   CHECK_LT(i, size_);
64   descs_[i] = descs_[size_ - 1];
65   size_--;
66 }
67 
68 uptr MutexSet::Size() const {
69   return size_;
70 }
71 
72 MutexSet::Desc MutexSet::Get(uptr i) const {
73   CHECK_LT(i, size_);
74   return descs_[i];
75 }
76 
77 DynamicMutexSet::DynamicMutexSet() : ptr_(New<MutexSet>()) {}
78 DynamicMutexSet::~DynamicMutexSet() { DestroyAndFree(ptr_); }
79 
80 }  // namespace __tsan
81