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 u64 id;
29 u64 epoch;
30 u32 seq;
31 u32 count;
32 bool write;
33
DescDesc34 Desc() { internal_memset(this, 0, sizeof(*this)); }
DescDesc35 Desc(const Desc& other) { *this = other; }
36 Desc& operator=(const MutexSet::Desc& other) {
37 internal_memcpy(this, &other, sizeof(*this));
38 return *this;
39 }
40 };
41
42 MutexSet();
43 // The 'id' is obtained from SyncVar::GetId().
44 void Add(u64 id, bool write, u64 epoch);
45 void Del(u64 id, bool write);
46 void Remove(u64 id); // Removes the mutex completely (if it's destroyed).
47 void AddAddr(uptr addr, StackID stack_id, bool write);
48 void DelAddr(uptr addr, bool destroy = false);
49 uptr Size() const;
50 Desc Get(uptr i) const;
51
52 private:
53 #if !SANITIZER_GO
54 u32 seq_ = 0;
55 uptr size_ = 0;
56 Desc descs_[kMaxSize];
57
58 void RemovePos(uptr i);
59 #endif
60 };
61
62 // MutexSet is too large to live on stack.
63 // DynamicMutexSet can be use used to create local MutexSet's.
64 class DynamicMutexSet {
65 public:
66 DynamicMutexSet();
67 ~DynamicMutexSet();
68 MutexSet* operator->() { return ptr_; }
69 operator MutexSet*() { return ptr_; }
70 DynamicMutexSet(const DynamicMutexSet&) = delete;
71 DynamicMutexSet& operator=(const DynamicMutexSet&) = delete;
72
73 private:
74 MutexSet* ptr_;
75 #if SANITIZER_GO
76 MutexSet set_;
77 #endif
78 };
79
80 // Go does not have mutexes, so do not spend memory and time.
81 // (Go sync.Mutex is actually a semaphore -- can be unlocked
82 // in different goroutine).
83 #if SANITIZER_GO
MutexSet()84 MutexSet::MutexSet() {}
Add(u64 id,bool write,u64 epoch)85 void MutexSet::Add(u64 id, bool write, u64 epoch) {}
Del(u64 id,bool write)86 void MutexSet::Del(u64 id, bool write) {}
Remove(u64 id)87 void MutexSet::Remove(u64 id) {}
AddAddr(uptr addr,StackID stack_id,bool write)88 void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {}
DelAddr(uptr addr,bool destroy)89 void MutexSet::DelAddr(uptr addr, bool destroy) {}
Size()90 uptr MutexSet::Size() const { return 0; }
Get(uptr i)91 MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
DynamicMutexSet()92 DynamicMutexSet::DynamicMutexSet() : ptr_(&set_) {}
~DynamicMutexSet()93 DynamicMutexSet::~DynamicMutexSet() {}
94 #endif
95
96 } // namespace __tsan
97
98 #endif // TSAN_MUTEXSET_H
99