// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/allocator/dispatcher/tls.h" #if USE_LOCAL_TLS_EMULATION() #include "base/check.h" #include "base/dcheck_is_on.h" #include "base/immediate_crash.h" #include "build/build_config.h" #include #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) #include #endif namespace base::allocator::dispatcher::internal { void* MMapAllocator::AllocateMemory(size_t size_in_bytes) { void* const mmap_res = mmap(nullptr, size_in_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) #if defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME) if (mmap_res != MAP_FAILED) { // Allow the anonymous memory region allocated by mmap(MAP_ANONYMOUS) to // be identified in /proc/$PID/smaps. This helps improve visibility into // Chromium's memory usage on Android. prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, mmap_res, size_in_bytes, "tls-mmap-allocator"); } #endif #endif return (mmap_res != MAP_FAILED) ? mmap_res : nullptr; } bool MMapAllocator::FreeMemoryForTesting(void* pointer_to_allocated, size_t size_in_bytes) { auto const munmap_res = munmap(pointer_to_allocated, size_in_bytes); return (munmap_res == 0); } bool PThreadTLSSystem::Setup( OnThreadTerminationFunction thread_termination_function) { #if DCHECK_IS_ON() // Initialize must happen outside of the allocation path. Therefore, it is // secure to verify with DCHECK. DCHECK(!initialized_.exchange(true, std::memory_order_acq_rel)); #endif auto const key_create_res = pthread_key_create(&data_access_key_, thread_termination_function); // On some platforms creating a new pthread-key requires an allocation when a // given number of keys has been created. I.e. in glibc this limit is denoted // by PTHREAD_KEY_2NDLEVEL_SIZE. However, this value is neither present on all // systems nor accessible from here. Hence, we do not do any checks here. // However, we strongly recommend to setup the TLS system as early as possible // to avoid exceeding this limit. return (0 == key_create_res); } bool PThreadTLSSystem::TearDownForTesting() { #if DCHECK_IS_ON() // TearDownForTesting must happen outside of the allocation path. Therefore, // it is secure to verify with DCHECK. DCHECK(initialized_.exchange(false, std::memory_order_acq_rel)); #endif auto const key_delete_res = pthread_key_delete(data_access_key_); return (0 == key_delete_res); } void* PThreadTLSSystem::GetThreadSpecificData() { #if DCHECK_IS_ON() if (!initialized_.load(std::memory_order_acquire)) { return nullptr; } #endif return pthread_getspecific(data_access_key_); } bool PThreadTLSSystem::SetThreadSpecificData(void* data) { #if DCHECK_IS_ON() if (!initialized_.load(std::memory_order_acquire)) { return false; } #endif return (0 == pthread_setspecific(data_access_key_, data)); } } // namespace base::allocator::dispatcher::internal #endif // USE_LOCAL_TLS_EMULATION()