xref: /aosp_15_r20/external/cronet/base/allocator/dispatcher/dispatcher.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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()98 Dispatcher::Dispatcher() : impl_(std::make_unique<Impl>()) {}
99 
100 Dispatcher::~Dispatcher() = default;
101 
GetInstance()102 Dispatcher& Dispatcher::GetInstance() {
103   static base::NoDestructor<Dispatcher> instance;
104   return *instance;
105 }
106 
Initialize(const internal::DispatchData & dispatch_data)107 void Dispatcher::Initialize(const internal::DispatchData& dispatch_data) {
108   impl_->Initialize(dispatch_data);
109 }
110 
ResetForTesting()111 void Dispatcher::ResetForTesting() {
112   impl_->Reset();
113 }
114 }  // namespace base::allocator::dispatcher
115