1 //===-- tsan_clock.h --------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
11 //===----------------------------------------------------------------------===//
15 #include "tsan_defs.h"
16 #include "tsan_dense_alloc.h"
20 typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
21 typedef DenseSlabAllocCache ClockCache;
23 // The clock that lives in sync variables (mutexes, atomics, etc).
31 // These are used only in tests.
32 u64 get(unsigned tid) const;
33 u64 get_clean(unsigned tid) const;
35 void Resize(ClockCache *c, uptr nclk);
36 void Reset(ClockCache *c);
38 void DebugDump(int(*printf)(const char *s, ...));
40 // Clock element iterator.
41 // Note: it iterates only over the table without regard to dirty entries.
44 explicit Iter(SyncClock* parent);
46 bool operator!=(const Iter& other);
47 ClockElem &operator*();
51 // [pos_, end_) is the current continuous range of clock elements.
54 int block_; // Current number of second level block.
63 friend class ThreadClock;
65 static const uptr kDirtyTids = 2;
69 u64 tid : 64 - kClkBits; // kInvalidId if not active
72 unsigned release_store_tid_;
73 unsigned release_store_reused_;
74 Dirty dirty_[kDirtyTids];
75 // If size_ is 0, tab_ is nullptr.
76 // If size <= 64 (kClockCount), tab_ contains pointer to an array with
77 // 64 ClockElem's (ClockBlock::clock).
78 // Otherwise, tab_ points to an array with up to 127 u32 elements,
79 // each pointing to the second-level 512b block with 64 ClockElem's.
80 // Unused space in the first level ClockBlock is used to store additional
82 // The last u32 element in the first level ClockBlock is always used as
85 // See the following scheme for details.
86 // All memory blocks are 512 bytes (allocated from ClockAlloc).
87 // Clock (clk) elements are 64 bits.
88 // Idx and ref are 32 bits.
93 // +----------------------------------------------------+
94 // | clk128 | clk129 | ...unused... | idx1 | idx0 | ref |
95 // +----------------------------------------------------+
98 // | +----------------+
99 // | | clk0 ... clk63 |
100 // | +----------------+
102 // +------------------+
103 // | clk64 ... clk127 |
104 // +------------------+
106 // Note: dirty entries, if active, always override what's stored in the clock.
110 u16 blocks_; // Number of second level blocks.
112 void Unshare(ClockCache *c);
113 bool IsShared() const;
114 bool Cachable() const;
117 uptr capacity() const;
118 u32 get_block(uptr bi) const;
119 void append_block(u32 idx);
120 ClockElem &elem(unsigned tid) const;
123 // The clock that lives in threads.
126 typedef DenseSlabAllocCache Cache;
128 explicit ThreadClock(unsigned tid, unsigned reused = 0);
130 u64 get(unsigned tid) const;
131 void set(ClockCache *c, unsigned tid, u64 v);
136 void acquire(ClockCache *c, SyncClock *src);
137 void release(ClockCache *c, SyncClock *dst);
138 void acq_rel(ClockCache *c, SyncClock *dst);
139 void ReleaseStore(ClockCache *c, SyncClock *dst);
140 void ResetCached(ClockCache *c);
143 void DebugDump(int(*printf)(const char *s, ...));
146 static const uptr kDirtyTids = SyncClock::kDirtyTids;
147 // Index of the thread associated with he clock ("current thread").
149 const unsigned reused_; // tid_ reuse count.
150 // Current thread time when it acquired something from other threads.
153 // Cached SyncClock (without dirty entries and release_store_tid_).
154 // We reuse it for subsequent store-release operations without intervening
155 // acquire operations. Since it is shared (and thus constant), clock value
156 // for the current thread is then stored in dirty entries in the SyncClock.
157 // We host a refernece to the table while it is cached here.
162 // Number of active elements in the clk_ table (the rest is zeros).
164 u64 clk_[kMaxTidInClock]; // Fixed size vector clock.
166 bool IsAlreadyAcquired(const SyncClock *src) const;
167 void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const;
170 ALWAYS_INLINE u64 ThreadClock::get(unsigned tid) const {
171 DCHECK_LT(tid, kMaxTidInClock);
175 ALWAYS_INLINE void ThreadClock::set(u64 v) {
176 DCHECK_GE(v, clk_[tid_]);
180 ALWAYS_INLINE void ThreadClock::tick() {
184 ALWAYS_INLINE uptr ThreadClock::size() const {
188 ALWAYS_INLINE SyncClock::Iter SyncClock::begin() {
192 ALWAYS_INLINE SyncClock::Iter SyncClock::end() {
193 return Iter(nullptr);
196 ALWAYS_INLINE uptr SyncClock::size() const {
200 ALWAYS_INLINE SyncClock::Iter::Iter(SyncClock* parent)
209 ALWAYS_INLINE SyncClock::Iter& SyncClock::Iter::operator++() {
211 if (UNLIKELY(pos_ >= end_))
216 ALWAYS_INLINE bool SyncClock::Iter::operator!=(const SyncClock::Iter& other) {
217 return parent_ != other.parent_;
220 ALWAYS_INLINE ClockElem &SyncClock::Iter::operator*() {
223 } // namespace __tsan
225 #endif // TSAN_CLOCK_H