1 //===-- scudo_tsd_shared.cpp ------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// Scudo shared TSD implementation. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "scudo_tsd.h" 15 16 #if !SCUDO_TSD_EXCLUSIVE 17 18 namespace __scudo { 19 20 static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT; 21 pthread_key_t PThreadKey; 22 23 static atomic_uint32_t CurrentIndex; 24 static ScudoTSD *TSDs; 25 static u32 NumberOfTSDs; 26 27 // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used as they allocate memory. 28 static u32 getNumberOfCPUs() { 29 cpu_set_t CPUs; 30 CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); 31 return CPU_COUNT(&CPUs); 32 } 33 34 static void initOnce() { 35 CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); 36 initScudo(); 37 NumberOfTSDs = Min(Max(1U, getNumberOfCPUs()), 38 static_cast<u32>(SCUDO_SHARED_TSD_POOL_SIZE)); 39 TSDs = reinterpret_cast<ScudoTSD *>( 40 MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); 41 for (u32 i = 0; i < NumberOfTSDs; i++) 42 TSDs[i].init(/*Shared=*/true); 43 } 44 45 ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) { 46 #if SANITIZER_ANDROID 47 *get_android_tls_ptr() = reinterpret_cast<uptr>(TSD); 48 #else 49 CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(TSD)), 0); 50 #endif // SANITIZER_ANDROID 51 } 52 53 void initThread(bool MinimalInit) { 54 pthread_once(&GlobalInitialized, initOnce); 55 // Initial context assignment is done in a plain round-robin fashion. 56 u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); 57 setCurrentTSD(&TSDs[Index % NumberOfTSDs]); 58 } 59 60 ScudoTSD *getTSDAndLockSlow() { 61 ScudoTSD *TSD; 62 if (NumberOfTSDs > 1) { 63 // Go through all the contexts and find the first unlocked one. 64 for (u32 i = 0; i < NumberOfTSDs; i++) { 65 TSD = &TSDs[i]; 66 if (TSD->tryLock()) { 67 setCurrentTSD(TSD); 68 return TSD; 69 } 70 } 71 // No luck, find the one with the lowest Precedence, and slow lock it. 72 u64 LowestPrecedence = UINT64_MAX; 73 for (u32 i = 0; i < NumberOfTSDs; i++) { 74 u64 Precedence = TSDs[i].getPrecedence(); 75 if (Precedence && Precedence < LowestPrecedence) { 76 TSD = &TSDs[i]; 77 LowestPrecedence = Precedence; 78 } 79 } 80 if (LIKELY(LowestPrecedence != UINT64_MAX)) { 81 TSD->lock(); 82 setCurrentTSD(TSD); 83 return TSD; 84 } 85 } 86 // Last resort, stick with the current one. 87 TSD = getCurrentTSD(); 88 TSD->lock(); 89 return TSD; 90 } 91 92 } // namespace __scudo 93 94 #endif // !SCUDO_TSD_EXCLUSIVE 95