1 //===-- tsan_clock.h --------------------------------------------*- C++ -*-===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
14 #include "tsan_defs.h"
15 #include "tsan_dense_alloc.h"
19 typedef DenseSlabAlloc
<ClockBlock
, 1<<16, 1<<10> ClockAlloc
;
20 typedef DenseSlabAllocCache ClockCache
;
22 // The clock that lives in sync variables (mutexes, atomics, etc).
30 // These are used only in tests.
31 u64
get(unsigned tid
) const;
32 u64
get_clean(unsigned tid
) const;
34 void Resize(ClockCache
*c
, uptr nclk
);
35 void Reset(ClockCache
*c
);
37 void DebugDump(int(*printf
)(const char *s
, ...));
39 // Clock element iterator.
40 // Note: it iterates only over the table without regard to dirty entries.
43 explicit Iter(SyncClock
* parent
);
45 bool operator!=(const Iter
& other
);
46 ClockElem
&operator*();
50 // [pos_, end_) is the current continuous range of clock elements.
53 int block_
; // Current number of second level block.
62 friend class ThreadClock
;
64 static const uptr kDirtyTids
= 2;
68 u64 tid
: 64 - kClkBits
; // kInvalidId if not active
71 unsigned release_store_tid_
;
72 unsigned release_store_reused_
;
73 Dirty dirty_
[kDirtyTids
];
74 // If size_ is 0, tab_ is nullptr.
75 // If size <= 64 (kClockCount), tab_ contains pointer to an array with
76 // 64 ClockElem's (ClockBlock::clock).
77 // Otherwise, tab_ points to an array with up to 127 u32 elements,
78 // each pointing to the second-level 512b block with 64 ClockElem's.
79 // Unused space in the first level ClockBlock is used to store additional
81 // The last u32 element in the first level ClockBlock is always used as
84 // See the following scheme for details.
85 // All memory blocks are 512 bytes (allocated from ClockAlloc).
86 // Clock (clk) elements are 64 bits.
87 // Idx and ref are 32 bits.
92 // +----------------------------------------------------+
93 // | clk128 | clk129 | ...unused... | idx1 | idx0 | ref |
94 // +----------------------------------------------------+
97 // | +----------------+
98 // | | clk0 ... clk63 |
99 // | +----------------+
101 // +------------------+
102 // | clk64 ... clk127 |
103 // +------------------+
105 // Note: dirty entries, if active, always override what's stored in the clock.
109 u16 blocks_
; // Number of second level blocks.
111 void Unshare(ClockCache
*c
);
112 bool IsShared() const;
113 bool Cachable() const;
116 uptr
capacity() const;
117 u32
get_block(uptr bi
) const;
118 void append_block(u32 idx
);
119 ClockElem
&elem(unsigned tid
) const;
122 // The clock that lives in threads.
125 typedef DenseSlabAllocCache Cache
;
127 explicit ThreadClock(unsigned tid
, unsigned reused
= 0);
129 u64
get(unsigned tid
) const;
130 void set(ClockCache
*c
, unsigned tid
, u64 v
);
135 void acquire(ClockCache
*c
, SyncClock
*src
);
136 void release(ClockCache
*c
, SyncClock
*dst
);
137 void acq_rel(ClockCache
*c
, SyncClock
*dst
);
138 void ReleaseStore(ClockCache
*c
, SyncClock
*dst
);
139 void ResetCached(ClockCache
*c
);
142 void DebugDump(int(*printf
)(const char *s
, ...));
145 static const uptr kDirtyTids
= SyncClock::kDirtyTids
;
146 // Index of the thread associated with he clock ("current thread").
148 const unsigned reused_
; // tid_ reuse count.
149 // Current thread time when it acquired something from other threads.
152 // Cached SyncClock (without dirty entries and release_store_tid_).
153 // We reuse it for subsequent store-release operations without intervening
154 // acquire operations. Since it is shared (and thus constant), clock value
155 // for the current thread is then stored in dirty entries in the SyncClock.
156 // We host a refernece to the table while it is cached here.
161 // Number of active elements in the clk_ table (the rest is zeros).
163 u64 clk_
[kMaxTidInClock
]; // Fixed size vector clock.
165 bool IsAlreadyAcquired(const SyncClock
*src
) const;
166 void UpdateCurrentThread(ClockCache
*c
, SyncClock
*dst
) const;
169 ALWAYS_INLINE u64
ThreadClock::get(unsigned tid
) const {
170 DCHECK_LT(tid
, kMaxTidInClock
);
174 ALWAYS_INLINE
void ThreadClock::set(u64 v
) {
175 DCHECK_GE(v
, clk_
[tid_
]);
179 ALWAYS_INLINE
void ThreadClock::tick() {
183 ALWAYS_INLINE uptr
ThreadClock::size() const {
187 ALWAYS_INLINE
SyncClock::Iter
SyncClock::begin() {
191 ALWAYS_INLINE
SyncClock::Iter
SyncClock::end() {
192 return Iter(nullptr);
195 ALWAYS_INLINE uptr
SyncClock::size() const {
199 ALWAYS_INLINE
SyncClock::Iter::Iter(SyncClock
* parent
)
208 ALWAYS_INLINE
SyncClock::Iter
& SyncClock::Iter::operator++() {
210 if (UNLIKELY(pos_
>= end_
))
215 ALWAYS_INLINE
bool SyncClock::Iter::operator!=(const SyncClock::Iter
& other
) {
216 return parent_
!= other
.parent_
;
219 ALWAYS_INLINE ClockElem
&SyncClock::Iter::operator*() {
222 } // namespace __tsan
224 #endif // TSAN_CLOCK_H