scudo_tsd_shared.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //===-- scudo_tsd_shared.cpp ------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// Scudo shared TSD implementation.
  10. ///
  11. //===----------------------------------------------------------------------===//
  12. #include "scudo_tsd.h"
  13. #if !SCUDO_TSD_EXCLUSIVE
  14. namespace __scudo {
  15. static pthread_once_t GlobalInitialized = PTHREAD_ONCE_INIT;
  16. pthread_key_t PThreadKey;
  17. static atomic_uint32_t CurrentIndex;
  18. static ScudoTSD *TSDs;
  19. static u32 NumberOfTSDs;
  20. static u32 CoPrimes[SCUDO_SHARED_TSD_POOL_SIZE];
  21. static u32 NumberOfCoPrimes = 0;
  22. #if SANITIZER_LINUX && !SANITIZER_ANDROID
  23. __attribute__((tls_model("initial-exec")))
  24. THREADLOCAL ScudoTSD *CurrentTSD;
  25. #endif
  26. static void initOnce() {
  27. CHECK_EQ(pthread_key_create(&PThreadKey, NULL), 0);
  28. initScudo();
  29. NumberOfTSDs = Min(Max(1U, GetNumberOfCPUsCached()),
  30. static_cast<u32>(SCUDO_SHARED_TSD_POOL_SIZE));
  31. TSDs = reinterpret_cast<ScudoTSD *>(
  32. MmapOrDie(sizeof(ScudoTSD) * NumberOfTSDs, "ScudoTSDs"));
  33. for (u32 I = 0; I < NumberOfTSDs; I++) {
  34. TSDs[I].init();
  35. u32 A = I + 1;
  36. u32 B = NumberOfTSDs;
  37. while (B != 0) { const u32 T = A; A = B; B = T % B; }
  38. if (A == 1)
  39. CoPrimes[NumberOfCoPrimes++] = I + 1;
  40. }
  41. }
  42. ALWAYS_INLINE void setCurrentTSD(ScudoTSD *TSD) {
  43. #if SANITIZER_ANDROID
  44. *get_android_tls_ptr() = reinterpret_cast<uptr>(TSD);
  45. #elif SANITIZER_LINUX
  46. CurrentTSD = TSD;
  47. #else
  48. CHECK_EQ(pthread_setspecific(PThreadKey, reinterpret_cast<void *>(TSD)), 0);
  49. #endif // SANITIZER_ANDROID
  50. }
  51. void initThread(bool MinimalInit) {
  52. pthread_once(&GlobalInitialized, initOnce);
  53. // Initial context assignment is done in a plain round-robin fashion.
  54. u32 Index = atomic_fetch_add(&CurrentIndex, 1, memory_order_relaxed);
  55. setCurrentTSD(&TSDs[Index % NumberOfTSDs]);
  56. }
  57. ScudoTSD *getTSDAndLockSlow(ScudoTSD *TSD) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
  58. if (NumberOfTSDs > 1) {
  59. // Use the Precedence of the current TSD as our random seed. Since we are in
  60. // the slow path, it means that tryLock failed, and as a result it's very
  61. // likely that said Precedence is non-zero.
  62. u32 RandState = static_cast<u32>(TSD->getPrecedence());
  63. const u32 R = Rand(&RandState);
  64. const u32 Inc = CoPrimes[R % NumberOfCoPrimes];
  65. u32 Index = R % NumberOfTSDs;
  66. uptr LowestPrecedence = UINTPTR_MAX;
  67. ScudoTSD *CandidateTSD = nullptr;
  68. // Go randomly through at most 4 contexts and find a candidate.
  69. for (u32 I = 0; I < Min(4U, NumberOfTSDs); I++) {
  70. if (TSDs[Index].tryLock()) {
  71. setCurrentTSD(&TSDs[Index]);
  72. return &TSDs[Index];
  73. }
  74. const uptr Precedence = TSDs[Index].getPrecedence();
  75. // A 0 precedence here means another thread just locked this TSD.
  76. if (Precedence && Precedence < LowestPrecedence) {
  77. CandidateTSD = &TSDs[Index];
  78. LowestPrecedence = Precedence;
  79. }
  80. Index += Inc;
  81. if (Index >= NumberOfTSDs)
  82. Index -= NumberOfTSDs;
  83. }
  84. if (CandidateTSD) {
  85. CandidateTSD->lock();
  86. setCurrentTSD(CandidateTSD);
  87. return CandidateTSD;
  88. }
  89. }
  90. // Last resort, stick with the current one.
  91. TSD->lock();
  92. return TSD;
  93. }
  94. } // namespace __scudo
  95. #endif // !SCUDO_TSD_EXCLUSIVE