1 //===-- tsan_sync.h ---------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of ThreadSanitizer (TSan), a race detector. 11 // 12 //===----------------------------------------------------------------------===// 13 #ifndef TSAN_SYNC_H 14 #define TSAN_SYNC_H 15 16 #include "sanitizer_common/sanitizer_atomic.h" 17 #include "sanitizer_common/sanitizer_common.h" 18 #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" 19 #include "tsan_defs.h" 20 #include "tsan_clock.h" 21 #include "tsan_mutex.h" 22 #include "tsan_dense_alloc.h" 23 24 namespace __tsan { 25 26 struct SyncVar { 27 SyncVar(); 28 29 static const int kInvalidTid = -1; 30 31 uptr addr; // overwritten by DenseSlabAlloc freelist 32 Mutex mtx; 33 u64 uid; // Globally unique id. 34 u32 creation_stack_id; 35 int owner_tid; // Set only by exclusive owners. 36 u64 last_lock; 37 int recursion; 38 bool is_rw; 39 bool is_recursive; 40 bool is_broken; 41 bool is_linker_init; 42 u32 next; // in MetaMap 43 DDMutex dd; 44 SyncClock read_clock; // Used for rw mutexes only. 45 // The clock is placed last, so that it is situated on a different cache line 46 // with the mtx. This reduces contention for hot sync objects. 47 SyncClock clock; 48 49 void Init(ThreadState *thr, uptr pc, uptr addr, u64 uid); 50 void Reset(); 51 GetIdSyncVar52 u64 GetId() const { 53 // 47 lsb is addr, then 14 bits is low part of uid, then 3 zero bits. 54 return GetLsb((u64)addr | (uid << 47), 61); 55 } CheckIdSyncVar56 bool CheckId(u64 uid) const { 57 CHECK_EQ(uid, GetLsb(uid, 14)); 58 return GetLsb(this->uid, 14) == uid; 59 } SplitIdSyncVar60 static uptr SplitId(u64 id, u64 *uid) { 61 *uid = id >> 47; 62 return (uptr)GetLsb(id, 47); 63 } 64 }; 65 66 /* MetaMap allows to map arbitrary user pointers onto various descriptors. 67 Currently it maps pointers to heap block descriptors and sync var descs. 68 It uses 1/2 direct shadow, see tsan_platform.h. 69 */ 70 class MetaMap { 71 public: 72 MetaMap(); 73 74 void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz); 75 uptr FreeBlock(ThreadState *thr, uptr pc, uptr p); 76 void FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz); 77 MBlock* GetBlock(uptr p); 78 79 SyncVar* GetOrCreateAndLock(ThreadState *thr, uptr pc, 80 uptr addr, bool write_lock); 81 SyncVar* GetIfExistsAndLock(uptr addr); 82 83 void MoveMemory(uptr src, uptr dst, uptr sz); 84 85 void OnThreadIdle(ThreadState *thr); 86 87 private: 88 static const u32 kFlagMask = 3 << 30; 89 static const u32 kFlagBlock = 1 << 30; 90 static const u32 kFlagSync = 2 << 30; 91 typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc; 92 typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc; 93 BlockAlloc block_alloc_; 94 SyncAlloc sync_alloc_; 95 atomic_uint64_t uid_gen_; 96 97 SyncVar* GetAndLock(ThreadState *thr, uptr pc, uptr addr, bool write_lock, 98 bool create); 99 }; 100 101 } // namespace __tsan 102 103 #endif // TSAN_SYNC_H 104