1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/allocator/dispatcher/reentry_guard.h" 6 7 #include "base/check.h" 8 #include "base/compiler_specific.h" 9 #include "base/debug/crash_logging.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "build/build_config.h" 12 13 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) 14 #include <pthread.h> 15 #endif 16 17 namespace base::allocator::dispatcher { 18 19 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) 20 // pthread_key_t has different signedness on Mac and Android. Store the null 21 // value in a strongly-typed constant to avoid "comparison of integers of 22 // different signs" warnings when comparing with 0. 23 constexpr pthread_key_t kNullKey = 0; 24 25 pthread_key_t ReentryGuard::entered_key_ = kNullKey; 26 InitTLSSlot()27void ReentryGuard::InitTLSSlot() { 28 if (entered_key_ == kNullKey) { 29 int error = pthread_key_create(&entered_key_, nullptr); 30 CHECK(!error); 31 // Touch the TLS slot immediately to force any allocations. 32 // TODO(https://crbug.com/1411454): Use this technique to avoid allocations 33 // in PoissonAllocationSampler::ScopedMuteThreadSamples, which will make 34 // ReentryGuard redundant. 35 pthread_setspecific(entered_key_, nullptr); 36 } 37 38 DCHECK_NE(entered_key_, kNullKey); 39 } 40 41 #else 42 43 void ReentryGuard::InitTLSSlot() {} 44 45 #endif 46 RecordTLSSlotToCrashKey()47void ReentryGuard::RecordTLSSlotToCrashKey() { 48 // Record the key in crash dumps to detect when it's higher than 32 49 // (PTHREAD_KEY_2NDLEVEL_SIZE). 50 // TODO(crbug.com/1411454): Remove this after diagnosing reentry crashes. 51 static auto* const crash_key = base::debug::AllocateCrashKeyString( 52 "reentry_guard_tls_slot", base::debug::CrashKeySize::Size32); 53 54 #if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID) 55 base::debug::SetCrashKeyString(crash_key, base::NumberToString(entered_key_)); 56 #else 57 base::debug::SetCrashKeyString(crash_key, "unused"); 58 #endif 59 } 60 61 } // namespace base::allocator::dispatcher 62