1 //===-- tsan_clock.cc -----------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
9 //
10 //===----------------------------------------------------------------------===//
11 #include "tsan_clock.h"
12 #include "tsan_rtl.h"
13 #include "sanitizer_common/sanitizer_placement_new.h"
14 
15 // SyncClock and ThreadClock implement vector clocks for sync variables
16 // (mutexes, atomic variables, file descriptors, etc) and threads, respectively.
17 // ThreadClock contains fixed-size vector clock for maximum number of threads.
18 // SyncClock contains growable vector clock for currently necessary number of
19 // threads.
20 // Together they implement very simple model of operations, namely:
21 //
22 //   void ThreadClock::acquire(const SyncClock *src) {
23 //     for (int i = 0; i < kMaxThreads; i++)
24 //       clock[i] = max(clock[i], src->clock[i]);
25 //   }
26 //
27 //   void ThreadClock::release(SyncClock *dst) const {
28 //     for (int i = 0; i < kMaxThreads; i++)
29 //       dst->clock[i] = max(dst->clock[i], clock[i]);
30 //   }
31 //
32 //   void ThreadClock::ReleaseStore(SyncClock *dst) const {
33 //     for (int i = 0; i < kMaxThreads; i++)
34 //       dst->clock[i] = clock[i];
35 //   }
36 //
37 //   void ThreadClock::acq_rel(SyncClock *dst) {
38 //     acquire(dst);
39 //     release(dst);
40 //   }
41 //
42 // Conformance to this model is extensively verified in tsan_clock_test.cc.
43 // However, the implementation is significantly more complex. The complexity
44 // allows to implement important classes of use cases in O(1) instead of O(N).
45 //
46 // The use cases are:
47 // 1. Singleton/once atomic that has a single release-store operation followed
48 //    by zillions of acquire-loads (the acquire-load is O(1)).
49 // 2. Thread-local mutex (both lock and unlock can be O(1)).
50 // 3. Leaf mutex (unlock is O(1)).
51 // 4. A mutex shared by 2 threads (both lock and unlock can be O(1)).
52 // 5. An atomic with a single writer (writes can be O(1)).
53 // The implementation dynamically adopts to workload. So if an atomic is in
54 // read-only phase, these reads will be O(1); if it later switches to read/write
55 // phase, the implementation will correctly handle that by switching to O(N).
56 //
57 // Thread-safety note: all const operations on SyncClock's are conducted under
58 // a shared lock; all non-const operations on SyncClock's are conducted under
59 // an exclusive lock; ThreadClock's are private to respective threads and so
60 // do not need any protection.
61 //
62 // Description of SyncClock state:
63 // clk_ - variable size vector clock, low kClkBits hold timestamp,
64 //   the remaining bits hold "acquired" flag (the actual value is thread's
65 //   reused counter);
66 //   if acquried == thr->reused_, then the respective thread has already
67 //   acquired this clock (except possibly for dirty elements).
68 // dirty_ - holds up to two indeces in the vector clock that other threads
69 //   need to acquire regardless of "acquired" flag value;
70 // release_store_tid_ - denotes that the clock state is a result of
71 //   release-store operation by the thread with release_store_tid_ index.
72 // release_store_reused_ - reuse count of release_store_tid_.
73 
74 // We don't have ThreadState in these methods, so this is an ugly hack that
75 // works only in C++.
76 #if !SANITIZER_GO
77 # define CPP_STAT_INC(typ) StatInc(cur_thread(), typ)
78 #else
79 # define CPP_STAT_INC(typ) (void)0
80 #endif
81 
82 namespace __tsan {
83 
ref_ptr(ClockBlock * cb)84 static atomic_uint32_t *ref_ptr(ClockBlock *cb) {
85   return reinterpret_cast<atomic_uint32_t *>(&cb->table[ClockBlock::kRefIdx]);
86 }
87 
88 // Drop reference to the first level block idx.
UnrefClockBlock(ClockCache * c,u32 idx,uptr blocks)89 static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) {
90   ClockBlock *cb = ctx->clock_alloc.Map(idx);
91   atomic_uint32_t *ref = ref_ptr(cb);
92   u32 v = atomic_load(ref, memory_order_acquire);
93   for (;;) {
94     CHECK_GT(v, 0);
95     if (v == 1)
96       break;
97     if (atomic_compare_exchange_strong(ref, &v, v - 1, memory_order_acq_rel))
98       return;
99   }
100   // First level block owns second level blocks, so them as well.
101   for (uptr i = 0; i < blocks; i++)
102     ctx->clock_alloc.Free(c, cb->table[ClockBlock::kBlockIdx - i]);
103   ctx->clock_alloc.Free(c, idx);
104 }
105 
ThreadClock(unsigned tid,unsigned reused)106 ThreadClock::ThreadClock(unsigned tid, unsigned reused)
107     : tid_(tid)
108     , reused_(reused + 1)  // 0 has special meaning
109     , cached_idx_()
110     , cached_size_()
111     , cached_blocks_() {
112   CHECK_LT(tid, kMaxTidInClock);
113   CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
114   nclk_ = tid_ + 1;
115   last_acquire_ = 0;
116   internal_memset(clk_, 0, sizeof(clk_));
117 }
118 
ResetCached(ClockCache * c)119 void ThreadClock::ResetCached(ClockCache *c) {
120   if (cached_idx_) {
121     UnrefClockBlock(c, cached_idx_, cached_blocks_);
122     cached_idx_ = 0;
123     cached_size_ = 0;
124     cached_blocks_ = 0;
125   }
126 }
127 
acquire(ClockCache * c,SyncClock * src)128 void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
129   DCHECK_LE(nclk_, kMaxTid);
130   DCHECK_LE(src->size_, kMaxTid);
131   CPP_STAT_INC(StatClockAcquire);
132 
133   // Check if it's empty -> no need to do anything.
134   const uptr nclk = src->size_;
135   if (nclk == 0) {
136     CPP_STAT_INC(StatClockAcquireEmpty);
137     return;
138   }
139 
140   bool acquired = false;
141   for (unsigned i = 0; i < kDirtyTids; i++) {
142     SyncClock::Dirty dirty = src->dirty_[i];
143     unsigned tid = dirty.tid;
144     if (tid != kInvalidTid) {
145       if (clk_[tid] < dirty.epoch) {
146         clk_[tid] = dirty.epoch;
147         acquired = true;
148       }
149     }
150   }
151 
152   // Check if we've already acquired src after the last release operation on src
153   if (tid_ >= nclk || src->elem(tid_).reused != reused_) {
154     // O(N) acquire.
155     CPP_STAT_INC(StatClockAcquireFull);
156     nclk_ = max(nclk_, nclk);
157     u64 *dst_pos = &clk_[0];
158     for (ClockElem &src_elem : *src) {
159       u64 epoch = src_elem.epoch;
160       if (*dst_pos < epoch) {
161         *dst_pos = epoch;
162         acquired = true;
163       }
164       dst_pos++;
165     }
166 
167     // Remember that this thread has acquired this clock.
168     if (nclk > tid_)
169       src->elem(tid_).reused = reused_;
170   }
171 
172   if (acquired) {
173     CPP_STAT_INC(StatClockAcquiredSomething);
174     last_acquire_ = clk_[tid_];
175     ResetCached(c);
176   }
177 }
178 
release(ClockCache * c,SyncClock * dst)179 void ThreadClock::release(ClockCache *c, SyncClock *dst) {
180   DCHECK_LE(nclk_, kMaxTid);
181   DCHECK_LE(dst->size_, kMaxTid);
182 
183   if (dst->size_ == 0) {
184     // ReleaseStore will correctly set release_store_tid_,
185     // which can be important for future operations.
186     ReleaseStore(c, dst);
187     return;
188   }
189 
190   CPP_STAT_INC(StatClockRelease);
191   // Check if we need to resize dst.
192   if (dst->size_ < nclk_)
193     dst->Resize(c, nclk_);
194 
195   // Check if we had not acquired anything from other threads
196   // since the last release on dst. If so, we need to update
197   // only dst->elem(tid_).
198   if (dst->elem(tid_).epoch > last_acquire_) {
199     UpdateCurrentThread(c, dst);
200     if (dst->release_store_tid_ != tid_ ||
201         dst->release_store_reused_ != reused_)
202       dst->release_store_tid_ = kInvalidTid;
203     return;
204   }
205 
206   // O(N) release.
207   CPP_STAT_INC(StatClockReleaseFull);
208   dst->Unshare(c);
209   // First, remember whether we've acquired dst.
210   bool acquired = IsAlreadyAcquired(dst);
211   if (acquired)
212     CPP_STAT_INC(StatClockReleaseAcquired);
213   // Update dst->clk_.
214   dst->FlushDirty();
215   uptr i = 0;
216   for (ClockElem &ce : *dst) {
217     ce.epoch = max(ce.epoch, clk_[i]);
218     ce.reused = 0;
219     i++;
220   }
221   // Clear 'acquired' flag in the remaining elements.
222   if (nclk_ < dst->size_)
223     CPP_STAT_INC(StatClockReleaseClearTail);
224   for (uptr i = nclk_; i < dst->size_; i++)
225     dst->elem(i).reused = 0;
226   dst->release_store_tid_ = kInvalidTid;
227   dst->release_store_reused_ = 0;
228   // If we've acquired dst, remember this fact,
229   // so that we don't need to acquire it on next acquire.
230   if (acquired)
231     dst->elem(tid_).reused = reused_;
232 }
233 
ReleaseStore(ClockCache * c,SyncClock * dst)234 void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
235   DCHECK_LE(nclk_, kMaxTid);
236   DCHECK_LE(dst->size_, kMaxTid);
237   CPP_STAT_INC(StatClockStore);
238 
239   if (dst->size_ == 0 && cached_idx_ != 0) {
240     // Reuse the cached clock.
241     // Note: we could reuse/cache the cached clock in more cases:
242     // we could update the existing clock and cache it, or replace it with the
243     // currently cached clock and release the old one. And for a shared
244     // existing clock, we could replace it with the currently cached;
245     // or unshare, update and cache. But, for simplicity, we currnetly reuse
246     // cached clock only when the target clock is empty.
247     dst->tab_ = ctx->clock_alloc.Map(cached_idx_);
248     dst->tab_idx_ = cached_idx_;
249     dst->size_ = cached_size_;
250     dst->blocks_ = cached_blocks_;
251     CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
252     // The cached clock is shared (immutable),
253     // so this is where we store the current clock.
254     dst->dirty_[0].tid = tid_;
255     dst->dirty_[0].epoch = clk_[tid_];
256     dst->release_store_tid_ = tid_;
257     dst->release_store_reused_ = reused_;
258     // Rememeber that we don't need to acquire it in future.
259     dst->elem(tid_).reused = reused_;
260     // Grab a reference.
261     atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed);
262     return;
263   }
264 
265   // Check if we need to resize dst.
266   if (dst->size_ < nclk_)
267     dst->Resize(c, nclk_);
268 
269   if (dst->release_store_tid_ == tid_ &&
270       dst->release_store_reused_ == reused_ &&
271       dst->elem(tid_).epoch > last_acquire_) {
272     CPP_STAT_INC(StatClockStoreFast);
273     UpdateCurrentThread(c, dst);
274     return;
275   }
276 
277   // O(N) release-store.
278   CPP_STAT_INC(StatClockStoreFull);
279   dst->Unshare(c);
280   // Note: dst can be larger than this ThreadClock.
281   // This is fine since clk_ beyond size is all zeros.
282   uptr i = 0;
283   for (ClockElem &ce : *dst) {
284     ce.epoch = clk_[i];
285     ce.reused = 0;
286     i++;
287   }
288   for (uptr i = 0; i < kDirtyTids; i++)
289     dst->dirty_[i].tid = kInvalidTid;
290   dst->release_store_tid_ = tid_;
291   dst->release_store_reused_ = reused_;
292   // Rememeber that we don't need to acquire it in future.
293   dst->elem(tid_).reused = reused_;
294 
295   // If the resulting clock is cachable, cache it for future release operations.
296   // The clock is always cachable if we released to an empty sync object.
297   if (cached_idx_ == 0 && dst->Cachable()) {
298     // Grab a reference to the ClockBlock.
299     atomic_uint32_t *ref = ref_ptr(dst->tab_);
300     if (atomic_load(ref, memory_order_acquire) == 1)
301       atomic_store_relaxed(ref, 2);
302     else
303       atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed);
304     cached_idx_ = dst->tab_idx_;
305     cached_size_ = dst->size_;
306     cached_blocks_ = dst->blocks_;
307   }
308 }
309 
acq_rel(ClockCache * c,SyncClock * dst)310 void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
311   CPP_STAT_INC(StatClockAcquireRelease);
312   acquire(c, dst);
313   ReleaseStore(c, dst);
314 }
315 
316 // Updates only single element related to the current thread in dst->clk_.
UpdateCurrentThread(ClockCache * c,SyncClock * dst) const317 void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
318   // Update the threads time, but preserve 'acquired' flag.
319   for (unsigned i = 0; i < kDirtyTids; i++) {
320     SyncClock::Dirty *dirty = &dst->dirty_[i];
321     const unsigned tid = dirty->tid;
322     if (tid == tid_ || tid == kInvalidTid) {
323       CPP_STAT_INC(StatClockReleaseFast);
324       dirty->tid = tid_;
325       dirty->epoch = clk_[tid_];
326       return;
327     }
328   }
329   // Reset all 'acquired' flags, O(N).
330   // We are going to touch dst elements, so we need to unshare it.
331   dst->Unshare(c);
332   CPP_STAT_INC(StatClockReleaseSlow);
333   dst->elem(tid_).epoch = clk_[tid_];
334   for (uptr i = 0; i < dst->size_; i++)
335     dst->elem(i).reused = 0;
336   dst->FlushDirty();
337 }
338 
339 // Checks whether the current thread has already acquired src.
IsAlreadyAcquired(const SyncClock * src) const340 bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
341   if (src->elem(tid_).reused != reused_)
342     return false;
343   for (unsigned i = 0; i < kDirtyTids; i++) {
344     SyncClock::Dirty dirty = src->dirty_[i];
345     if (dirty.tid != kInvalidTid) {
346       if (clk_[dirty.tid] < dirty.epoch)
347         return false;
348     }
349   }
350   return true;
351 }
352 
353 // Sets a single element in the vector clock.
354 // This function is called only from weird places like AcquireGlobal.
set(ClockCache * c,unsigned tid,u64 v)355 void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) {
356   DCHECK_LT(tid, kMaxTid);
357   DCHECK_GE(v, clk_[tid]);
358   clk_[tid] = v;
359   if (nclk_ <= tid)
360     nclk_ = tid + 1;
361   last_acquire_ = clk_[tid_];
362   ResetCached(c);
363 }
364 
DebugDump(int (* printf)(const char * s,...))365 void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
366   printf("clock=[");
367   for (uptr i = 0; i < nclk_; i++)
368     printf("%s%llu", i == 0 ? "" : ",", clk_[i]);
369   printf("] tid=%u/%u last_acq=%llu", tid_, reused_, last_acquire_);
370 }
371 
SyncClock()372 SyncClock::SyncClock() {
373   ResetImpl();
374 }
375 
~SyncClock()376 SyncClock::~SyncClock() {
377   // Reset must be called before dtor.
378   CHECK_EQ(size_, 0);
379   CHECK_EQ(blocks_, 0);
380   CHECK_EQ(tab_, 0);
381   CHECK_EQ(tab_idx_, 0);
382 }
383 
Reset(ClockCache * c)384 void SyncClock::Reset(ClockCache *c) {
385   if (size_)
386     UnrefClockBlock(c, tab_idx_, blocks_);
387   ResetImpl();
388 }
389 
ResetImpl()390 void SyncClock::ResetImpl() {
391   tab_ = 0;
392   tab_idx_ = 0;
393   size_ = 0;
394   blocks_ = 0;
395   release_store_tid_ = kInvalidTid;
396   release_store_reused_ = 0;
397   for (uptr i = 0; i < kDirtyTids; i++)
398     dirty_[i].tid = kInvalidTid;
399 }
400 
Resize(ClockCache * c,uptr nclk)401 void SyncClock::Resize(ClockCache *c, uptr nclk) {
402   CPP_STAT_INC(StatClockReleaseResize);
403   Unshare(c);
404   if (nclk <= capacity()) {
405     // Memory is already allocated, just increase the size.
406     size_ = nclk;
407     return;
408   }
409   if (size_ == 0) {
410     // Grow from 0 to one-level table.
411     CHECK_EQ(size_, 0);
412     CHECK_EQ(blocks_, 0);
413     CHECK_EQ(tab_, 0);
414     CHECK_EQ(tab_idx_, 0);
415     tab_idx_ = ctx->clock_alloc.Alloc(c);
416     tab_ = ctx->clock_alloc.Map(tab_idx_);
417     internal_memset(tab_, 0, sizeof(*tab_));
418     atomic_store_relaxed(ref_ptr(tab_), 1);
419     size_ = 1;
420   } else if (size_ > blocks_ * ClockBlock::kClockCount) {
421     u32 idx = ctx->clock_alloc.Alloc(c);
422     ClockBlock *new_cb = ctx->clock_alloc.Map(idx);
423     uptr top = size_ - blocks_ * ClockBlock::kClockCount;
424     CHECK_LT(top, ClockBlock::kClockCount);
425     const uptr move = top * sizeof(tab_->clock[0]);
426     internal_memcpy(&new_cb->clock[0], tab_->clock, move);
427     internal_memset(&new_cb->clock[top], 0, sizeof(*new_cb) - move);
428     internal_memset(tab_->clock, 0, move);
429     append_block(idx);
430   }
431   // At this point we have first level table allocated and all clock elements
432   // are evacuated from it to a second level block.
433   // Add second level tables as necessary.
434   while (nclk > capacity()) {
435     u32 idx = ctx->clock_alloc.Alloc(c);
436     ClockBlock *cb = ctx->clock_alloc.Map(idx);
437     internal_memset(cb, 0, sizeof(*cb));
438     append_block(idx);
439   }
440   size_ = nclk;
441 }
442 
443 // Flushes all dirty elements into the main clock array.
FlushDirty()444 void SyncClock::FlushDirty() {
445   for (unsigned i = 0; i < kDirtyTids; i++) {
446     Dirty *dirty = &dirty_[i];
447     if (dirty->tid != kInvalidTid) {
448       CHECK_LT(dirty->tid, size_);
449       elem(dirty->tid).epoch = dirty->epoch;
450       dirty->tid = kInvalidTid;
451     }
452   }
453 }
454 
IsShared() const455 bool SyncClock::IsShared() const {
456   if (size_ == 0)
457     return false;
458   atomic_uint32_t *ref = ref_ptr(tab_);
459   u32 v = atomic_load(ref, memory_order_acquire);
460   CHECK_GT(v, 0);
461   return v > 1;
462 }
463 
464 // Unshares the current clock if it's shared.
465 // Shared clocks are immutable, so they need to be unshared before any updates.
466 // Note: this does not apply to dirty entries as they are not shared.
Unshare(ClockCache * c)467 void SyncClock::Unshare(ClockCache *c) {
468   if (!IsShared())
469     return;
470   // First, copy current state into old.
471   SyncClock old;
472   old.tab_ = tab_;
473   old.tab_idx_ = tab_idx_;
474   old.size_ = size_;
475   old.blocks_ = blocks_;
476   old.release_store_tid_ = release_store_tid_;
477   old.release_store_reused_ = release_store_reused_;
478   for (unsigned i = 0; i < kDirtyTids; i++)
479     old.dirty_[i] = dirty_[i];
480   // Then, clear current object.
481   ResetImpl();
482   // Allocate brand new clock in the current object.
483   Resize(c, old.size_);
484   // Now copy state back into this object.
485   Iter old_iter(&old);
486   for (ClockElem &ce : *this) {
487     ce = *old_iter;
488     ++old_iter;
489   }
490   release_store_tid_ = old.release_store_tid_;
491   release_store_reused_ = old.release_store_reused_;
492   for (unsigned i = 0; i < kDirtyTids; i++)
493     dirty_[i] = old.dirty_[i];
494   // Drop reference to old and delete if necessary.
495   old.Reset(c);
496 }
497 
498 // Can we cache this clock for future release operations?
Cachable() const499 ALWAYS_INLINE bool SyncClock::Cachable() const {
500   if (size_ == 0)
501     return false;
502   for (unsigned i = 0; i < kDirtyTids; i++) {
503     if (dirty_[i].tid != kInvalidTid)
504       return false;
505   }
506   return atomic_load_relaxed(ref_ptr(tab_)) == 1;
507 }
508 
509 // elem linearizes the two-level structure into linear array.
510 // Note: this is used only for one time accesses, vector operations use
511 // the iterator as it is much faster.
elem(unsigned tid) const512 ALWAYS_INLINE ClockElem &SyncClock::elem(unsigned tid) const {
513   DCHECK_LT(tid, size_);
514   const uptr block = tid / ClockBlock::kClockCount;
515   DCHECK_LE(block, blocks_);
516   tid %= ClockBlock::kClockCount;
517   if (block == blocks_)
518     return tab_->clock[tid];
519   u32 idx = get_block(block);
520   ClockBlock *cb = ctx->clock_alloc.Map(idx);
521   return cb->clock[tid];
522 }
523 
capacity() const524 ALWAYS_INLINE uptr SyncClock::capacity() const {
525   if (size_ == 0)
526     return 0;
527   uptr ratio = sizeof(ClockBlock::clock[0]) / sizeof(ClockBlock::table[0]);
528   // How many clock elements we can fit into the first level block.
529   // +1 for ref counter.
530   uptr top = ClockBlock::kClockCount - RoundUpTo(blocks_ + 1, ratio) / ratio;
531   return blocks_ * ClockBlock::kClockCount + top;
532 }
533 
get_block(uptr bi) const534 ALWAYS_INLINE u32 SyncClock::get_block(uptr bi) const {
535   DCHECK(size_);
536   DCHECK_LT(bi, blocks_);
537   return tab_->table[ClockBlock::kBlockIdx - bi];
538 }
539 
append_block(u32 idx)540 ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
541   uptr bi = blocks_++;
542   CHECK_EQ(get_block(bi), 0);
543   tab_->table[ClockBlock::kBlockIdx - bi] = idx;
544 }
545 
546 // Used only by tests.
get(unsigned tid) const547 u64 SyncClock::get(unsigned tid) const {
548   for (unsigned i = 0; i < kDirtyTids; i++) {
549     Dirty dirty = dirty_[i];
550     if (dirty.tid == tid)
551       return dirty.epoch;
552   }
553   return elem(tid).epoch;
554 }
555 
556 // Used only by Iter test.
get_clean(unsigned tid) const557 u64 SyncClock::get_clean(unsigned tid) const {
558   return elem(tid).epoch;
559 }
560 
DebugDump(int (* printf)(const char * s,...))561 void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
562   printf("clock=[");
563   for (uptr i = 0; i < size_; i++)
564     printf("%s%llu", i == 0 ? "" : ",", elem(i).epoch);
565   printf("] reused=[");
566   for (uptr i = 0; i < size_; i++)
567     printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
568   printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
569       release_store_tid_, release_store_reused_,
570       dirty_[0].tid, dirty_[0].epoch,
571       dirty_[1].tid, dirty_[1].epoch);
572 }
573 
Next()574 void SyncClock::Iter::Next() {
575   // Finished with the current block, move on to the next one.
576   block_++;
577   if (block_ < parent_->blocks_) {
578     // Iterate over the next second level block.
579     u32 idx = parent_->get_block(block_);
580     ClockBlock *cb = ctx->clock_alloc.Map(idx);
581     pos_ = &cb->clock[0];
582     end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount,
583         ClockBlock::kClockCount);
584     return;
585   }
586   if (block_ == parent_->blocks_ &&
587       parent_->size_ > parent_->blocks_ * ClockBlock::kClockCount) {
588     // Iterate over elements in the first level block.
589     pos_ = &parent_->tab_->clock[0];
590     end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount,
591         ClockBlock::kClockCount);
592     return;
593   }
594   parent_ = nullptr;  // denotes end
595 }
596 }  // namespace __tsan
597