1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_malloc/malloc.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <cstring>
18*61c4878aSAndroid Build Coastguard Worker #include <new>
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard Worker #include "pw_allocator/allocator.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_allocator/metrics.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_allocator/synchronized_allocator.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_allocator/tracking_allocator.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_malloc/config.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_metric/metric.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_tokenizer/tokenize.h"
28*61c4878aSAndroid Build Coastguard Worker
29*61c4878aSAndroid Build Coastguard Worker namespace {
30*61c4878aSAndroid Build Coastguard Worker
31*61c4878aSAndroid Build Coastguard Worker using ::pw::allocator::Layout;
32*61c4878aSAndroid Build Coastguard Worker using ::pw::allocator::NoMetrics;
33*61c4878aSAndroid Build Coastguard Worker using ::pw::allocator::NoSync;
34*61c4878aSAndroid Build Coastguard Worker using ::pw::allocator::SynchronizedAllocator;
35*61c4878aSAndroid Build Coastguard Worker using ::pw::allocator::TrackingAllocator;
36*61c4878aSAndroid Build Coastguard Worker using ::pw::metric::Token;
37*61c4878aSAndroid Build Coastguard Worker
38*61c4878aSAndroid Build Coastguard Worker const PW_MALLOC_METRICS_TYPE* system_metrics = nullptr;
39*61c4878aSAndroid Build Coastguard Worker
40*61c4878aSAndroid Build Coastguard Worker /// Instantiates the system allocator, based on the module configuration.
41*61c4878aSAndroid Build Coastguard Worker ///
42*61c4878aSAndroid Build Coastguard Worker /// This function must be a template to conditionally omit constexpr branches.
43*61c4878aSAndroid Build Coastguard Worker template <typename MetricsType, typename LockType>
WrapSystemAllocator()44*61c4878aSAndroid Build Coastguard Worker pw::Allocator& WrapSystemAllocator() {
45*61c4878aSAndroid Build Coastguard Worker pw::Allocator* system = pw::malloc::GetSystemAllocator();
46*61c4878aSAndroid Build Coastguard Worker if constexpr (!std::is_same_v<MetricsType, NoMetrics>) {
47*61c4878aSAndroid Build Coastguard Worker constexpr static Token kToken = PW_TOKENIZE_STRING("system allocator");
48*61c4878aSAndroid Build Coastguard Worker static TrackingAllocator<MetricsType> tracker(kToken, *system);
49*61c4878aSAndroid Build Coastguard Worker system = &tracker;
50*61c4878aSAndroid Build Coastguard Worker system_metrics = &tracker.metrics();
51*61c4878aSAndroid Build Coastguard Worker } else {
52*61c4878aSAndroid Build Coastguard Worker static MetricsType no_metrics;
53*61c4878aSAndroid Build Coastguard Worker system_metrics = &no_metrics;
54*61c4878aSAndroid Build Coastguard Worker }
55*61c4878aSAndroid Build Coastguard Worker if constexpr (!std::is_same_v<LockType, NoSync>) {
56*61c4878aSAndroid Build Coastguard Worker static SynchronizedAllocator<LockType> synchronized(*system);
57*61c4878aSAndroid Build Coastguard Worker system = &synchronized;
58*61c4878aSAndroid Build Coastguard Worker }
59*61c4878aSAndroid Build Coastguard Worker return *system;
60*61c4878aSAndroid Build Coastguard Worker }
61*61c4878aSAndroid Build Coastguard Worker
SystemAllocator()62*61c4878aSAndroid Build Coastguard Worker pw::Allocator& SystemAllocator() {
63*61c4878aSAndroid Build Coastguard Worker static pw::Allocator& system =
64*61c4878aSAndroid Build Coastguard Worker WrapSystemAllocator<PW_MALLOC_METRICS_TYPE, PW_MALLOC_LOCK_TYPE>();
65*61c4878aSAndroid Build Coastguard Worker return system;
66*61c4878aSAndroid Build Coastguard Worker }
67*61c4878aSAndroid Build Coastguard Worker
68*61c4878aSAndroid Build Coastguard Worker } // namespace
69*61c4878aSAndroid Build Coastguard Worker
70*61c4878aSAndroid Build Coastguard Worker namespace pw::malloc {
71*61c4878aSAndroid Build Coastguard Worker
InitSystemAllocator(void * heap_low_addr,void * heap_high_addr)72*61c4878aSAndroid Build Coastguard Worker void InitSystemAllocator(void* heap_low_addr, void* heap_high_addr) {
73*61c4878aSAndroid Build Coastguard Worker auto* lo = std::launder(reinterpret_cast<std::byte*>(heap_low_addr));
74*61c4878aSAndroid Build Coastguard Worker auto* hi = std::launder(reinterpret_cast<std::byte*>(heap_high_addr));
75*61c4878aSAndroid Build Coastguard Worker InitSystemAllocator(pw::ByteSpan(lo, (hi - lo)));
76*61c4878aSAndroid Build Coastguard Worker }
77*61c4878aSAndroid Build Coastguard Worker
GetSystemMetrics()78*61c4878aSAndroid Build Coastguard Worker const PW_MALLOC_METRICS_TYPE& GetSystemMetrics() {
79*61c4878aSAndroid Build Coastguard Worker SystemAllocator();
80*61c4878aSAndroid Build Coastguard Worker return *system_metrics;
81*61c4878aSAndroid Build Coastguard Worker }
82*61c4878aSAndroid Build Coastguard Worker
83*61c4878aSAndroid Build Coastguard Worker } // namespace pw::malloc
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker PW_EXTERN_C_START
86*61c4878aSAndroid Build Coastguard Worker
pw_MallocInit(uint8_t * heap_low_addr,uint8_t * heap_high_addr)87*61c4878aSAndroid Build Coastguard Worker void pw_MallocInit(uint8_t* heap_low_addr, uint8_t* heap_high_addr) {
88*61c4878aSAndroid Build Coastguard Worker pw::malloc::InitSystemAllocator(heap_low_addr, heap_high_addr);
89*61c4878aSAndroid Build Coastguard Worker }
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker // Wrapper functions for malloc, free, realloc and calloc.
92*61c4878aSAndroid Build Coastguard Worker // With linker options "-Wl --wrap=<function name>", linker will link
93*61c4878aSAndroid Build Coastguard Worker // "__wrap_<function name>" with "<function_name>", and calling
94*61c4878aSAndroid Build Coastguard Worker // "<function name>" will call "__wrap_<function name>" instead
__wrap_malloc(size_t size)95*61c4878aSAndroid Build Coastguard Worker void* __wrap_malloc(size_t size) {
96*61c4878aSAndroid Build Coastguard Worker return SystemAllocator().Allocate(Layout(size));
97*61c4878aSAndroid Build Coastguard Worker }
98*61c4878aSAndroid Build Coastguard Worker
__wrap_free(void * ptr)99*61c4878aSAndroid Build Coastguard Worker void __wrap_free(void* ptr) { SystemAllocator().Deallocate(ptr); }
100*61c4878aSAndroid Build Coastguard Worker
__wrap_realloc(void * ptr,size_t size)101*61c4878aSAndroid Build Coastguard Worker void* __wrap_realloc(void* ptr, size_t size) {
102*61c4878aSAndroid Build Coastguard Worker return SystemAllocator().Reallocate(ptr, Layout(size));
103*61c4878aSAndroid Build Coastguard Worker }
104*61c4878aSAndroid Build Coastguard Worker
__wrap_calloc(size_t num,size_t size)105*61c4878aSAndroid Build Coastguard Worker void* __wrap_calloc(size_t num, size_t size) {
106*61c4878aSAndroid Build Coastguard Worker if (PW_MUL_OVERFLOW(num, size, &size)) {
107*61c4878aSAndroid Build Coastguard Worker return nullptr;
108*61c4878aSAndroid Build Coastguard Worker }
109*61c4878aSAndroid Build Coastguard Worker void* ptr = __wrap_malloc(size);
110*61c4878aSAndroid Build Coastguard Worker if (ptr != nullptr) {
111*61c4878aSAndroid Build Coastguard Worker std::memset(ptr, 0, size);
112*61c4878aSAndroid Build Coastguard Worker }
113*61c4878aSAndroid Build Coastguard Worker return ptr;
114*61c4878aSAndroid Build Coastguard Worker }
115*61c4878aSAndroid Build Coastguard Worker
__wrap__malloc_r(struct _reent *,size_t size)116*61c4878aSAndroid Build Coastguard Worker void* __wrap__malloc_r(struct _reent*, size_t size) {
117*61c4878aSAndroid Build Coastguard Worker return __wrap_malloc(size);
118*61c4878aSAndroid Build Coastguard Worker }
119*61c4878aSAndroid Build Coastguard Worker
__wrap__free_r(struct _reent *,void * ptr)120*61c4878aSAndroid Build Coastguard Worker void __wrap__free_r(struct _reent*, void* ptr) { __wrap_free(ptr); }
121*61c4878aSAndroid Build Coastguard Worker
__wrap__realloc_r(struct _reent *,void * ptr,size_t size)122*61c4878aSAndroid Build Coastguard Worker void* __wrap__realloc_r(struct _reent*, void* ptr, size_t size) {
123*61c4878aSAndroid Build Coastguard Worker return __wrap_realloc(ptr, size);
124*61c4878aSAndroid Build Coastguard Worker }
125*61c4878aSAndroid Build Coastguard Worker
__wrap__calloc_r(struct _reent *,size_t num,size_t size)126*61c4878aSAndroid Build Coastguard Worker void* __wrap__calloc_r(struct _reent*, size_t num, size_t size) {
127*61c4878aSAndroid Build Coastguard Worker return __wrap_calloc(num, size);
128*61c4878aSAndroid Build Coastguard Worker }
129*61c4878aSAndroid Build Coastguard Worker
130*61c4878aSAndroid Build Coastguard Worker PW_EXTERN_C_END
131