| //===-- tsan_mutexset.h -----------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file is a part of ThreadSanitizer (TSan), a race detector. |
| // |
| // MutexSet holds the set of mutexes currently held by a thread. |
| //===----------------------------------------------------------------------===// |
| #ifndef TSAN_MUTEXSET_H |
| #define TSAN_MUTEXSET_H |
| |
| #include "tsan_defs.h" |
| |
| namespace __tsan { |
| |
| class MutexSet { |
| public: |
| // Holds limited number of mutexes. |
| // The oldest mutexes are discarded on overflow. |
| static constexpr uptr kMaxSize = 16; |
| struct Desc { |
| uptr addr; |
| StackID stack_id; |
| u64 id; |
| u64 epoch; |
| u32 seq; |
| u32 count; |
| bool write; |
| |
| Desc() { internal_memset(this, 0, sizeof(*this)); } |
| Desc(const Desc& other) { *this = other; } |
| Desc& operator=(const MutexSet::Desc& other) { |
| internal_memcpy(this, &other, sizeof(*this)); |
| return *this; |
| } |
| }; |
| |
| MutexSet(); |
| // The 'id' is obtained from SyncVar::GetId(). |
| void Add(u64 id, bool write, u64 epoch); |
| void Del(u64 id, bool write); |
| void Remove(u64 id); // Removes the mutex completely (if it's destroyed). |
| void AddAddr(uptr addr, StackID stack_id, bool write); |
| void DelAddr(uptr addr, bool destroy = false); |
| uptr Size() const; |
| Desc Get(uptr i) const; |
| |
| private: |
| #if !SANITIZER_GO |
| u32 seq_ = 0; |
| uptr size_ = 0; |
| Desc descs_[kMaxSize]; |
| |
| void RemovePos(uptr i); |
| #endif |
| }; |
| |
| // MutexSet is too large to live on stack. |
| // DynamicMutexSet can be use used to create local MutexSet's. |
| class DynamicMutexSet { |
| public: |
| DynamicMutexSet(); |
| ~DynamicMutexSet(); |
| MutexSet* operator->() { return ptr_; } |
| operator MutexSet*() { return ptr_; } |
| DynamicMutexSet(const DynamicMutexSet&) = delete; |
| DynamicMutexSet& operator=(const DynamicMutexSet&) = delete; |
| |
| private: |
| MutexSet* ptr_; |
| #if SANITIZER_GO |
| MutexSet set_; |
| #endif |
| }; |
| |
| // Go does not have mutexes, so do not spend memory and time. |
| // (Go sync.Mutex is actually a semaphore -- can be unlocked |
| // in different goroutine). |
| #if SANITIZER_GO |
| MutexSet::MutexSet() {} |
| void MutexSet::Add(u64 id, bool write, u64 epoch) {} |
| void MutexSet::Del(u64 id, bool write) {} |
| void MutexSet::Remove(u64 id) {} |
| void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {} |
| void MutexSet::DelAddr(uptr addr, bool destroy) {} |
| uptr MutexSet::Size() const { return 0; } |
| MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); } |
| DynamicMutexSet::DynamicMutexSet() : ptr_(&set_) {} |
| DynamicMutexSet::~DynamicMutexSet() {} |
| #endif |
| |
| } // namespace __tsan |
| |
| #endif // TSAN_MUTEXSET_H |