1*76559068SAndroid Build Coastguard Worker //===-- tsd.h ---------------------------------------------------*- C++ -*-===// 2*76559068SAndroid Build Coastguard Worker // 3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*76559068SAndroid Build Coastguard Worker // 7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*76559068SAndroid Build Coastguard Worker 9*76559068SAndroid Build Coastguard Worker #ifndef SCUDO_TSD_H_ 10*76559068SAndroid Build Coastguard Worker #define SCUDO_TSD_H_ 11*76559068SAndroid Build Coastguard Worker 12*76559068SAndroid Build Coastguard Worker #include "atomic_helpers.h" 13*76559068SAndroid Build Coastguard Worker #include "common.h" 14*76559068SAndroid Build Coastguard Worker #include "mutex.h" 15*76559068SAndroid Build Coastguard Worker #include "thread_annotations.h" 16*76559068SAndroid Build Coastguard Worker 17*76559068SAndroid Build Coastguard Worker #include <limits.h> // for PTHREAD_DESTRUCTOR_ITERATIONS 18*76559068SAndroid Build Coastguard Worker #include <pthread.h> 19*76559068SAndroid Build Coastguard Worker 20*76559068SAndroid Build Coastguard Worker // With some build setups, this might still not be defined. 21*76559068SAndroid Build Coastguard Worker #ifndef PTHREAD_DESTRUCTOR_ITERATIONS 22*76559068SAndroid Build Coastguard Worker #define PTHREAD_DESTRUCTOR_ITERATIONS 4 23*76559068SAndroid Build Coastguard Worker #endif 24*76559068SAndroid Build Coastguard Worker 25*76559068SAndroid Build Coastguard Worker namespace scudo { 26*76559068SAndroid Build Coastguard Worker 27*76559068SAndroid Build Coastguard Worker template <class Allocator> struct alignas(SCUDO_CACHE_LINE_SIZE) TSD { 28*76559068SAndroid Build Coastguard Worker using ThisT = TSD<Allocator>; 29*76559068SAndroid Build Coastguard Worker u8 DestructorIterations = 0; 30*76559068SAndroid Build Coastguard Worker initTSD31*76559068SAndroid Build Coastguard Worker void init(Allocator *Instance) NO_THREAD_SAFETY_ANALYSIS { 32*76559068SAndroid Build Coastguard Worker DCHECK_EQ(DestructorIterations, 0U); 33*76559068SAndroid Build Coastguard Worker DCHECK(isAligned(reinterpret_cast<uptr>(this), alignof(ThisT))); 34*76559068SAndroid Build Coastguard Worker Instance->initCache(&Cache); 35*76559068SAndroid Build Coastguard Worker DestructorIterations = PTHREAD_DESTRUCTOR_ITERATIONS; 36*76559068SAndroid Build Coastguard Worker } 37*76559068SAndroid Build Coastguard Worker tryLockTSD38*76559068SAndroid Build Coastguard Worker inline bool tryLock() NO_THREAD_SAFETY_ANALYSIS { 39*76559068SAndroid Build Coastguard Worker if (Mutex.tryLock()) { 40*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(&Precedence, 0); 41*76559068SAndroid Build Coastguard Worker return true; 42*76559068SAndroid Build Coastguard Worker } 43*76559068SAndroid Build Coastguard Worker if (atomic_load_relaxed(&Precedence) == 0) 44*76559068SAndroid Build Coastguard Worker atomic_store_relaxed( 45*76559068SAndroid Build Coastguard Worker &Precedence, 46*76559068SAndroid Build Coastguard Worker static_cast<uptr>(getMonotonicTime() >> FIRST_32_SECOND_64(16, 0))); 47*76559068SAndroid Build Coastguard Worker return false; 48*76559068SAndroid Build Coastguard Worker } lockTSD49*76559068SAndroid Build Coastguard Worker inline void lock() NO_THREAD_SAFETY_ANALYSIS { 50*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(&Precedence, 0); 51*76559068SAndroid Build Coastguard Worker Mutex.lock(); 52*76559068SAndroid Build Coastguard Worker } unlockTSD53*76559068SAndroid Build Coastguard Worker inline void unlock() NO_THREAD_SAFETY_ANALYSIS { Mutex.unlock(); } getPrecedenceTSD54*76559068SAndroid Build Coastguard Worker inline uptr getPrecedence() { return atomic_load_relaxed(&Precedence); } 55*76559068SAndroid Build Coastguard Worker commitBackTSD56*76559068SAndroid Build Coastguard Worker void commitBack(Allocator *Instance) { Instance->commitBack(this); } 57*76559068SAndroid Build Coastguard Worker 58*76559068SAndroid Build Coastguard Worker // As the comments attached to `getCache()`, the TSD doesn't always need to be 59*76559068SAndroid Build Coastguard Worker // locked. In that case, we would only skip the check before we have all TSDs 60*76559068SAndroid Build Coastguard Worker // locked in all paths. assertLockedTSD61*76559068SAndroid Build Coastguard Worker void assertLocked(bool BypassCheck) ASSERT_CAPABILITY(Mutex) { 62*76559068SAndroid Build Coastguard Worker if (SCUDO_DEBUG && !BypassCheck) 63*76559068SAndroid Build Coastguard Worker Mutex.assertHeld(); 64*76559068SAndroid Build Coastguard Worker } 65*76559068SAndroid Build Coastguard Worker 66*76559068SAndroid Build Coastguard Worker // Ideally, we may want to assert that all the operations on 67*76559068SAndroid Build Coastguard Worker // Cache/QuarantineCache always have the `Mutex` acquired. However, the 68*76559068SAndroid Build Coastguard Worker // current architecture of accessing TSD is not easy to cooperate with the 69*76559068SAndroid Build Coastguard Worker // thread-safety analysis because of pointer aliasing. So now we just add the 70*76559068SAndroid Build Coastguard Worker // assertion on the getters of Cache/QuarantineCache. 71*76559068SAndroid Build Coastguard Worker // 72*76559068SAndroid Build Coastguard Worker // TODO(chiahungduan): Ideally, we want to do `Mutex.assertHeld` but acquiring 73*76559068SAndroid Build Coastguard Worker // TSD doesn't always require holding the lock. Add this assertion while the 74*76559068SAndroid Build Coastguard Worker // lock is always acquired. getCacheTSD75*76559068SAndroid Build Coastguard Worker typename Allocator::CacheT &getCache() REQUIRES(Mutex) { return Cache; } getQuarantineCacheTSD76*76559068SAndroid Build Coastguard Worker typename Allocator::QuarantineCacheT &getQuarantineCache() REQUIRES(Mutex) { 77*76559068SAndroid Build Coastguard Worker return QuarantineCache; 78*76559068SAndroid Build Coastguard Worker } 79*76559068SAndroid Build Coastguard Worker 80*76559068SAndroid Build Coastguard Worker private: 81*76559068SAndroid Build Coastguard Worker HybridMutex Mutex; 82*76559068SAndroid Build Coastguard Worker atomic_uptr Precedence = {}; 83*76559068SAndroid Build Coastguard Worker 84*76559068SAndroid Build Coastguard Worker typename Allocator::CacheT Cache GUARDED_BY(Mutex); 85*76559068SAndroid Build Coastguard Worker typename Allocator::QuarantineCacheT QuarantineCache GUARDED_BY(Mutex); 86*76559068SAndroid Build Coastguard Worker }; 87*76559068SAndroid Build Coastguard Worker 88*76559068SAndroid Build Coastguard Worker } // namespace scudo 89*76559068SAndroid Build Coastguard Worker 90*76559068SAndroid Build Coastguard Worker #endif // SCUDO_TSD_H_ 91