annotate libsanitizer/tsan/tsan_clock.h @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 //===-- tsan_clock.h --------------------------------------------*- C++ -*-===//
kono
parents:
diff changeset
2 //
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 111
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
1830386684a0 gcc-9.2.0
anatofuz
parents: 111
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
1830386684a0 gcc-9.2.0
anatofuz
parents: 111
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
111
kono
parents:
diff changeset
6 //
kono
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
kono
parents:
diff changeset
8 //
kono
parents:
diff changeset
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
kono
parents:
diff changeset
10 //
kono
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
kono
parents:
diff changeset
12 #ifndef TSAN_CLOCK_H
kono
parents:
diff changeset
13 #define TSAN_CLOCK_H
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 #include "tsan_defs.h"
kono
parents:
diff changeset
16 #include "tsan_dense_alloc.h"
kono
parents:
diff changeset
17
kono
parents:
diff changeset
18 namespace __tsan {
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
kono
parents:
diff changeset
21 typedef DenseSlabAllocCache ClockCache;
kono
parents:
diff changeset
22
kono
parents:
diff changeset
23 // The clock that lives in sync variables (mutexes, atomics, etc).
kono
parents:
diff changeset
24 class SyncClock {
kono
parents:
diff changeset
25 public:
kono
parents:
diff changeset
26 SyncClock();
kono
parents:
diff changeset
27 ~SyncClock();
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 uptr size() const;
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 // These are used only in tests.
kono
parents:
diff changeset
32 u64 get(unsigned tid) const;
kono
parents:
diff changeset
33 u64 get_clean(unsigned tid) const;
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 void Resize(ClockCache *c, uptr nclk);
kono
parents:
diff changeset
36 void Reset(ClockCache *c);
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 void DebugDump(int(*printf)(const char *s, ...));
kono
parents:
diff changeset
39
kono
parents:
diff changeset
40 // Clock element iterator.
kono
parents:
diff changeset
41 // Note: it iterates only over the table without regard to dirty entries.
kono
parents:
diff changeset
42 class Iter {
kono
parents:
diff changeset
43 public:
kono
parents:
diff changeset
44 explicit Iter(SyncClock* parent);
kono
parents:
diff changeset
45 Iter& operator++();
kono
parents:
diff changeset
46 bool operator!=(const Iter& other);
kono
parents:
diff changeset
47 ClockElem &operator*();
kono
parents:
diff changeset
48
kono
parents:
diff changeset
49 private:
kono
parents:
diff changeset
50 SyncClock *parent_;
kono
parents:
diff changeset
51 // [pos_, end_) is the current continuous range of clock elements.
kono
parents:
diff changeset
52 ClockElem *pos_;
kono
parents:
diff changeset
53 ClockElem *end_;
kono
parents:
diff changeset
54 int block_; // Current number of second level block.
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 NOINLINE void Next();
kono
parents:
diff changeset
57 };
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 Iter begin();
kono
parents:
diff changeset
60 Iter end();
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 private:
kono
parents:
diff changeset
63 friend class ThreadClock;
kono
parents:
diff changeset
64 friend class Iter;
kono
parents:
diff changeset
65 static const uptr kDirtyTids = 2;
kono
parents:
diff changeset
66
kono
parents:
diff changeset
67 struct Dirty {
kono
parents:
diff changeset
68 u64 epoch : kClkBits;
kono
parents:
diff changeset
69 u64 tid : 64 - kClkBits; // kInvalidId if not active
kono
parents:
diff changeset
70 };
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 unsigned release_store_tid_;
kono
parents:
diff changeset
73 unsigned release_store_reused_;
kono
parents:
diff changeset
74 Dirty dirty_[kDirtyTids];
kono
parents:
diff changeset
75 // If size_ is 0, tab_ is nullptr.
kono
parents:
diff changeset
76 // If size <= 64 (kClockCount), tab_ contains pointer to an array with
kono
parents:
diff changeset
77 // 64 ClockElem's (ClockBlock::clock).
kono
parents:
diff changeset
78 // Otherwise, tab_ points to an array with up to 127 u32 elements,
kono
parents:
diff changeset
79 // each pointing to the second-level 512b block with 64 ClockElem's.
kono
parents:
diff changeset
80 // Unused space in the first level ClockBlock is used to store additional
kono
parents:
diff changeset
81 // clock elements.
kono
parents:
diff changeset
82 // The last u32 element in the first level ClockBlock is always used as
kono
parents:
diff changeset
83 // reference counter.
kono
parents:
diff changeset
84 //
kono
parents:
diff changeset
85 // See the following scheme for details.
kono
parents:
diff changeset
86 // All memory blocks are 512 bytes (allocated from ClockAlloc).
kono
parents:
diff changeset
87 // Clock (clk) elements are 64 bits.
kono
parents:
diff changeset
88 // Idx and ref are 32 bits.
kono
parents:
diff changeset
89 //
kono
parents:
diff changeset
90 // tab_
kono
parents:
diff changeset
91 // |
kono
parents:
diff changeset
92 // \/
kono
parents:
diff changeset
93 // +----------------------------------------------------+
kono
parents:
diff changeset
94 // | clk128 | clk129 | ...unused... | idx1 | idx0 | ref |
kono
parents:
diff changeset
95 // +----------------------------------------------------+
kono
parents:
diff changeset
96 // | |
kono
parents:
diff changeset
97 // | \/
kono
parents:
diff changeset
98 // | +----------------+
kono
parents:
diff changeset
99 // | | clk0 ... clk63 |
kono
parents:
diff changeset
100 // | +----------------+
kono
parents:
diff changeset
101 // \/
kono
parents:
diff changeset
102 // +------------------+
kono
parents:
diff changeset
103 // | clk64 ... clk127 |
kono
parents:
diff changeset
104 // +------------------+
kono
parents:
diff changeset
105 //
kono
parents:
diff changeset
106 // Note: dirty entries, if active, always override what's stored in the clock.
kono
parents:
diff changeset
107 ClockBlock *tab_;
kono
parents:
diff changeset
108 u32 tab_idx_;
kono
parents:
diff changeset
109 u16 size_;
kono
parents:
diff changeset
110 u16 blocks_; // Number of second level blocks.
kono
parents:
diff changeset
111
kono
parents:
diff changeset
112 void Unshare(ClockCache *c);
kono
parents:
diff changeset
113 bool IsShared() const;
kono
parents:
diff changeset
114 bool Cachable() const;
kono
parents:
diff changeset
115 void ResetImpl();
kono
parents:
diff changeset
116 void FlushDirty();
kono
parents:
diff changeset
117 uptr capacity() const;
kono
parents:
diff changeset
118 u32 get_block(uptr bi) const;
kono
parents:
diff changeset
119 void append_block(u32 idx);
kono
parents:
diff changeset
120 ClockElem &elem(unsigned tid) const;
kono
parents:
diff changeset
121 };
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 // The clock that lives in threads.
kono
parents:
diff changeset
124 class ThreadClock {
kono
parents:
diff changeset
125 public:
kono
parents:
diff changeset
126 typedef DenseSlabAllocCache Cache;
kono
parents:
diff changeset
127
kono
parents:
diff changeset
128 explicit ThreadClock(unsigned tid, unsigned reused = 0);
kono
parents:
diff changeset
129
kono
parents:
diff changeset
130 u64 get(unsigned tid) const;
kono
parents:
diff changeset
131 void set(ClockCache *c, unsigned tid, u64 v);
kono
parents:
diff changeset
132 void set(u64 v);
kono
parents:
diff changeset
133 void tick();
kono
parents:
diff changeset
134 uptr size() const;
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 void acquire(ClockCache *c, SyncClock *src);
kono
parents:
diff changeset
137 void release(ClockCache *c, SyncClock *dst);
kono
parents:
diff changeset
138 void acq_rel(ClockCache *c, SyncClock *dst);
kono
parents:
diff changeset
139 void ReleaseStore(ClockCache *c, SyncClock *dst);
kono
parents:
diff changeset
140 void ResetCached(ClockCache *c);
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 void DebugReset();
kono
parents:
diff changeset
143 void DebugDump(int(*printf)(const char *s, ...));
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 private:
kono
parents:
diff changeset
146 static const uptr kDirtyTids = SyncClock::kDirtyTids;
kono
parents:
diff changeset
147 // Index of the thread associated with he clock ("current thread").
kono
parents:
diff changeset
148 const unsigned tid_;
kono
parents:
diff changeset
149 const unsigned reused_; // tid_ reuse count.
kono
parents:
diff changeset
150 // Current thread time when it acquired something from other threads.
kono
parents:
diff changeset
151 u64 last_acquire_;
kono
parents:
diff changeset
152
kono
parents:
diff changeset
153 // Cached SyncClock (without dirty entries and release_store_tid_).
kono
parents:
diff changeset
154 // We reuse it for subsequent store-release operations without intervening
kono
parents:
diff changeset
155 // acquire operations. Since it is shared (and thus constant), clock value
kono
parents:
diff changeset
156 // for the current thread is then stored in dirty entries in the SyncClock.
kono
parents:
diff changeset
157 // We host a refernece to the table while it is cached here.
kono
parents:
diff changeset
158 u32 cached_idx_;
kono
parents:
diff changeset
159 u16 cached_size_;
kono
parents:
diff changeset
160 u16 cached_blocks_;
kono
parents:
diff changeset
161
kono
parents:
diff changeset
162 // Number of active elements in the clk_ table (the rest is zeros).
kono
parents:
diff changeset
163 uptr nclk_;
kono
parents:
diff changeset
164 u64 clk_[kMaxTidInClock]; // Fixed size vector clock.
kono
parents:
diff changeset
165
kono
parents:
diff changeset
166 bool IsAlreadyAcquired(const SyncClock *src) const;
kono
parents:
diff changeset
167 void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const;
kono
parents:
diff changeset
168 };
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 ALWAYS_INLINE u64 ThreadClock::get(unsigned tid) const {
kono
parents:
diff changeset
171 DCHECK_LT(tid, kMaxTidInClock);
kono
parents:
diff changeset
172 return clk_[tid];
kono
parents:
diff changeset
173 }
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 ALWAYS_INLINE void ThreadClock::set(u64 v) {
kono
parents:
diff changeset
176 DCHECK_GE(v, clk_[tid_]);
kono
parents:
diff changeset
177 clk_[tid_] = v;
kono
parents:
diff changeset
178 }
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 ALWAYS_INLINE void ThreadClock::tick() {
kono
parents:
diff changeset
181 clk_[tid_]++;
kono
parents:
diff changeset
182 }
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 ALWAYS_INLINE uptr ThreadClock::size() const {
kono
parents:
diff changeset
185 return nclk_;
kono
parents:
diff changeset
186 }
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 ALWAYS_INLINE SyncClock::Iter SyncClock::begin() {
kono
parents:
diff changeset
189 return Iter(this);
kono
parents:
diff changeset
190 }
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 ALWAYS_INLINE SyncClock::Iter SyncClock::end() {
kono
parents:
diff changeset
193 return Iter(nullptr);
kono
parents:
diff changeset
194 }
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 ALWAYS_INLINE uptr SyncClock::size() const {
kono
parents:
diff changeset
197 return size_;
kono
parents:
diff changeset
198 }
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 ALWAYS_INLINE SyncClock::Iter::Iter(SyncClock* parent)
kono
parents:
diff changeset
201 : parent_(parent)
kono
parents:
diff changeset
202 , pos_(nullptr)
kono
parents:
diff changeset
203 , end_(nullptr)
kono
parents:
diff changeset
204 , block_(-1) {
kono
parents:
diff changeset
205 if (parent)
kono
parents:
diff changeset
206 Next();
kono
parents:
diff changeset
207 }
kono
parents:
diff changeset
208
kono
parents:
diff changeset
209 ALWAYS_INLINE SyncClock::Iter& SyncClock::Iter::operator++() {
kono
parents:
diff changeset
210 pos_++;
kono
parents:
diff changeset
211 if (UNLIKELY(pos_ >= end_))
kono
parents:
diff changeset
212 Next();
kono
parents:
diff changeset
213 return *this;
kono
parents:
diff changeset
214 }
kono
parents:
diff changeset
215
kono
parents:
diff changeset
216 ALWAYS_INLINE bool SyncClock::Iter::operator!=(const SyncClock::Iter& other) {
kono
parents:
diff changeset
217 return parent_ != other.parent_;
kono
parents:
diff changeset
218 }
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 ALWAYS_INLINE ClockElem &SyncClock::Iter::operator*() {
kono
parents:
diff changeset
221 return *pos_;
kono
parents:
diff changeset
222 }
kono
parents:
diff changeset
223 } // namespace __tsan
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 #endif // TSAN_CLOCK_H