| // 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 <sys/mman.h> |
| |
| #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) |
| #include <sys/prctl.h> |
| #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() |