| // Copyright 2024 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| #include "pw_malloc/malloc.h" |
| |
| #include <cstring> |
| #include <new> |
| |
| #include "pw_allocator/allocator.h" |
| #include "pw_allocator/metrics.h" |
| #include "pw_allocator/synchronized_allocator.h" |
| #include "pw_allocator/tracking_allocator.h" |
| #include "pw_assert/check.h" |
| #include "pw_malloc/config.h" |
| #include "pw_metric/metric.h" |
| #include "pw_tokenizer/tokenize.h" |
| |
| namespace { |
| |
| using ::pw::allocator::Layout; |
| using ::pw::allocator::NoMetrics; |
| using ::pw::allocator::NoSync; |
| using ::pw::allocator::SynchronizedAllocator; |
| using ::pw::allocator::TrackingAllocator; |
| using ::pw::metric::Token; |
| |
| const PW_MALLOC_METRICS_TYPE* system_metrics = nullptr; |
| |
| /// Instantiates the system allocator, based on the module configuration. |
| /// |
| /// This function must be a template to conditionally omit constexpr branches. |
| template <typename MetricsType, typename LockType> |
| pw::Allocator& WrapSystemAllocator() { |
| pw::Allocator* system = pw::malloc::GetSystemAllocator(); |
| if constexpr (!std::is_same_v<MetricsType, NoMetrics>) { |
| constexpr static Token kToken = PW_TOKENIZE_STRING("system allocator"); |
| static TrackingAllocator<MetricsType> tracker(kToken, *system); |
| system = &tracker; |
| system_metrics = &tracker.metrics(); |
| } else { |
| static MetricsType no_metrics; |
| system_metrics = &no_metrics; |
| } |
| if constexpr (!std::is_same_v<LockType, NoSync>) { |
| static SynchronizedAllocator<LockType> synchronized(*system); |
| system = &synchronized; |
| } |
| return *system; |
| } |
| |
| pw::Allocator& SystemAllocator() { |
| static pw::Allocator& system = |
| WrapSystemAllocator<PW_MALLOC_METRICS_TYPE, PW_MALLOC_LOCK_TYPE>(); |
| return system; |
| } |
| |
| } // namespace |
| |
| namespace pw::malloc { |
| |
| void InitSystemAllocator(void* heap_low_addr, void* heap_high_addr) { |
| auto* lo = std::launder(reinterpret_cast<std::byte*>(heap_low_addr)); |
| auto* hi = std::launder(reinterpret_cast<std::byte*>(heap_high_addr)); |
| InitSystemAllocator(pw::ByteSpan(lo, (hi - lo))); |
| } |
| |
| const PW_MALLOC_METRICS_TYPE& GetSystemMetrics() { |
| SystemAllocator(); |
| return *system_metrics; |
| } |
| |
| } // namespace pw::malloc |
| |
| PW_EXTERN_C_START |
| |
| void pw_MallocInit(uint8_t* heap_low_addr, uint8_t* heap_high_addr) { |
| pw::malloc::InitSystemAllocator(heap_low_addr, heap_high_addr); |
| } |
| |
| // Wrapper functions for malloc, free, realloc and calloc. |
| // With linker options "-Wl --wrap=<function name>", linker will link |
| // "__wrap_<function name>" with "<function_name>", and calling |
| // "<function name>" will call "__wrap_<function name>" instead |
| void* __wrap_malloc(size_t size) { |
| return SystemAllocator().Allocate(Layout(size)); |
| } |
| |
| void __wrap_free(void* ptr) { SystemAllocator().Deallocate(ptr); } |
| |
| void* __wrap_realloc(void* ptr, size_t size) { |
| return SystemAllocator().Reallocate(ptr, Layout(size)); |
| } |
| |
| void* __wrap_calloc(size_t num, size_t size) { |
| if (PW_MUL_OVERFLOW(num, size, &size)) { |
| return nullptr; |
| } |
| void* ptr = __wrap_malloc(size); |
| if (ptr != nullptr) { |
| std::memset(ptr, 0, size); |
| } |
| return ptr; |
| } |
| |
| void* __wrap__malloc_r(struct _reent*, size_t size) { |
| return __wrap_malloc(size); |
| } |
| |
| void __wrap__free_r(struct _reent*, void* ptr) { __wrap_free(ptr); } |
| |
| void* __wrap__realloc_r(struct _reent*, void* ptr, size_t size) { |
| return __wrap_realloc(ptr, size); |
| } |
| |
| void* __wrap__calloc_r(struct _reent*, size_t num, size_t size) { |
| return __wrap_calloc(num, size); |
| } |
| |
| PW_EXTERN_C_END |