tsan_clock.cpp 19 KB

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