10b57cec5SDimitry Andric //===-- tsan_sync.h ---------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric #ifndef TSAN_SYNC_H 130b57cec5SDimitry Andric #define TSAN_SYNC_H 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_atomic.h" 160b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 170b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_deadlock_detector_interface.h" 180b57cec5SDimitry Andric #include "tsan_defs.h" 190b57cec5SDimitry Andric #include "tsan_dense_alloc.h" 20*0eae32dcSDimitry Andric #include "tsan_shadow.h" 21*0eae32dcSDimitry Andric #include "tsan_vector_clock.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric namespace __tsan { 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric // These need to match __tsan_mutex_* flags defined in tsan_interface.h. 260b57cec5SDimitry Andric // See documentation there as well. 270b57cec5SDimitry Andric enum MutexFlags { 280b57cec5SDimitry Andric MutexFlagLinkerInit = 1 << 0, // __tsan_mutex_linker_init 290b57cec5SDimitry Andric MutexFlagWriteReentrant = 1 << 1, // __tsan_mutex_write_reentrant 300b57cec5SDimitry Andric MutexFlagReadReentrant = 1 << 2, // __tsan_mutex_read_reentrant 310b57cec5SDimitry Andric MutexFlagReadLock = 1 << 3, // __tsan_mutex_read_lock 320b57cec5SDimitry Andric MutexFlagTryLock = 1 << 4, // __tsan_mutex_try_lock 330b57cec5SDimitry Andric MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed 340b57cec5SDimitry Andric MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock 350b57cec5SDimitry Andric MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock 360b57cec5SDimitry Andric MutexFlagNotStatic = 1 << 8, // __tsan_mutex_not_static 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric // The following flags are runtime private. 390b57cec5SDimitry Andric // Mutex API misuse was detected, so don't report any more. 400b57cec5SDimitry Andric MutexFlagBroken = 1 << 30, 410b57cec5SDimitry Andric // We did not intercept pre lock event, so handle it on post lock. 420b57cec5SDimitry Andric MutexFlagDoPreLockOnPostLock = 1 << 29, 430b57cec5SDimitry Andric // Must list all mutex creation flags. 440b57cec5SDimitry Andric MutexCreationFlagMask = MutexFlagLinkerInit | 450b57cec5SDimitry Andric MutexFlagWriteReentrant | 460b57cec5SDimitry Andric MutexFlagReadReentrant | 470b57cec5SDimitry Andric MutexFlagNotStatic, 480b57cec5SDimitry Andric }; 490b57cec5SDimitry Andric 50349cc55cSDimitry Andric // SyncVar is a descriptor of a user synchronization object 51349cc55cSDimitry Andric // (mutex or an atomic variable). 520b57cec5SDimitry Andric struct SyncVar { 530b57cec5SDimitry Andric SyncVar(); 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric uptr addr; // overwritten by DenseSlabAlloc freelist 560b57cec5SDimitry Andric Mutex mtx; 57349cc55cSDimitry Andric StackID creation_stack_id; 58349cc55cSDimitry Andric Tid owner_tid; // Set only by exclusive owners. 59*0eae32dcSDimitry Andric FastState last_lock; 600b57cec5SDimitry Andric int recursion; 610b57cec5SDimitry Andric atomic_uint32_t flags; 620b57cec5SDimitry Andric u32 next; // in MetaMap 630b57cec5SDimitry Andric DDMutex dd; 64*0eae32dcSDimitry Andric VectorClock *read_clock; // Used for rw mutexes only. 65*0eae32dcSDimitry Andric VectorClock *clock; 660b57cec5SDimitry Andric 67*0eae32dcSDimitry Andric void Init(ThreadState *thr, uptr pc, uptr addr, bool save_stack); 68*0eae32dcSDimitry Andric void Reset(); 690b57cec5SDimitry Andric IsFlagSetSyncVar700b57cec5SDimitry Andric bool IsFlagSet(u32 f) const { 710b57cec5SDimitry Andric return atomic_load_relaxed(&flags) & f; 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric SetFlagsSyncVar740b57cec5SDimitry Andric void SetFlags(u32 f) { 750b57cec5SDimitry Andric atomic_store_relaxed(&flags, atomic_load_relaxed(&flags) | f); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric UpdateFlagsSyncVar780b57cec5SDimitry Andric void UpdateFlags(u32 flagz) { 790b57cec5SDimitry Andric // Filter out operation flags. 800b57cec5SDimitry Andric if (!(flagz & MutexCreationFlagMask)) 810b57cec5SDimitry Andric return; 820b57cec5SDimitry Andric u32 current = atomic_load_relaxed(&flags); 830b57cec5SDimitry Andric if (current & MutexCreationFlagMask) 840b57cec5SDimitry Andric return; 850b57cec5SDimitry Andric // Note: this can be called from MutexPostReadLock which holds only read 860b57cec5SDimitry Andric // lock on the SyncVar. 870b57cec5SDimitry Andric atomic_store_relaxed(&flags, current | (flagz & MutexCreationFlagMask)); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric }; 900b57cec5SDimitry Andric 91349cc55cSDimitry Andric // MetaMap maps app addresses to heap block (MBlock) and sync var (SyncVar) 92349cc55cSDimitry Andric // descriptors. It uses 1/2 direct shadow, see tsan_platform.h for the mapping. 930b57cec5SDimitry Andric class MetaMap { 940b57cec5SDimitry Andric public: 950b57cec5SDimitry Andric MetaMap(); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric void AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz); 98*0eae32dcSDimitry Andric 99*0eae32dcSDimitry Andric // FreeBlock resets all sync objects in the range if reset=true and must not 100*0eae32dcSDimitry Andric // run concurrently with ResetClocks which resets all sync objects 101*0eae32dcSDimitry Andric // w/o any synchronization (as part of DoReset). 102*0eae32dcSDimitry Andric // If we don't have a thread slot (very early/late in thread lifetime or 103*0eae32dcSDimitry Andric // Go/Java callbacks) or the slot is not locked, then reset must be set to 104*0eae32dcSDimitry Andric // false. In such case sync object clocks will be reset later (when it's 105*0eae32dcSDimitry Andric // reused or during the next ResetClocks). 106*0eae32dcSDimitry Andric uptr FreeBlock(Processor *proc, uptr p, bool reset); 107*0eae32dcSDimitry Andric bool FreeRange(Processor *proc, uptr p, uptr sz, bool reset); 108*0eae32dcSDimitry Andric void ResetRange(Processor *proc, uptr p, uptr sz, bool reset); 109*0eae32dcSDimitry Andric // Reset vector clocks of all sync objects. 110*0eae32dcSDimitry Andric // Must be called when no other threads access sync objects. 111*0eae32dcSDimitry Andric void ResetClocks(); 1120b57cec5SDimitry Andric MBlock* GetBlock(uptr p); 1130b57cec5SDimitry Andric GetSyncOrCreate(ThreadState * thr,uptr pc,uptr addr,bool save_stack)114349cc55cSDimitry Andric SyncVar *GetSyncOrCreate(ThreadState *thr, uptr pc, uptr addr, 115349cc55cSDimitry Andric bool save_stack) { 116349cc55cSDimitry Andric return GetSync(thr, pc, addr, true, save_stack); 117349cc55cSDimitry Andric } GetSyncIfExists(uptr addr)118349cc55cSDimitry Andric SyncVar *GetSyncIfExists(uptr addr) { 119349cc55cSDimitry Andric return GetSync(nullptr, 0, addr, false, false); 120349cc55cSDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric void MoveMemory(uptr src, uptr dst, uptr sz); 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric void OnProcIdle(Processor *proc); 1250b57cec5SDimitry Andric 126349cc55cSDimitry Andric struct MemoryStats { 127349cc55cSDimitry Andric uptr mem_block; 128349cc55cSDimitry Andric uptr sync_obj; 129349cc55cSDimitry Andric }; 130349cc55cSDimitry Andric 131349cc55cSDimitry Andric MemoryStats GetMemoryStats() const; 132349cc55cSDimitry Andric 1330b57cec5SDimitry Andric private: 1340b57cec5SDimitry Andric static const u32 kFlagMask = 3u << 30; 1350b57cec5SDimitry Andric static const u32 kFlagBlock = 1u << 30; 1360b57cec5SDimitry Andric static const u32 kFlagSync = 2u << 30; 137fe6060f1SDimitry Andric typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc; 138fe6060f1SDimitry Andric typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc; 1390b57cec5SDimitry Andric BlockAlloc block_alloc_; 1400b57cec5SDimitry Andric SyncAlloc sync_alloc_; 1410b57cec5SDimitry Andric 142349cc55cSDimitry Andric SyncVar *GetSync(ThreadState *thr, uptr pc, uptr addr, bool create, 143349cc55cSDimitry Andric bool save_stack); 1440b57cec5SDimitry Andric }; 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric } // namespace __tsan 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric #endif // TSAN_SYNC_H 149