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 static void initOnce() { 28 CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0); 29 initScudo(); 30 NumberOfTSDs = Min(Max(1U, GetNumberOfCPUsCached()), 31 static_cast<u32>(SCUDO_SHARED_TSD_POOL_SIZE)); 32 TSDs = reinterpret_cast<ScudoTSD *>( 33 MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs")); 34 for (u32 i = 0; i < NumberOfTSDs; i++) 35 TSDs[i].init(/*Shared=*/true); 36 } 37 38 ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) { 39 #if SANITIZER_ANDROID 40 *get_android_tls_ptr() = reinterpret_cast<uptr>(TSD); 41 #else 42 CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(TSD)), 0); 43 #endif // SANITIZER_ANDROID 44 } 45 46 void initThread(bool MinimalInit) { 47 pthread_once(&GlobalInitialized, initOnce); 48 // Initial context assignment is done in a plain round-robin fashion. 49 u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed); 50 setCurrentTSD(&TSDs[Index % NumberOfTSDs]); 51 } 52 53 ScudoTSD *getTSDAndLockSlow() { 54 ScudoTSD *TSD; 55 if (NumberOfTSDs > 1) { 56 // Go through all the contexts and find the first unlocked one. 57 for (u32 i = 0; i < NumberOfTSDs; i++) { 58 TSD = &TSDs[i]; 59 if (TSD->tryLock()) { 60 setCurrentTSD(TSD); 61 return TSD; 62 } 63 } 64 // No luck, find the one with the lowest Precedence, and slow lock it. 65 u64 LowestPrecedence = UINT64_MAX; 66 for (u32 i = 0; i < NumberOfTSDs; i++) { 67 u64 Precedence = TSDs[i].getPrecedence(); 68 if (Precedence && Precedence < LowestPrecedence) { 69 TSD = &TSDs[i]; 70 LowestPrecedence = Precedence; 71 } 72 } 73 if (LIKELY(LowestPrecedence != UINT64_MAX)) { 74 TSD->lock(); 75 setCurrentTSD(TSD); 76 return TSD; 77 } 78 } 79 // Last resort, stick with the current one. 80 TSD = getCurrentTSD(); 81 TSD->lock(); 82 return TSD; 83 } 84 85 } // namespace __scudo 86 87 #endif // !SCUDO_TSD_EXCLUSIVE 88