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 | |