1 //===-- tsan_mutexset.h -----------------------------------------*- C++ -*-===//
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 // MutexSet holds the set of mutexes currently held by a thread.
12 //===----------------------------------------------------------------------===//
13 #ifndef TSAN_MUTEXSET_H
14 #define TSAN_MUTEXSET_H
15 
16 #include "tsan_defs.h"
17 
18 namespace __tsan {
19 
20 class MutexSet {
21  public:
22   // Holds limited number of mutexes.
23   // The oldest mutexes are discarded on overflow.
24   static constexpr uptr kMaxSize = 16;
25   struct Desc {
26     uptr addr;
27     StackID stack_id;
28     u32 seq;
29     u32 count;
30     bool write;
31 
32     Desc() { internal_memset(this, 0, sizeof(*this)); }
33     Desc(const Desc& other) { *this = other; }
34     Desc& operator=(const MutexSet::Desc& other) {
35       internal_memcpy(this, &other, sizeof(*this));
36       return *this;
37     }
38   };
39 
40   MutexSet();
41   void Reset();
42   void AddAddr(uptr addr, StackID stack_id, bool write);
43   void DelAddr(uptr addr, bool destroy = false);
44   uptr Size() const;
45   Desc Get(uptr i) const;
46 
47  private:
48 #if !SANITIZER_GO
49   u32 seq_ = 0;
50   uptr size_ = 0;
51   Desc descs_[kMaxSize];
52 
53   void RemovePos(uptr i);
54 #endif
55 };
56 
57 // MutexSet is too large to live on stack.
58 // DynamicMutexSet can be use used to create local MutexSet's.
59 class DynamicMutexSet {
60  public:
61   DynamicMutexSet();
62   ~DynamicMutexSet();
63   MutexSet* operator->() { return ptr_; }
64   operator MutexSet*() { return ptr_; }
65   DynamicMutexSet(const DynamicMutexSet&) = delete;
66   DynamicMutexSet& operator=(const DynamicMutexSet&) = delete;
67 
68  private:
69   MutexSet* ptr_;
70 #if SANITIZER_GO
71   MutexSet set_;
72 #endif
73 };
74 
75 // Go does not have mutexes, so do not spend memory and time.
76 // (Go sync.Mutex is actually a semaphore -- can be unlocked
77 // in different goroutine).
78 #if SANITIZER_GO
79 MutexSet::MutexSet() {}
80 void MutexSet::Reset() {}
81 void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {}
82 void MutexSet::DelAddr(uptr addr, bool destroy) {}
83 uptr MutexSet::Size() const { return 0; }
84 MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
85 DynamicMutexSet::DynamicMutexSet() : ptr_(&set_) {}
86 DynamicMutexSet::~DynamicMutexSet() {}
87 #endif
88 
89 }  // namespace __tsan
90 
91 #endif  // TSAN_MUTEXSET_H
92