xref: /aosp_15_r20/external/compiler-rt/lib/tsan/rtl/tsan_clock.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- tsan_clock.cc -----------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of ThreadSanitizer (TSan), a race detector.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
13*7c3d14c8STreehugger Robot #include "tsan_clock.h"
14*7c3d14c8STreehugger Robot #include "tsan_rtl.h"
15*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
16*7c3d14c8STreehugger Robot 
17*7c3d14c8STreehugger Robot // SyncClock and ThreadClock implement vector clocks for sync variables
18*7c3d14c8STreehugger Robot // (mutexes, atomic variables, file descriptors, etc) and threads, respectively.
19*7c3d14c8STreehugger Robot // ThreadClock contains fixed-size vector clock for maximum number of threads.
20*7c3d14c8STreehugger Robot // SyncClock contains growable vector clock for currently necessary number of
21*7c3d14c8STreehugger Robot // threads.
22*7c3d14c8STreehugger Robot // Together they implement very simple model of operations, namely:
23*7c3d14c8STreehugger Robot //
24*7c3d14c8STreehugger Robot //   void ThreadClock::acquire(const SyncClock *src) {
25*7c3d14c8STreehugger Robot //     for (int i = 0; i < kMaxThreads; i++)
26*7c3d14c8STreehugger Robot //       clock[i] = max(clock[i], src->clock[i]);
27*7c3d14c8STreehugger Robot //   }
28*7c3d14c8STreehugger Robot //
29*7c3d14c8STreehugger Robot //   void ThreadClock::release(SyncClock *dst) const {
30*7c3d14c8STreehugger Robot //     for (int i = 0; i < kMaxThreads; i++)
31*7c3d14c8STreehugger Robot //       dst->clock[i] = max(dst->clock[i], clock[i]);
32*7c3d14c8STreehugger Robot //   }
33*7c3d14c8STreehugger Robot //
34*7c3d14c8STreehugger Robot //   void ThreadClock::ReleaseStore(SyncClock *dst) const {
35*7c3d14c8STreehugger Robot //     for (int i = 0; i < kMaxThreads; i++)
36*7c3d14c8STreehugger Robot //       dst->clock[i] = clock[i];
37*7c3d14c8STreehugger Robot //   }
38*7c3d14c8STreehugger Robot //
39*7c3d14c8STreehugger Robot //   void ThreadClock::acq_rel(SyncClock *dst) {
40*7c3d14c8STreehugger Robot //     acquire(dst);
41*7c3d14c8STreehugger Robot //     release(dst);
42*7c3d14c8STreehugger Robot //   }
43*7c3d14c8STreehugger Robot //
44*7c3d14c8STreehugger Robot // Conformance to this model is extensively verified in tsan_clock_test.cc.
45*7c3d14c8STreehugger Robot // However, the implementation is significantly more complex. The complexity
46*7c3d14c8STreehugger Robot // allows to implement important classes of use cases in O(1) instead of O(N).
47*7c3d14c8STreehugger Robot //
48*7c3d14c8STreehugger Robot // The use cases are:
49*7c3d14c8STreehugger Robot // 1. Singleton/once atomic that has a single release-store operation followed
50*7c3d14c8STreehugger Robot //    by zillions of acquire-loads (the acquire-load is O(1)).
51*7c3d14c8STreehugger Robot // 2. Thread-local mutex (both lock and unlock can be O(1)).
52*7c3d14c8STreehugger Robot // 3. Leaf mutex (unlock is O(1)).
53*7c3d14c8STreehugger Robot // 4. A mutex shared by 2 threads (both lock and unlock can be O(1)).
54*7c3d14c8STreehugger Robot // 5. An atomic with a single writer (writes can be O(1)).
55*7c3d14c8STreehugger Robot // The implementation dynamically adopts to workload. So if an atomic is in
56*7c3d14c8STreehugger Robot // read-only phase, these reads will be O(1); if it later switches to read/write
57*7c3d14c8STreehugger Robot // phase, the implementation will correctly handle that by switching to O(N).
58*7c3d14c8STreehugger Robot //
59*7c3d14c8STreehugger Robot // Thread-safety note: all const operations on SyncClock's are conducted under
60*7c3d14c8STreehugger Robot // a shared lock; all non-const operations on SyncClock's are conducted under
61*7c3d14c8STreehugger Robot // an exclusive lock; ThreadClock's are private to respective threads and so
62*7c3d14c8STreehugger Robot // do not need any protection.
63*7c3d14c8STreehugger Robot //
64*7c3d14c8STreehugger Robot // Description of ThreadClock state:
65*7c3d14c8STreehugger Robot // clk_ - fixed size vector clock.
66*7c3d14c8STreehugger Robot // nclk_ - effective size of the vector clock (the rest is zeros).
67*7c3d14c8STreehugger Robot // tid_ - index of the thread associated with he clock ("current thread").
68*7c3d14c8STreehugger Robot // last_acquire_ - current thread time when it acquired something from
69*7c3d14c8STreehugger Robot //   other threads.
70*7c3d14c8STreehugger Robot //
71*7c3d14c8STreehugger Robot // Description of SyncClock state:
72*7c3d14c8STreehugger Robot // clk_ - variable size vector clock, low kClkBits hold timestamp,
73*7c3d14c8STreehugger Robot //   the remaining bits hold "acquired" flag (the actual value is thread's
74*7c3d14c8STreehugger Robot //   reused counter);
75*7c3d14c8STreehugger Robot //   if acquried == thr->reused_, then the respective thread has already
76*7c3d14c8STreehugger Robot //   acquired this clock (except possibly dirty_tids_).
77*7c3d14c8STreehugger Robot // dirty_tids_ - holds up to two indeces in the vector clock that other threads
78*7c3d14c8STreehugger Robot //   need to acquire regardless of "acquired" flag value;
79*7c3d14c8STreehugger Robot // release_store_tid_ - denotes that the clock state is a result of
80*7c3d14c8STreehugger Robot //   release-store operation by the thread with release_store_tid_ index.
81*7c3d14c8STreehugger Robot // release_store_reused_ - reuse count of release_store_tid_.
82*7c3d14c8STreehugger Robot 
83*7c3d14c8STreehugger Robot // We don't have ThreadState in these methods, so this is an ugly hack that
84*7c3d14c8STreehugger Robot // works only in C++.
85*7c3d14c8STreehugger Robot #ifndef SANITIZER_GO
86*7c3d14c8STreehugger Robot # define CPP_STAT_INC(typ) StatInc(cur_thread(), typ)
87*7c3d14c8STreehugger Robot #else
88*7c3d14c8STreehugger Robot # define CPP_STAT_INC(typ) (void)0
89*7c3d14c8STreehugger Robot #endif
90*7c3d14c8STreehugger Robot 
91*7c3d14c8STreehugger Robot namespace __tsan {
92*7c3d14c8STreehugger Robot 
ThreadClock(unsigned tid,unsigned reused)93*7c3d14c8STreehugger Robot ThreadClock::ThreadClock(unsigned tid, unsigned reused)
94*7c3d14c8STreehugger Robot     : tid_(tid)
95*7c3d14c8STreehugger Robot     , reused_(reused + 1) {  // 0 has special meaning
96*7c3d14c8STreehugger Robot   CHECK_LT(tid, kMaxTidInClock);
97*7c3d14c8STreehugger Robot   CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
98*7c3d14c8STreehugger Robot   nclk_ = tid_ + 1;
99*7c3d14c8STreehugger Robot   last_acquire_ = 0;
100*7c3d14c8STreehugger Robot   internal_memset(clk_, 0, sizeof(clk_));
101*7c3d14c8STreehugger Robot   clk_[tid_].reused = reused_;
102*7c3d14c8STreehugger Robot }
103*7c3d14c8STreehugger Robot 
acquire(ClockCache * c,const SyncClock * src)104*7c3d14c8STreehugger Robot void ThreadClock::acquire(ClockCache *c, const SyncClock *src) {
105*7c3d14c8STreehugger Robot   DCHECK_LE(nclk_, kMaxTid);
106*7c3d14c8STreehugger Robot   DCHECK_LE(src->size_, kMaxTid);
107*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockAcquire);
108*7c3d14c8STreehugger Robot 
109*7c3d14c8STreehugger Robot   // Check if it's empty -> no need to do anything.
110*7c3d14c8STreehugger Robot   const uptr nclk = src->size_;
111*7c3d14c8STreehugger Robot   if (nclk == 0) {
112*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockAcquireEmpty);
113*7c3d14c8STreehugger Robot     return;
114*7c3d14c8STreehugger Robot   }
115*7c3d14c8STreehugger Robot 
116*7c3d14c8STreehugger Robot   // Check if we've already acquired src after the last release operation on src
117*7c3d14c8STreehugger Robot   bool acquired = false;
118*7c3d14c8STreehugger Robot   if (nclk > tid_) {
119*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockAcquireLarge);
120*7c3d14c8STreehugger Robot     if (src->elem(tid_).reused == reused_) {
121*7c3d14c8STreehugger Robot       CPP_STAT_INC(StatClockAcquireRepeat);
122*7c3d14c8STreehugger Robot       for (unsigned i = 0; i < kDirtyTids; i++) {
123*7c3d14c8STreehugger Robot         unsigned tid = src->dirty_tids_[i];
124*7c3d14c8STreehugger Robot         if (tid != kInvalidTid) {
125*7c3d14c8STreehugger Robot           u64 epoch = src->elem(tid).epoch;
126*7c3d14c8STreehugger Robot           if (clk_[tid].epoch < epoch) {
127*7c3d14c8STreehugger Robot             clk_[tid].epoch = epoch;
128*7c3d14c8STreehugger Robot             acquired = true;
129*7c3d14c8STreehugger Robot           }
130*7c3d14c8STreehugger Robot         }
131*7c3d14c8STreehugger Robot       }
132*7c3d14c8STreehugger Robot       if (acquired) {
133*7c3d14c8STreehugger Robot         CPP_STAT_INC(StatClockAcquiredSomething);
134*7c3d14c8STreehugger Robot         last_acquire_ = clk_[tid_].epoch;
135*7c3d14c8STreehugger Robot       }
136*7c3d14c8STreehugger Robot       return;
137*7c3d14c8STreehugger Robot     }
138*7c3d14c8STreehugger Robot   }
139*7c3d14c8STreehugger Robot 
140*7c3d14c8STreehugger Robot   // O(N) acquire.
141*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockAcquireFull);
142*7c3d14c8STreehugger Robot   nclk_ = max(nclk_, nclk);
143*7c3d14c8STreehugger Robot   for (uptr i = 0; i < nclk; i++) {
144*7c3d14c8STreehugger Robot     u64 epoch = src->elem(i).epoch;
145*7c3d14c8STreehugger Robot     if (clk_[i].epoch < epoch) {
146*7c3d14c8STreehugger Robot       clk_[i].epoch = epoch;
147*7c3d14c8STreehugger Robot       acquired = true;
148*7c3d14c8STreehugger Robot     }
149*7c3d14c8STreehugger Robot   }
150*7c3d14c8STreehugger Robot 
151*7c3d14c8STreehugger Robot   // Remember that this thread has acquired this clock.
152*7c3d14c8STreehugger Robot   if (nclk > tid_)
153*7c3d14c8STreehugger Robot     src->elem(tid_).reused = reused_;
154*7c3d14c8STreehugger Robot 
155*7c3d14c8STreehugger Robot   if (acquired) {
156*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockAcquiredSomething);
157*7c3d14c8STreehugger Robot     last_acquire_ = clk_[tid_].epoch;
158*7c3d14c8STreehugger Robot   }
159*7c3d14c8STreehugger Robot }
160*7c3d14c8STreehugger Robot 
release(ClockCache * c,SyncClock * dst) const161*7c3d14c8STreehugger Robot void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
162*7c3d14c8STreehugger Robot   DCHECK_LE(nclk_, kMaxTid);
163*7c3d14c8STreehugger Robot   DCHECK_LE(dst->size_, kMaxTid);
164*7c3d14c8STreehugger Robot 
165*7c3d14c8STreehugger Robot   if (dst->size_ == 0) {
166*7c3d14c8STreehugger Robot     // ReleaseStore will correctly set release_store_tid_,
167*7c3d14c8STreehugger Robot     // which can be important for future operations.
168*7c3d14c8STreehugger Robot     ReleaseStore(c, dst);
169*7c3d14c8STreehugger Robot     return;
170*7c3d14c8STreehugger Robot   }
171*7c3d14c8STreehugger Robot 
172*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockRelease);
173*7c3d14c8STreehugger Robot   // Check if we need to resize dst.
174*7c3d14c8STreehugger Robot   if (dst->size_ < nclk_)
175*7c3d14c8STreehugger Robot     dst->Resize(c, nclk_);
176*7c3d14c8STreehugger Robot 
177*7c3d14c8STreehugger Robot   // Check if we had not acquired anything from other threads
178*7c3d14c8STreehugger Robot   // since the last release on dst. If so, we need to update
179*7c3d14c8STreehugger Robot   // only dst->elem(tid_).
180*7c3d14c8STreehugger Robot   if (dst->elem(tid_).epoch > last_acquire_) {
181*7c3d14c8STreehugger Robot     UpdateCurrentThread(dst);
182*7c3d14c8STreehugger Robot     if (dst->release_store_tid_ != tid_ ||
183*7c3d14c8STreehugger Robot         dst->release_store_reused_ != reused_)
184*7c3d14c8STreehugger Robot       dst->release_store_tid_ = kInvalidTid;
185*7c3d14c8STreehugger Robot     return;
186*7c3d14c8STreehugger Robot   }
187*7c3d14c8STreehugger Robot 
188*7c3d14c8STreehugger Robot   // O(N) release.
189*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockReleaseFull);
190*7c3d14c8STreehugger Robot   // First, remember whether we've acquired dst.
191*7c3d14c8STreehugger Robot   bool acquired = IsAlreadyAcquired(dst);
192*7c3d14c8STreehugger Robot   if (acquired)
193*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockReleaseAcquired);
194*7c3d14c8STreehugger Robot   // Update dst->clk_.
195*7c3d14c8STreehugger Robot   for (uptr i = 0; i < nclk_; i++) {
196*7c3d14c8STreehugger Robot     ClockElem &ce = dst->elem(i);
197*7c3d14c8STreehugger Robot     ce.epoch = max(ce.epoch, clk_[i].epoch);
198*7c3d14c8STreehugger Robot     ce.reused = 0;
199*7c3d14c8STreehugger Robot   }
200*7c3d14c8STreehugger Robot   // Clear 'acquired' flag in the remaining elements.
201*7c3d14c8STreehugger Robot   if (nclk_ < dst->size_)
202*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockReleaseClearTail);
203*7c3d14c8STreehugger Robot   for (uptr i = nclk_; i < dst->size_; i++)
204*7c3d14c8STreehugger Robot     dst->elem(i).reused = 0;
205*7c3d14c8STreehugger Robot   for (unsigned i = 0; i < kDirtyTids; i++)
206*7c3d14c8STreehugger Robot     dst->dirty_tids_[i] = kInvalidTid;
207*7c3d14c8STreehugger Robot   dst->release_store_tid_ = kInvalidTid;
208*7c3d14c8STreehugger Robot   dst->release_store_reused_ = 0;
209*7c3d14c8STreehugger Robot   // If we've acquired dst, remember this fact,
210*7c3d14c8STreehugger Robot   // so that we don't need to acquire it on next acquire.
211*7c3d14c8STreehugger Robot   if (acquired)
212*7c3d14c8STreehugger Robot     dst->elem(tid_).reused = reused_;
213*7c3d14c8STreehugger Robot }
214*7c3d14c8STreehugger Robot 
ReleaseStore(ClockCache * c,SyncClock * dst) const215*7c3d14c8STreehugger Robot void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const {
216*7c3d14c8STreehugger Robot   DCHECK_LE(nclk_, kMaxTid);
217*7c3d14c8STreehugger Robot   DCHECK_LE(dst->size_, kMaxTid);
218*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockStore);
219*7c3d14c8STreehugger Robot 
220*7c3d14c8STreehugger Robot   // Check if we need to resize dst.
221*7c3d14c8STreehugger Robot   if (dst->size_ < nclk_)
222*7c3d14c8STreehugger Robot     dst->Resize(c, nclk_);
223*7c3d14c8STreehugger Robot 
224*7c3d14c8STreehugger Robot   if (dst->release_store_tid_ == tid_ &&
225*7c3d14c8STreehugger Robot       dst->release_store_reused_ == reused_ &&
226*7c3d14c8STreehugger Robot       dst->elem(tid_).epoch > last_acquire_) {
227*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockStoreFast);
228*7c3d14c8STreehugger Robot     UpdateCurrentThread(dst);
229*7c3d14c8STreehugger Robot     return;
230*7c3d14c8STreehugger Robot   }
231*7c3d14c8STreehugger Robot 
232*7c3d14c8STreehugger Robot   // O(N) release-store.
233*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockStoreFull);
234*7c3d14c8STreehugger Robot   for (uptr i = 0; i < nclk_; i++) {
235*7c3d14c8STreehugger Robot     ClockElem &ce = dst->elem(i);
236*7c3d14c8STreehugger Robot     ce.epoch = clk_[i].epoch;
237*7c3d14c8STreehugger Robot     ce.reused = 0;
238*7c3d14c8STreehugger Robot   }
239*7c3d14c8STreehugger Robot   // Clear the tail of dst->clk_.
240*7c3d14c8STreehugger Robot   if (nclk_ < dst->size_) {
241*7c3d14c8STreehugger Robot     for (uptr i = nclk_; i < dst->size_; i++) {
242*7c3d14c8STreehugger Robot       ClockElem &ce = dst->elem(i);
243*7c3d14c8STreehugger Robot       ce.epoch = 0;
244*7c3d14c8STreehugger Robot       ce.reused = 0;
245*7c3d14c8STreehugger Robot     }
246*7c3d14c8STreehugger Robot     CPP_STAT_INC(StatClockStoreTail);
247*7c3d14c8STreehugger Robot   }
248*7c3d14c8STreehugger Robot   for (unsigned i = 0; i < kDirtyTids; i++)
249*7c3d14c8STreehugger Robot     dst->dirty_tids_[i] = kInvalidTid;
250*7c3d14c8STreehugger Robot   dst->release_store_tid_ = tid_;
251*7c3d14c8STreehugger Robot   dst->release_store_reused_ = reused_;
252*7c3d14c8STreehugger Robot   // Rememeber that we don't need to acquire it in future.
253*7c3d14c8STreehugger Robot   dst->elem(tid_).reused = reused_;
254*7c3d14c8STreehugger Robot }
255*7c3d14c8STreehugger Robot 
acq_rel(ClockCache * c,SyncClock * dst)256*7c3d14c8STreehugger Robot void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
257*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockAcquireRelease);
258*7c3d14c8STreehugger Robot   acquire(c, dst);
259*7c3d14c8STreehugger Robot   ReleaseStore(c, dst);
260*7c3d14c8STreehugger Robot }
261*7c3d14c8STreehugger Robot 
262*7c3d14c8STreehugger Robot // Updates only single element related to the current thread in dst->clk_.
UpdateCurrentThread(SyncClock * dst) const263*7c3d14c8STreehugger Robot void ThreadClock::UpdateCurrentThread(SyncClock *dst) const {
264*7c3d14c8STreehugger Robot   // Update the threads time, but preserve 'acquired' flag.
265*7c3d14c8STreehugger Robot   dst->elem(tid_).epoch = clk_[tid_].epoch;
266*7c3d14c8STreehugger Robot 
267*7c3d14c8STreehugger Robot   for (unsigned i = 0; i < kDirtyTids; i++) {
268*7c3d14c8STreehugger Robot     if (dst->dirty_tids_[i] == tid_) {
269*7c3d14c8STreehugger Robot       CPP_STAT_INC(StatClockReleaseFast1);
270*7c3d14c8STreehugger Robot       return;
271*7c3d14c8STreehugger Robot     }
272*7c3d14c8STreehugger Robot     if (dst->dirty_tids_[i] == kInvalidTid) {
273*7c3d14c8STreehugger Robot       CPP_STAT_INC(StatClockReleaseFast2);
274*7c3d14c8STreehugger Robot       dst->dirty_tids_[i] = tid_;
275*7c3d14c8STreehugger Robot       return;
276*7c3d14c8STreehugger Robot     }
277*7c3d14c8STreehugger Robot   }
278*7c3d14c8STreehugger Robot   // Reset all 'acquired' flags, O(N).
279*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockReleaseSlow);
280*7c3d14c8STreehugger Robot   for (uptr i = 0; i < dst->size_; i++)
281*7c3d14c8STreehugger Robot     dst->elem(i).reused = 0;
282*7c3d14c8STreehugger Robot   for (unsigned i = 0; i < kDirtyTids; i++)
283*7c3d14c8STreehugger Robot     dst->dirty_tids_[i] = kInvalidTid;
284*7c3d14c8STreehugger Robot }
285*7c3d14c8STreehugger Robot 
286*7c3d14c8STreehugger Robot // Checks whether the current threads has already acquired src.
IsAlreadyAcquired(const SyncClock * src) const287*7c3d14c8STreehugger Robot bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
288*7c3d14c8STreehugger Robot   if (src->elem(tid_).reused != reused_)
289*7c3d14c8STreehugger Robot     return false;
290*7c3d14c8STreehugger Robot   for (unsigned i = 0; i < kDirtyTids; i++) {
291*7c3d14c8STreehugger Robot     unsigned tid = src->dirty_tids_[i];
292*7c3d14c8STreehugger Robot     if (tid != kInvalidTid) {
293*7c3d14c8STreehugger Robot       if (clk_[tid].epoch < src->elem(tid).epoch)
294*7c3d14c8STreehugger Robot         return false;
295*7c3d14c8STreehugger Robot     }
296*7c3d14c8STreehugger Robot   }
297*7c3d14c8STreehugger Robot   return true;
298*7c3d14c8STreehugger Robot }
299*7c3d14c8STreehugger Robot 
Resize(ClockCache * c,uptr nclk)300*7c3d14c8STreehugger Robot void SyncClock::Resize(ClockCache *c, uptr nclk) {
301*7c3d14c8STreehugger Robot   CPP_STAT_INC(StatClockReleaseResize);
302*7c3d14c8STreehugger Robot   if (RoundUpTo(nclk, ClockBlock::kClockCount) <=
303*7c3d14c8STreehugger Robot       RoundUpTo(size_, ClockBlock::kClockCount)) {
304*7c3d14c8STreehugger Robot     // Growing within the same block.
305*7c3d14c8STreehugger Robot     // Memory is already allocated, just increase the size.
306*7c3d14c8STreehugger Robot     size_ = nclk;
307*7c3d14c8STreehugger Robot     return;
308*7c3d14c8STreehugger Robot   }
309*7c3d14c8STreehugger Robot   if (nclk <= ClockBlock::kClockCount) {
310*7c3d14c8STreehugger Robot     // Grow from 0 to one-level table.
311*7c3d14c8STreehugger Robot     CHECK_EQ(size_, 0);
312*7c3d14c8STreehugger Robot     CHECK_EQ(tab_, 0);
313*7c3d14c8STreehugger Robot     CHECK_EQ(tab_idx_, 0);
314*7c3d14c8STreehugger Robot     size_ = nclk;
315*7c3d14c8STreehugger Robot     tab_idx_ = ctx->clock_alloc.Alloc(c);
316*7c3d14c8STreehugger Robot     tab_ = ctx->clock_alloc.Map(tab_idx_);
317*7c3d14c8STreehugger Robot     internal_memset(tab_, 0, sizeof(*tab_));
318*7c3d14c8STreehugger Robot     return;
319*7c3d14c8STreehugger Robot   }
320*7c3d14c8STreehugger Robot   // Growing two-level table.
321*7c3d14c8STreehugger Robot   if (size_ == 0) {
322*7c3d14c8STreehugger Robot     // Allocate first level table.
323*7c3d14c8STreehugger Robot     tab_idx_ = ctx->clock_alloc.Alloc(c);
324*7c3d14c8STreehugger Robot     tab_ = ctx->clock_alloc.Map(tab_idx_);
325*7c3d14c8STreehugger Robot     internal_memset(tab_, 0, sizeof(*tab_));
326*7c3d14c8STreehugger Robot   } else if (size_ <= ClockBlock::kClockCount) {
327*7c3d14c8STreehugger Robot     // Transform one-level table to two-level table.
328*7c3d14c8STreehugger Robot     u32 old = tab_idx_;
329*7c3d14c8STreehugger Robot     tab_idx_ = ctx->clock_alloc.Alloc(c);
330*7c3d14c8STreehugger Robot     tab_ = ctx->clock_alloc.Map(tab_idx_);
331*7c3d14c8STreehugger Robot     internal_memset(tab_, 0, sizeof(*tab_));
332*7c3d14c8STreehugger Robot     tab_->table[0] = old;
333*7c3d14c8STreehugger Robot   }
334*7c3d14c8STreehugger Robot   // At this point we have first level table allocated.
335*7c3d14c8STreehugger Robot   // Add second level tables as necessary.
336*7c3d14c8STreehugger Robot   for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount);
337*7c3d14c8STreehugger Robot       i < nclk; i += ClockBlock::kClockCount) {
338*7c3d14c8STreehugger Robot     u32 idx = ctx->clock_alloc.Alloc(c);
339*7c3d14c8STreehugger Robot     ClockBlock *cb = ctx->clock_alloc.Map(idx);
340*7c3d14c8STreehugger Robot     internal_memset(cb, 0, sizeof(*cb));
341*7c3d14c8STreehugger Robot     CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0);
342*7c3d14c8STreehugger Robot     tab_->table[i/ClockBlock::kClockCount] = idx;
343*7c3d14c8STreehugger Robot   }
344*7c3d14c8STreehugger Robot   size_ = nclk;
345*7c3d14c8STreehugger Robot }
346*7c3d14c8STreehugger Robot 
347*7c3d14c8STreehugger Robot // Sets a single element in the vector clock.
348*7c3d14c8STreehugger Robot // This function is called only from weird places like AcquireGlobal.
set(unsigned tid,u64 v)349*7c3d14c8STreehugger Robot void ThreadClock::set(unsigned tid, u64 v) {
350*7c3d14c8STreehugger Robot   DCHECK_LT(tid, kMaxTid);
351*7c3d14c8STreehugger Robot   DCHECK_GE(v, clk_[tid].epoch);
352*7c3d14c8STreehugger Robot   clk_[tid].epoch = v;
353*7c3d14c8STreehugger Robot   if (nclk_ <= tid)
354*7c3d14c8STreehugger Robot     nclk_ = tid + 1;
355*7c3d14c8STreehugger Robot   last_acquire_ = clk_[tid_].epoch;
356*7c3d14c8STreehugger Robot }
357*7c3d14c8STreehugger Robot 
DebugDump(int (* printf)(const char * s,...))358*7c3d14c8STreehugger Robot void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
359*7c3d14c8STreehugger Robot   printf("clock=[");
360*7c3d14c8STreehugger Robot   for (uptr i = 0; i < nclk_; i++)
361*7c3d14c8STreehugger Robot     printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
362*7c3d14c8STreehugger Robot   printf("] reused=[");
363*7c3d14c8STreehugger Robot   for (uptr i = 0; i < nclk_; i++)
364*7c3d14c8STreehugger Robot     printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
365*7c3d14c8STreehugger Robot   printf("] tid=%u/%u last_acq=%llu",
366*7c3d14c8STreehugger Robot       tid_, reused_, last_acquire_);
367*7c3d14c8STreehugger Robot }
368*7c3d14c8STreehugger Robot 
SyncClock()369*7c3d14c8STreehugger Robot SyncClock::SyncClock()
370*7c3d14c8STreehugger Robot     : release_store_tid_(kInvalidTid)
371*7c3d14c8STreehugger Robot     , release_store_reused_()
372*7c3d14c8STreehugger Robot     , tab_()
373*7c3d14c8STreehugger Robot     , tab_idx_()
374*7c3d14c8STreehugger Robot     , size_() {
375*7c3d14c8STreehugger Robot   for (uptr i = 0; i < kDirtyTids; i++)
376*7c3d14c8STreehugger Robot     dirty_tids_[i] = kInvalidTid;
377*7c3d14c8STreehugger Robot }
378*7c3d14c8STreehugger Robot 
~SyncClock()379*7c3d14c8STreehugger Robot SyncClock::~SyncClock() {
380*7c3d14c8STreehugger Robot   // Reset must be called before dtor.
381*7c3d14c8STreehugger Robot   CHECK_EQ(size_, 0);
382*7c3d14c8STreehugger Robot   CHECK_EQ(tab_, 0);
383*7c3d14c8STreehugger Robot   CHECK_EQ(tab_idx_, 0);
384*7c3d14c8STreehugger Robot }
385*7c3d14c8STreehugger Robot 
Reset(ClockCache * c)386*7c3d14c8STreehugger Robot void SyncClock::Reset(ClockCache *c) {
387*7c3d14c8STreehugger Robot   if (size_ == 0) {
388*7c3d14c8STreehugger Robot     // nothing
389*7c3d14c8STreehugger Robot   } else if (size_ <= ClockBlock::kClockCount) {
390*7c3d14c8STreehugger Robot     // One-level table.
391*7c3d14c8STreehugger Robot     ctx->clock_alloc.Free(c, tab_idx_);
392*7c3d14c8STreehugger Robot   } else {
393*7c3d14c8STreehugger Robot     // Two-level table.
394*7c3d14c8STreehugger Robot     for (uptr i = 0; i < size_; i += ClockBlock::kClockCount)
395*7c3d14c8STreehugger Robot       ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]);
396*7c3d14c8STreehugger Robot     ctx->clock_alloc.Free(c, tab_idx_);
397*7c3d14c8STreehugger Robot   }
398*7c3d14c8STreehugger Robot   tab_ = 0;
399*7c3d14c8STreehugger Robot   tab_idx_ = 0;
400*7c3d14c8STreehugger Robot   size_ = 0;
401*7c3d14c8STreehugger Robot   release_store_tid_ = kInvalidTid;
402*7c3d14c8STreehugger Robot   release_store_reused_ = 0;
403*7c3d14c8STreehugger Robot   for (uptr i = 0; i < kDirtyTids; i++)
404*7c3d14c8STreehugger Robot     dirty_tids_[i] = kInvalidTid;
405*7c3d14c8STreehugger Robot }
406*7c3d14c8STreehugger Robot 
elem(unsigned tid) const407*7c3d14c8STreehugger Robot ClockElem &SyncClock::elem(unsigned tid) const {
408*7c3d14c8STreehugger Robot   DCHECK_LT(tid, size_);
409*7c3d14c8STreehugger Robot   if (size_ <= ClockBlock::kClockCount)
410*7c3d14c8STreehugger Robot     return tab_->clock[tid];
411*7c3d14c8STreehugger Robot   u32 idx = tab_->table[tid / ClockBlock::kClockCount];
412*7c3d14c8STreehugger Robot   ClockBlock *cb = ctx->clock_alloc.Map(idx);
413*7c3d14c8STreehugger Robot   return cb->clock[tid % ClockBlock::kClockCount];
414*7c3d14c8STreehugger Robot }
415*7c3d14c8STreehugger Robot 
DebugDump(int (* printf)(const char * s,...))416*7c3d14c8STreehugger Robot void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
417*7c3d14c8STreehugger Robot   printf("clock=[");
418*7c3d14c8STreehugger Robot   for (uptr i = 0; i < size_; i++)
419*7c3d14c8STreehugger Robot     printf("%s%llu", i == 0 ? "" : ",", elem(i).epoch);
420*7c3d14c8STreehugger Robot   printf("] reused=[");
421*7c3d14c8STreehugger Robot   for (uptr i = 0; i < size_; i++)
422*7c3d14c8STreehugger Robot     printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
423*7c3d14c8STreehugger Robot   printf("] release_store_tid=%d/%d dirty_tids=%d/%d",
424*7c3d14c8STreehugger Robot       release_store_tid_, release_store_reused_,
425*7c3d14c8STreehugger Robot       dirty_tids_[0], dirty_tids_[1]);
426*7c3d14c8STreehugger Robot }
427*7c3d14c8STreehugger Robot }  // namespace __tsan
428