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