]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/scudo/scudo_tsd_shared.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ release_60 r321788,
[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
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