1 //===-- tsan_sync.h ---------------------------------------------*- C++ -*-===// 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 #ifndef TSAN_SYNC_H 13 #define TSAN_SYNC_H 14 15 #include "sanitizer_common/sanitizer_atomic.h" 16 #include "sanitizer_common/sanitizer_common.h" 17 #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" 18 #include "tsan_defs.h" 19 #include "tsan_dense_alloc.h" 20 #include "tsan_shadow.h" 21 #include "tsan_vector_clock.h" 22 23 namespace __tsan { 24 25 // These need to match __tsan_mutex_* flags defined in tsan_interface.h. 26 // See documentation there as well. 27 enum MutexFlags { 28 MutexFlagLinkerInit = 1 << 0, // __tsan_mutex_linker_init 29 MutexFlagWriteReentrant = 1 << 1, // __tsan_mutex_write_reentrant 30 MutexFlagReadReentrant = 1 << 2, // __tsan_mutex_read_reentrant 31 MutexFlagReadLock = 1 << 3, // __tsan_mutex_read_lock 32 MutexFlagTryLock = 1 << 4, // __tsan_mutex_try_lock 33 MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed 34 MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock 35 MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock 36 MutexFlagNotStatic = 1 << 8, // __tsan_mutex_not_static 37 38 // The following flags are runtime private. 39 // Mutex API misuse was detected, so don't report any more. 40 MutexFlagBroken = 1 << 30, 41 // We did not intercept pre lock event, so handle it on post lock. 42 MutexFlagDoPreLockOnPostLock = 1 << 29, 43 // Must list all mutex creation flags. 44 MutexCreationFlagMask = MutexFlagLinkerInit | 45 MutexFlagWriteReentrant | 46 MutexFlagReadReentrant | 47 MutexFlagNotStatic, 48 }; 49 50 // SyncVar is a descriptor of a user synchronization object 51 // (mutex or an atomic variable). 52 struct SyncVar { 53 SyncVar(); 54 55 uptr addr; // overwritten by DenseSlabAlloc freelist 56 Mutex mtx; 57 StackID creation_stack_id; 58 Tid owner_tid; // Set only by exclusive owners. 59 FastState last_lock; 60 int recursion; 61 atomic_uint32_t flags; 62 u32 next; // in MetaMap 63 DDMutex dd; 64 VectorClock *read_clock; // Used for rw mutexes only. 65 VectorClock *clock; 66 67 void Init(ThreadState *thr, uptr pc, uptr addr, bool save_stack); 68 void Reset(); 69 IsFlagSetSyncVar70 bool IsFlagSet(u32 f) const { 71 return atomic_load_relaxed(&flags) & f; 72 } 73 SetFlagsSyncVar74 void SetFlags(u32 f) { 75 atomic_store_relaxed(&flags, atomic_load_relaxed(&flags) | f); 76 } 77 UpdateFlagsSyncVar78 void UpdateFlags(u32 flagz) { 79 // Filter out operation flags. 80 if (!(flagz & MutexCreationFlagMask)) 81 return; 82 u32 current = atomic_load_relaxed(&flags); 83 if (current & MutexCreationFlagMask) 84 return; 85 // Note: this can be called from MutexPostReadLock which holds only read 86 // lock on the SyncVar. 87 atomic_store_relaxed(&flags, current | (flagz & MutexCreationFlagMask)); 88 } 89 }; 90 91 // MetaMap maps app addresses to heap block (MBlock) and sync var (SyncVar) 92 // descriptors. It uses 1/2 direct shadow, see tsan_platform.h for the mapping. 93 class MetaMap { 94 public: 95 MetaMap(); 96 97 void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz); 98 99 // FreeBlock resets all sync objects in the range if reset=true and must not 100 // run concurrently with ResetClocks which resets all sync objects 101 // w/o any synchronization (as part of DoReset). 102 // If we don't have a thread slot (very early/late in thread lifetime or 103 // Go/Java callbacks) or the slot is not locked, then reset must be set to 104 // false. In such case sync object clocks will be reset later (when it's 105 // reused or during the next ResetClocks). 106 uptr FreeBlock(Processor *proc, uptr p, bool reset); 107 bool FreeRange(Processor *proc, uptr p, uptr sz, bool reset); 108 void ResetRange(Processor *proc, uptr p, uptr sz, bool reset); 109 // Reset vector clocks of all sync objects. 110 // Must be called when no other threads access sync objects. 111 void ResetClocks(); 112 MBlock* GetBlock(uptr p); 113 GetSyncOrCreate(ThreadState * thr,uptr pc,uptr addr,bool save_stack)114 SyncVar *GetSyncOrCreate(ThreadState *thr, uptr pc, uptr addr, 115 bool save_stack) { 116 return GetSync(thr, pc, addr, true, save_stack); 117 } GetSyncIfExists(uptr addr)118 SyncVar *GetSyncIfExists(uptr addr) { 119 return GetSync(nullptr, 0, addr, false, false); 120 } 121 122 void MoveMemory(uptr src, uptr dst, uptr sz); 123 124 void OnProcIdle(Processor *proc); 125 126 struct MemoryStats { 127 uptr mem_block; 128 uptr sync_obj; 129 }; 130 131 MemoryStats GetMemoryStats() const; 132 133 private: 134 static const u32 kFlagMask = 3u << 30; 135 static const u32 kFlagBlock = 1u << 30; 136 static const u32 kFlagSync = 2u << 30; 137 typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc; 138 typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc; 139 BlockAlloc block_alloc_; 140 SyncAlloc sync_alloc_; 141 142 SyncVar *GetSync(ThreadState *thr, uptr pc, uptr addr, bool create, 143 bool save_stack); 144 }; 145 146 } // namespace __tsan 147 148 #endif // TSAN_SYNC_H 149