xref: /aosp_15_r20/external/cronet/base/allocator/dispatcher/tls.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/tls.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <string_view>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #if USE_LOCAL_TLS_EMULATION()
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/dcheck_is_on.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/debug/crash_logging.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/immediate_crash.h"
15*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #include <sys/mman.h>
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
20*6777b538SAndroid Build Coastguard Worker #include <sys/prctl.h>
21*6777b538SAndroid Build Coastguard Worker #endif
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace base::allocator::dispatcher::internal {
24*6777b538SAndroid Build Coastguard Worker namespace {
GetCrashKeySize(const std::string & crash_key_name)25*6777b538SAndroid Build Coastguard Worker base::debug::CrashKeySize GetCrashKeySize(const std::string& crash_key_name) {
26*6777b538SAndroid Build Coastguard Worker   if (std::size(crash_key_name) <= 32ul) {
27*6777b538SAndroid Build Coastguard Worker     return base::debug::CrashKeySize::Size32;
28*6777b538SAndroid Build Coastguard Worker   }
29*6777b538SAndroid Build Coastguard Worker   if (std::size(crash_key_name) <= 64ul) {
30*6777b538SAndroid Build Coastguard Worker     return base::debug::CrashKeySize::Size64;
31*6777b538SAndroid Build Coastguard Worker   }
32*6777b538SAndroid Build Coastguard Worker   if (std::size(crash_key_name) <= 256ul) {
33*6777b538SAndroid Build Coastguard Worker     return base::debug::CrashKeySize::Size256;
34*6777b538SAndroid Build Coastguard Worker   }
35*6777b538SAndroid Build Coastguard Worker   CHECK(std::size(crash_key_name) <= 1024ul);
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker   return base::debug::CrashKeySize::Size1024;
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
Swap(std::atomic_bool & lh_op,std::atomic_bool & rh_op)41*6777b538SAndroid Build Coastguard Worker void Swap(std::atomic_bool& lh_op, std::atomic_bool& rh_op) {
42*6777b538SAndroid Build Coastguard Worker   auto lh_op_value = lh_op.load(std::memory_order_relaxed);
43*6777b538SAndroid Build Coastguard Worker   auto rh_op_value = rh_op.load(std::memory_order_relaxed);
44*6777b538SAndroid Build Coastguard Worker 
45*6777b538SAndroid Build Coastguard Worker   CHECK(lh_op.compare_exchange_strong(lh_op_value, rh_op_value));
46*6777b538SAndroid Build Coastguard Worker   CHECK(rh_op.compare_exchange_strong(rh_op_value, lh_op_value));
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker #endif
49*6777b538SAndroid Build Coastguard Worker }  // namespace
50*6777b538SAndroid Build Coastguard Worker 
AllocateMemory(size_t size_in_bytes)51*6777b538SAndroid Build Coastguard Worker void* MMapAllocator::AllocateMemory(size_t size_in_bytes) {
52*6777b538SAndroid Build Coastguard Worker   void* const mmap_res = mmap(nullptr, size_in_bytes, PROT_READ | PROT_WRITE,
53*6777b538SAndroid Build Coastguard Worker                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
54*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX)
55*6777b538SAndroid Build Coastguard Worker #if defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
56*6777b538SAndroid Build Coastguard Worker   if (mmap_res != MAP_FAILED) {
57*6777b538SAndroid Build Coastguard Worker     // Allow the anonymous memory region allocated by mmap(MAP_ANONYMOUS) to
58*6777b538SAndroid Build Coastguard Worker     // be identified in /proc/$PID/smaps.  This helps improve visibility into
59*6777b538SAndroid Build Coastguard Worker     // Chromium's memory usage on Android.
60*6777b538SAndroid Build Coastguard Worker     prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, mmap_res, size_in_bytes,
61*6777b538SAndroid Build Coastguard Worker           "tls-mmap-allocator");
62*6777b538SAndroid Build Coastguard Worker   }
63*6777b538SAndroid Build Coastguard Worker #endif
64*6777b538SAndroid Build Coastguard Worker #endif
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker   return (mmap_res != MAP_FAILED) ? mmap_res : nullptr;
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker 
FreeMemoryForTesting(void * pointer_to_allocated,size_t size_in_bytes)69*6777b538SAndroid Build Coastguard Worker bool MMapAllocator::FreeMemoryForTesting(void* pointer_to_allocated,
70*6777b538SAndroid Build Coastguard Worker                                          size_t size_in_bytes) {
71*6777b538SAndroid Build Coastguard Worker   auto const munmap_res = munmap(pointer_to_allocated, size_in_bytes);
72*6777b538SAndroid Build Coastguard Worker   return (munmap_res == 0);
73*6777b538SAndroid Build Coastguard Worker }
74*6777b538SAndroid Build Coastguard Worker 
75*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem::PThreadTLSSystem() = default;
76*6777b538SAndroid Build Coastguard Worker 
PThreadTLSSystem(PThreadTLSSystem && other)77*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem::PThreadTLSSystem(PThreadTLSSystem&& other) {
78*6777b538SAndroid Build Coastguard Worker   std::swap(crash_key_, other.crash_key_);
79*6777b538SAndroid Build Coastguard Worker   std::swap(data_access_key_, other.data_access_key_);
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
82*6777b538SAndroid Build Coastguard Worker   Swap(initialized_, other.initialized_);
83*6777b538SAndroid Build Coastguard Worker #endif
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker 
operator =(PThreadTLSSystem && other)86*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem& PThreadTLSSystem::operator=(PThreadTLSSystem&& other) {
87*6777b538SAndroid Build Coastguard Worker   std::swap(crash_key_, other.crash_key_);
88*6777b538SAndroid Build Coastguard Worker   std::swap(data_access_key_, other.data_access_key_);
89*6777b538SAndroid Build Coastguard Worker 
90*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
91*6777b538SAndroid Build Coastguard Worker   Swap(initialized_, other.initialized_);
92*6777b538SAndroid Build Coastguard Worker #endif
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker   return *this;
95*6777b538SAndroid Build Coastguard Worker }
96*6777b538SAndroid Build Coastguard Worker 
Setup(OnThreadTerminationFunction thread_termination_function,const std::string_view instance_id)97*6777b538SAndroid Build Coastguard Worker bool PThreadTLSSystem::Setup(
98*6777b538SAndroid Build Coastguard Worker     OnThreadTerminationFunction thread_termination_function,
99*6777b538SAndroid Build Coastguard Worker     const std::string_view instance_id) {
100*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
101*6777b538SAndroid Build Coastguard Worker   // Initialize must happen outside of the allocation path. Therefore, it is
102*6777b538SAndroid Build Coastguard Worker   // secure to verify with DCHECK.
103*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_.exchange(true, std::memory_order_acq_rel));
104*6777b538SAndroid Build Coastguard Worker #endif
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker   auto const key_create_res =
107*6777b538SAndroid Build Coastguard Worker       pthread_key_create(&data_access_key_, thread_termination_function);
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   // On some platforms creating a new pthread-key requires an allocation when a
110*6777b538SAndroid Build Coastguard Worker   // given number of keys has been created. I.e. in glibc this limit is denoted
111*6777b538SAndroid Build Coastguard Worker   // by PTHREAD_KEY_2NDLEVEL_SIZE. However, this value is neither present on all
112*6777b538SAndroid Build Coastguard Worker   // systems nor accessible from here. Hence, we do not do any checks here.
113*6777b538SAndroid Build Coastguard Worker   // However, we strongly recommend to setup the TLS system as early as possible
114*6777b538SAndroid Build Coastguard Worker   // to avoid exceeding this limit.
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   // Some crashes might be caused by the initialization being performed too late
117*6777b538SAndroid Build Coastguard Worker   // and running into the problems mentioned above. Since there's no way to
118*6777b538SAndroid Build Coastguard Worker   // handle this issue programmatically, we include the key into the crashpad
119*6777b538SAndroid Build Coastguard Worker   // report to allow for later inspection.
120*6777b538SAndroid Build Coastguard Worker   std::string crash_key_name = "tls_system-";
121*6777b538SAndroid Build Coastguard Worker   crash_key_name += instance_id;
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker   crash_key_ = base::debug::AllocateCrashKeyString(
124*6777b538SAndroid Build Coastguard Worker       crash_key_name.c_str(), GetCrashKeySize(crash_key_name));
125*6777b538SAndroid Build Coastguard Worker   base::debug::SetCrashKeyString(crash_key_,
126*6777b538SAndroid Build Coastguard Worker                                  base::NumberToString(data_access_key_));
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   return (0 == key_create_res);
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker 
TearDownForTesting()131*6777b538SAndroid Build Coastguard Worker bool PThreadTLSSystem::TearDownForTesting() {
132*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
133*6777b538SAndroid Build Coastguard Worker   // TearDownForTesting must happen outside of the allocation path. Therefore,
134*6777b538SAndroid Build Coastguard Worker   // it is secure to verify with DCHECK.
135*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_.exchange(false, std::memory_order_acq_rel));
136*6777b538SAndroid Build Coastguard Worker #endif
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker   base::debug::ClearCrashKeyString(crash_key_);
139*6777b538SAndroid Build Coastguard Worker   crash_key_ = nullptr;
140*6777b538SAndroid Build Coastguard Worker 
141*6777b538SAndroid Build Coastguard Worker   auto const key_delete_res = pthread_key_delete(data_access_key_);
142*6777b538SAndroid Build Coastguard Worker   return (0 == key_delete_res);
143*6777b538SAndroid Build Coastguard Worker }
144*6777b538SAndroid Build Coastguard Worker 
GetThreadSpecificData()145*6777b538SAndroid Build Coastguard Worker void* PThreadTLSSystem::GetThreadSpecificData() {
146*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
147*6777b538SAndroid Build Coastguard Worker   if (!initialized_.load(std::memory_order_acquire)) {
148*6777b538SAndroid Build Coastguard Worker     return nullptr;
149*6777b538SAndroid Build Coastguard Worker   }
150*6777b538SAndroid Build Coastguard Worker #endif
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   return pthread_getspecific(data_access_key_);
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker 
SetThreadSpecificData(void * data)155*6777b538SAndroid Build Coastguard Worker bool PThreadTLSSystem::SetThreadSpecificData(void* data) {
156*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
157*6777b538SAndroid Build Coastguard Worker   if (!initialized_.load(std::memory_order_acquire)) {
158*6777b538SAndroid Build Coastguard Worker     return false;
159*6777b538SAndroid Build Coastguard Worker   }
160*6777b538SAndroid Build Coastguard Worker #endif
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   return (0 == pthread_setspecific(data_access_key_, data));
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker }  // namespace base::allocator::dispatcher::internal
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker #endif  // USE_LOCAL_TLS_EMULATION()
168