]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/scudo/scudo_tsd_shared.cpp
Suppress excessive error prints in ENA TX hotpath
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / scudo / scudo_tsd_shared.cpp
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 static u32 CoPrimes[SCUDO_SHARED_TSD_POOL_SIZE];
27 static u32 NumberOfCoPrimes = 0;
28
29 #if SANITIZER_LINUX && !SANITIZER_ANDROID
30 __attribute__((tls_model("initial-exec")))
31 THREADLOCAL ScudoTSD *CurrentTSD;
32 #endif
33
34 static void initOnce() {
35   CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0);
36   initScudo();
37   NumberOfTSDs = Min(Max(1U, GetNumberOfCPUsCached()),
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();
43     u32 A = I + 1;
44     u32 B = NumberOfTSDs;
45     while (B != 0) { const u32 T = A; A = B; B = T % B; }
46     if (A == 1)
47       CoPrimes[NumberOfCoPrimes++] = I + 1;
48   }
49 }
50
51 ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) {
52 #if SANITIZER_ANDROID
53   *get_android_tls_ptr() = reinterpret_cast<uptr>(TSD);
54 #elif SANITIZER_LINUX
55   CurrentTSD = TSD;
56 #else
57   CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(TSD)), 0);
58 #endif  // SANITIZER_ANDROID
59 }
60
61 void initThread(bool MinimalInit) {
62   pthread_once(&GlobalInitialized, initOnce);
63   // Initial context assignment is done in a plain round-robin fashion.
64   u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed);
65   setCurrentTSD(&TSDs[Index % NumberOfTSDs]);
66 }
67
68 ScudoTSD *getTSDAndLockSlow(ScudoTSD *TSD) {
69   if (NumberOfTSDs > 1) {
70     // Use the Precedence of the current TSD as our random seed. Since we are in
71     // the slow path, it means that tryLock failed, and as a result it's very
72     // likely that said Precedence is non-zero.
73     u32 RandState = static_cast<u32>(TSD->getPrecedence());
74     const u32 R = Rand(&RandState);
75     const u32 Inc = CoPrimes[R % NumberOfCoPrimes];
76     u32 Index = R % NumberOfTSDs;
77     uptr LowestPrecedence = UINTPTR_MAX;
78     ScudoTSD *CandidateTSD = nullptr;
79     // Go randomly through at most 4 contexts and find a candidate.
80     for (u32 I = 0; I < Min(4U, NumberOfTSDs); I++) {
81       if (TSDs[Index].tryLock()) {
82         setCurrentTSD(&TSDs[Index]);
83         return &TSDs[Index];
84       }
85       const uptr Precedence = TSDs[Index].getPrecedence();
86       // A 0 precedence here means another thread just locked this TSD.
87       if (UNLIKELY(Precedence == 0))
88         continue;
89       if (Precedence < LowestPrecedence) {
90         CandidateTSD = &TSDs[Index];
91         LowestPrecedence = Precedence;
92       }
93       Index += Inc;
94       if (Index >= NumberOfTSDs)
95         Index -= NumberOfTSDs;
96     }
97     if (CandidateTSD) {
98       CandidateTSD->lock();
99       setCurrentTSD(CandidateTSD);
100       return CandidateTSD;
101     }
102   }
103   // Last resort, stick with the current one.
104   TSD->lock();
105   return TSD;
106 }
107
108 }  // namespace __scudo
109
110 #endif  // !SCUDO_TSD_EXCLUSIVE