13cab2bb3Spatrick //===-- tsan_mutexset.cpp -------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of ThreadSanitizer (TSan), a race detector.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick #include "tsan_mutexset.h"
13*810390e3Srobert
14*810390e3Srobert #include "sanitizer_common/sanitizer_placement_new.h"
153cab2bb3Spatrick #include "tsan_rtl.h"
163cab2bb3Spatrick
173cab2bb3Spatrick namespace __tsan {
183cab2bb3Spatrick
MutexSet()193cab2bb3Spatrick MutexSet::MutexSet() {
203cab2bb3Spatrick }
213cab2bb3Spatrick
Reset()22*810390e3Srobert void MutexSet::Reset() { internal_memset(this, 0, sizeof(*this)); }
23*810390e3Srobert
AddAddr(uptr addr,StackID stack_id,bool write)24*810390e3Srobert void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {
253cab2bb3Spatrick // Look up existing mutex with the same id.
263cab2bb3Spatrick for (uptr i = 0; i < size_; i++) {
27*810390e3Srobert if (descs_[i].addr == addr) {
283cab2bb3Spatrick descs_[i].count++;
29*810390e3Srobert descs_[i].seq = seq_++;
303cab2bb3Spatrick return;
313cab2bb3Spatrick }
323cab2bb3Spatrick }
333cab2bb3Spatrick // On overflow, find the oldest mutex and drop it.
343cab2bb3Spatrick if (size_ == kMaxSize) {
35*810390e3Srobert uptr min = 0;
363cab2bb3Spatrick for (uptr i = 0; i < size_; i++) {
37*810390e3Srobert if (descs_[i].seq < descs_[min].seq)
38*810390e3Srobert min = i;
393cab2bb3Spatrick }
40*810390e3Srobert RemovePos(min);
413cab2bb3Spatrick CHECK_EQ(size_, kMaxSize - 1);
423cab2bb3Spatrick }
433cab2bb3Spatrick // Add new mutex descriptor.
44*810390e3Srobert descs_[size_].addr = addr;
45*810390e3Srobert descs_[size_].stack_id = stack_id;
463cab2bb3Spatrick descs_[size_].write = write;
47*810390e3Srobert descs_[size_].seq = seq_++;
483cab2bb3Spatrick descs_[size_].count = 1;
493cab2bb3Spatrick size_++;
503cab2bb3Spatrick }
513cab2bb3Spatrick
DelAddr(uptr addr,bool destroy)52*810390e3Srobert void MutexSet::DelAddr(uptr addr, bool destroy) {
533cab2bb3Spatrick for (uptr i = 0; i < size_; i++) {
54*810390e3Srobert if (descs_[i].addr == addr) {
55*810390e3Srobert if (destroy || --descs_[i].count == 0)
563cab2bb3Spatrick RemovePos(i);
573cab2bb3Spatrick return;
583cab2bb3Spatrick }
593cab2bb3Spatrick }
603cab2bb3Spatrick }
613cab2bb3Spatrick
RemovePos(uptr i)623cab2bb3Spatrick void MutexSet::RemovePos(uptr i) {
633cab2bb3Spatrick CHECK_LT(i, size_);
643cab2bb3Spatrick descs_[i] = descs_[size_ - 1];
653cab2bb3Spatrick size_--;
663cab2bb3Spatrick }
673cab2bb3Spatrick
Size() const683cab2bb3Spatrick uptr MutexSet::Size() const {
693cab2bb3Spatrick return size_;
703cab2bb3Spatrick }
713cab2bb3Spatrick
Get(uptr i) const723cab2bb3Spatrick MutexSet::Desc MutexSet::Get(uptr i) const {
733cab2bb3Spatrick CHECK_LT(i, size_);
743cab2bb3Spatrick return descs_[i];
753cab2bb3Spatrick }
763cab2bb3Spatrick
DynamicMutexSet()77*810390e3Srobert DynamicMutexSet::DynamicMutexSet() : ptr_(New<MutexSet>()) {}
~DynamicMutexSet()78*810390e3Srobert DynamicMutexSet::~DynamicMutexSet() { DestroyAndFree(ptr_); }
79*810390e3Srobert
803cab2bb3Spatrick } // namespace __tsan
81