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/dispatcher.h" 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/internal/dispatch_data.h" 8*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 9*6777b538SAndroid Build Coastguard Worker #include "base/dcheck_is_on.h" 10*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h" 11*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_buildflags.h" 12*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/shim/allocator_shim.h" 13*6777b538SAndroid Build Coastguard Worker 14*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 15*6777b538SAndroid Build Coastguard Worker #include <atomic> 16*6777b538SAndroid Build Coastguard Worker #endif 17*6777b538SAndroid Build Coastguard Worker 18*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_PARTITION_ALLOC) 19*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_hooks.h" 20*6777b538SAndroid Build Coastguard Worker #endif 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker namespace base::allocator::dispatcher { 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker // The private implementation of Dispatcher. 25*6777b538SAndroid Build Coastguard Worker struct Dispatcher::Impl { Initializebase::allocator::dispatcher::Dispatcher::Impl26*6777b538SAndroid Build Coastguard Worker void Initialize(const internal::DispatchData& dispatch_data) { 27*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 28*6777b538SAndroid Build Coastguard Worker DCHECK(!is_initialized_check_flag_.test_and_set()); 29*6777b538SAndroid Build Coastguard Worker #endif 30*6777b538SAndroid Build Coastguard Worker 31*6777b538SAndroid Build Coastguard Worker dispatch_data_ = dispatch_data; 32*6777b538SAndroid Build Coastguard Worker ConnectToEmitters(dispatch_data_); 33*6777b538SAndroid Build Coastguard Worker } 34*6777b538SAndroid Build Coastguard Worker Resetbase::allocator::dispatcher::Dispatcher::Impl35*6777b538SAndroid Build Coastguard Worker void Reset() { 36*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 37*6777b538SAndroid Build Coastguard Worker DCHECK([&]() { 38*6777b538SAndroid Build Coastguard Worker auto const was_set = is_initialized_check_flag_.test_and_set(); 39*6777b538SAndroid Build Coastguard Worker is_initialized_check_flag_.clear(); 40*6777b538SAndroid Build Coastguard Worker return was_set; 41*6777b538SAndroid Build Coastguard Worker }()); 42*6777b538SAndroid Build Coastguard Worker #endif 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker DisconnectFromEmitters(dispatch_data_); 45*6777b538SAndroid Build Coastguard Worker dispatch_data_ = {}; 46*6777b538SAndroid Build Coastguard Worker } 47*6777b538SAndroid Build Coastguard Worker 48*6777b538SAndroid Build Coastguard Worker private: 49*6777b538SAndroid Build Coastguard Worker // Connect the hooks to the memory subsystem. In some cases, most notably when 50*6777b538SAndroid Build Coastguard Worker // we have no observers at all, the hooks will be invalid and must NOT be 51*6777b538SAndroid Build Coastguard Worker // connected. This way we prevent notifications although no observers are 52*6777b538SAndroid Build Coastguard Worker // present. ConnectToEmittersbase::allocator::dispatcher::Dispatcher::Impl53*6777b538SAndroid Build Coastguard Worker static void ConnectToEmitters(const internal::DispatchData& dispatch_data) { 54*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_ALLOCATOR_SHIM) 55*6777b538SAndroid Build Coastguard Worker if (auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch()) { 56*6777b538SAndroid Build Coastguard Worker allocator_shim::InsertAllocatorDispatch(allocator_dispatch); 57*6777b538SAndroid Build Coastguard Worker } 58*6777b538SAndroid Build Coastguard Worker #endif 59*6777b538SAndroid Build Coastguard Worker 60*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_PARTITION_ALLOC) 61*6777b538SAndroid Build Coastguard Worker { 62*6777b538SAndroid Build Coastguard Worker auto* const allocation_hook = dispatch_data.GetAllocationObserverHook(); 63*6777b538SAndroid Build Coastguard Worker auto* const free_hook = dispatch_data.GetFreeObserverHook(); 64*6777b538SAndroid Build Coastguard Worker if (allocation_hook && free_hook) { 65*6777b538SAndroid Build Coastguard Worker partition_alloc::PartitionAllocHooks::SetObserverHooks(allocation_hook, 66*6777b538SAndroid Build Coastguard Worker free_hook); 67*6777b538SAndroid Build Coastguard Worker } 68*6777b538SAndroid Build Coastguard Worker } 69*6777b538SAndroid Build Coastguard Worker #endif 70*6777b538SAndroid Build Coastguard Worker } 71*6777b538SAndroid Build Coastguard Worker DisconnectFromEmittersbase::allocator::dispatcher::Dispatcher::Impl72*6777b538SAndroid Build Coastguard Worker static void DisconnectFromEmitters(internal::DispatchData& dispatch_data) { 73*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_ALLOCATOR_SHIM) 74*6777b538SAndroid Build Coastguard Worker if (auto* const allocator_dispatch = dispatch_data.GetAllocatorDispatch()) { 75*6777b538SAndroid Build Coastguard Worker allocator_shim::RemoveAllocatorDispatchForTesting( 76*6777b538SAndroid Build Coastguard Worker allocator_dispatch); // IN-TEST 77*6777b538SAndroid Build Coastguard Worker } 78*6777b538SAndroid Build Coastguard Worker #endif 79*6777b538SAndroid Build Coastguard Worker 80*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_PARTITION_ALLOC) 81*6777b538SAndroid Build Coastguard Worker partition_alloc::PartitionAllocHooks::SetObserverHooks(nullptr, nullptr); 82*6777b538SAndroid Build Coastguard Worker #endif 83*6777b538SAndroid Build Coastguard Worker } 84*6777b538SAndroid Build Coastguard Worker 85*6777b538SAndroid Build Coastguard Worker // Information on the hooks. 86*6777b538SAndroid Build Coastguard Worker internal::DispatchData dispatch_data_; 87*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON() 88*6777b538SAndroid Build Coastguard Worker // Indicator if the dispatcher has been initialized before. 89*6777b538SAndroid Build Coastguard Worker #if !defined(__cpp_lib_atomic_value_initialization) || \ 90*6777b538SAndroid Build Coastguard Worker __cpp_lib_atomic_value_initialization < 201911L 91*6777b538SAndroid Build Coastguard Worker std::atomic_flag is_initialized_check_flag_ = ATOMIC_FLAG_INIT; 92*6777b538SAndroid Build Coastguard Worker #else 93*6777b538SAndroid Build Coastguard Worker std::atomic_flag is_initialized_check_flag_; 94*6777b538SAndroid Build Coastguard Worker #endif 95*6777b538SAndroid Build Coastguard Worker #endif 96*6777b538SAndroid Build Coastguard Worker }; 97*6777b538SAndroid Build Coastguard Worker Dispatcher()98*6777b538SAndroid Build Coastguard WorkerDispatcher::Dispatcher() : impl_(std::make_unique<Impl>()) {} 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker Dispatcher::~Dispatcher() = default; 101*6777b538SAndroid Build Coastguard Worker GetInstance()102*6777b538SAndroid Build Coastguard WorkerDispatcher& Dispatcher::GetInstance() { 103*6777b538SAndroid Build Coastguard Worker static base::NoDestructor<Dispatcher> instance; 104*6777b538SAndroid Build Coastguard Worker return *instance; 105*6777b538SAndroid Build Coastguard Worker } 106*6777b538SAndroid Build Coastguard Worker Initialize(const internal::DispatchData & dispatch_data)107*6777b538SAndroid Build Coastguard Workervoid Dispatcher::Initialize(const internal::DispatchData& dispatch_data) { 108*6777b538SAndroid Build Coastguard Worker impl_->Initialize(dispatch_data); 109*6777b538SAndroid Build Coastguard Worker } 110*6777b538SAndroid Build Coastguard Worker ResetForTesting()111*6777b538SAndroid Build Coastguard Workervoid Dispatcher::ResetForTesting() { 112*6777b538SAndroid Build Coastguard Worker impl_->Reset(); 113*6777b538SAndroid Build Coastguard Worker } 114*6777b538SAndroid Build Coastguard Worker } // namespace base::allocator::dispatcher 115