xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_mutexset.h (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
10b57cec5SDimitry Andric //===-- tsan_mutexset.h -----------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // MutexSet holds the set of mutexes currently held by a thread.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric #ifndef TSAN_MUTEXSET_H
140b57cec5SDimitry Andric #define TSAN_MUTEXSET_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "tsan_defs.h"
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric namespace __tsan {
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric class MutexSet {
210b57cec5SDimitry Andric  public:
220b57cec5SDimitry Andric   // Holds limited number of mutexes.
230b57cec5SDimitry Andric   // The oldest mutexes are discarded on overflow.
24349cc55cSDimitry Andric   static constexpr uptr kMaxSize = 16;
250b57cec5SDimitry Andric   struct Desc {
26349cc55cSDimitry Andric     uptr addr;
27349cc55cSDimitry Andric     StackID stack_id;
28349cc55cSDimitry Andric     u32 seq;
29349cc55cSDimitry Andric     u32 count;
300b57cec5SDimitry Andric     bool write;
31349cc55cSDimitry Andric 
DescDesc32349cc55cSDimitry Andric     Desc() { internal_memset(this, 0, sizeof(*this)); }
DescDesc33349cc55cSDimitry Andric     Desc(const Desc& other) { *this = other; }
34349cc55cSDimitry Andric     Desc& operator=(const MutexSet::Desc& other) {
35349cc55cSDimitry Andric       internal_memcpy(this, &other, sizeof(*this));
36349cc55cSDimitry Andric       return *this;
37349cc55cSDimitry Andric     }
380b57cec5SDimitry Andric   };
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   MutexSet();
41*0eae32dcSDimitry Andric   void Reset();
42349cc55cSDimitry Andric   void AddAddr(uptr addr, StackID stack_id, bool write);
43349cc55cSDimitry Andric   void DelAddr(uptr addr, bool destroy = false);
440b57cec5SDimitry Andric   uptr Size() const;
450b57cec5SDimitry Andric   Desc Get(uptr i) const;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric  private:
480b57cec5SDimitry Andric #if !SANITIZER_GO
49349cc55cSDimitry Andric   u32 seq_ = 0;
50349cc55cSDimitry Andric   uptr size_ = 0;
510b57cec5SDimitry Andric   Desc descs_[kMaxSize];
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   void RemovePos(uptr i);
54349cc55cSDimitry Andric #endif
55349cc55cSDimitry Andric };
56349cc55cSDimitry Andric 
57349cc55cSDimitry Andric // MutexSet is too large to live on stack.
58349cc55cSDimitry Andric // DynamicMutexSet can be use used to create local MutexSet's.
59349cc55cSDimitry Andric class DynamicMutexSet {
60349cc55cSDimitry Andric  public:
61349cc55cSDimitry Andric   DynamicMutexSet();
62349cc55cSDimitry Andric   ~DynamicMutexSet();
63349cc55cSDimitry Andric   MutexSet* operator->() { return ptr_; }
64349cc55cSDimitry Andric   operator MutexSet*() { return ptr_; }
65349cc55cSDimitry Andric   DynamicMutexSet(const DynamicMutexSet&) = delete;
66349cc55cSDimitry Andric   DynamicMutexSet& operator=(const DynamicMutexSet&) = delete;
67349cc55cSDimitry Andric 
68349cc55cSDimitry Andric  private:
69349cc55cSDimitry Andric   MutexSet* ptr_;
70349cc55cSDimitry Andric #if SANITIZER_GO
71349cc55cSDimitry Andric   MutexSet set_;
72349cc55cSDimitry Andric #endif
730b57cec5SDimitry Andric };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric // Go does not have mutexes, so do not spend memory and time.
760b57cec5SDimitry Andric // (Go sync.Mutex is actually a semaphore -- can be unlocked
770b57cec5SDimitry Andric // in different goroutine).
780b57cec5SDimitry Andric #if SANITIZER_GO
MutexSet()790b57cec5SDimitry Andric MutexSet::MutexSet() {}
Reset()80*0eae32dcSDimitry Andric void MutexSet::Reset() {}
AddAddr(uptr addr,StackID stack_id,bool write)81349cc55cSDimitry Andric void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {}
DelAddr(uptr addr,bool destroy)82349cc55cSDimitry Andric void MutexSet::DelAddr(uptr addr, bool destroy) {}
Size()830b57cec5SDimitry Andric uptr MutexSet::Size() const { return 0; }
Get(uptr i)840b57cec5SDimitry Andric MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
DynamicMutexSet()85349cc55cSDimitry Andric DynamicMutexSet::DynamicMutexSet() : ptr_(&set_) {}
~DynamicMutexSet()86349cc55cSDimitry Andric DynamicMutexSet::~DynamicMutexSet() {}
870b57cec5SDimitry Andric #endif
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric }  // namespace __tsan
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric #endif  // TSAN_MUTEXSET_H
92