tsan_clock.h revision 1.1.1.4
1//===-- tsan_clock.h --------------------------------------------*- C++ -*-===// 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#ifndef TSAN_CLOCK_H 12#define TSAN_CLOCK_H 13 14#include "tsan_defs.h" 15#include "tsan_dense_alloc.h" 16 17namespace __tsan { 18 19struct ClockElem { 20 u64 epoch : kClkBits; 21 u64 reused : 64 - kClkBits; 22}; 23 24struct ClockBlock { 25 static const uptr kSize = 512; 26 static const uptr kTableSize = kSize / sizeof(u32); 27 static const uptr kClockCount = kSize / sizeof(ClockElem); 28 29 union { 30 u32 table[kTableSize]; 31 ClockElem clock[kClockCount]; 32 }; 33 34 ClockBlock() { 35 } 36}; 37 38typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc; 39typedef DenseSlabAllocCache ClockCache; 40 41// The clock that lives in sync variables (mutexes, atomics, etc). 42class SyncClock { 43 public: 44 SyncClock(); 45 ~SyncClock(); 46 47 uptr size() const { 48 return size_; 49 } 50 51 u64 get(unsigned tid) const { 52 return elem(tid).epoch; 53 } 54 55 void Resize(ClockCache *c, uptr nclk); 56 void Reset(ClockCache *c); 57 58 void DebugDump(int(*printf)(const char *s, ...)); 59 60 private: 61 friend struct ThreadClock; 62 static const uptr kDirtyTids = 2; 63 64 unsigned release_store_tid_; 65 unsigned release_store_reused_; 66 unsigned dirty_tids_[kDirtyTids]; 67 // tab_ contains indirect pointer to a 512b block using DenseSlabAlloc. 68 // If size_ <= 64, then tab_ points to an array with 64 ClockElem's. 69 // Otherwise, tab_ points to an array with 128 u32 elements, 70 // each pointing to the second-level 512b block with 64 ClockElem's. 71 ClockBlock *tab_; 72 u32 tab_idx_; 73 u32 size_; 74 75 ClockElem &elem(unsigned tid) const; 76}; 77 78// The clock that lives in threads. 79struct ThreadClock { 80 public: 81 typedef DenseSlabAllocCache Cache; 82 83 explicit ThreadClock(unsigned tid, unsigned reused = 0); 84 85 u64 get(unsigned tid) const { 86 DCHECK_LT(tid, kMaxTidInClock); 87 return clk_[tid].epoch; 88 } 89 90 void set(unsigned tid, u64 v); 91 92 void set(u64 v) { 93 DCHECK_GE(v, clk_[tid_].epoch); 94 clk_[tid_].epoch = v; 95 } 96 97 void tick() { 98 clk_[tid_].epoch++; 99 } 100 101 uptr size() const { 102 return nclk_; 103 } 104 105 void acquire(ClockCache *c, const SyncClock *src); 106 void release(ClockCache *c, SyncClock *dst) const; 107 void acq_rel(ClockCache *c, SyncClock *dst); 108 void ReleaseStore(ClockCache *c, SyncClock *dst) const; 109 110 void DebugReset(); 111 void DebugDump(int(*printf)(const char *s, ...)); 112 113 private: 114 static const uptr kDirtyTids = SyncClock::kDirtyTids; 115 const unsigned tid_; 116 const unsigned reused_; 117 u64 last_acquire_; 118 uptr nclk_; 119 ClockElem clk_[kMaxTidInClock]; 120 121 bool IsAlreadyAcquired(const SyncClock *src) const; 122 void UpdateCurrentThread(SyncClock *dst) const; 123}; 124 125} // namespace __tsan 126 127#endif // TSAN_CLOCK_H 128