| 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 | |
| 70 | bool IsFlagSet(u32 f) const { |
| 71 | return atomic_load_relaxed(a: &flags) & f; |
| 72 | } |
| 73 | |
| 74 | void SetFlags(u32 f) { |
| 75 | atomic_store_relaxed(a: &flags, v: atomic_load_relaxed(a: &flags) | f); |
| 76 | } |
| 77 | |
| 78 | void UpdateFlags(u32 flagz) { |
| 79 | // Filter out operation flags. |
| 80 | if (!(flagz & MutexCreationFlagMask)) |
| 81 | return; |
| 82 | u32 current = atomic_load_relaxed(a: &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(a: &flags, v: 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 | |
| 114 | SyncVar *GetSyncOrCreate(ThreadState *thr, uptr pc, uptr addr, |
| 115 | bool save_stack) { |
| 116 | return GetSync(thr, pc, addr, create: true, save_stack); |
| 117 | } |
| 118 | SyncVar *GetSyncIfExists(uptr addr) { |
| 119 | return GetSync(thr: nullptr, pc: 0, addr, create: false, save_stack: 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 | |