/* * * Copyright (c) 2022 Project CHIP 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 * * http://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 "SysHeapMalloc.h" #include #include extern "C" { #include #include #include #include } #include #include using namespace chip; namespace { // Alignment of memory blocks returned by malloc. // Choose the value that guarantees that the returned memory blocks are castable to all built-in types. constexpr size_t kMallocAlignment = alignof(long long); uint8_t sHeapMemory[CONFIG_CHIP_MALLOC_SYS_HEAP_SIZE] alignas(kMallocAlignment); sys_heap sHeap; SYS_MUTEX_DEFINE(sLock); // RAII helper for synchronizing access to the common heap. class LockGuard { public: LockGuard() : mStatus(sys_mutex_lock(&sLock, K_FOREVER)) {} ~LockGuard(); bool Locked() const { return mStatus == 0; } CHIP_ERROR Error() const { return System::MapErrorZephyr(mStatus); } private: const int mStatus; }; LockGuard::~LockGuard() { if (mStatus == 0) { sys_mutex_unlock(&sLock); } } int InitSysHeapMalloc() { sys_heap_init(&sHeap, sHeapMemory, sizeof(sHeapMemory)); return 0; } } // namespace // Initialize the heap in the POST_KERNEL phase to make sure that it is ready even before // C++ static constructors are called (which happens prior to the APPLICATION initialization phase). SYS_INIT(InitSysHeapMalloc, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); namespace chip { namespace DeviceLayer { namespace Malloc { void * Malloc(size_t size) { LockGuard lockGuard; return lockGuard.Locked() ? sys_heap_aligned_alloc(&sHeap, kMallocAlignment, size) : nullptr; } void * Calloc(size_t num, size_t size) { size_t totalSize; if (size_mul_overflow(num, size, &totalSize)) { return nullptr; } void * mem = Malloc(totalSize); if (mem) { memset(mem, 0, totalSize); } return mem; } void * Realloc(void * mem, size_t size) { LockGuard lockGuard; return lockGuard.Locked() ? sys_heap_aligned_realloc(&sHeap, mem, kMallocAlignment, size) : nullptr; } void Free(void * mem) { LockGuard lockGuard; VerifyOrReturn(lockGuard.Locked()); sys_heap_free(&sHeap, mem); } #ifdef CONFIG_SYS_HEAP_RUNTIME_STATS CHIP_ERROR GetStats(Stats & stats) { LockGuard lockGuard; ReturnErrorOnFailure(lockGuard.Error()); sys_memory_stats sysHeapStats; ReturnErrorOnFailure(System::MapErrorZephyr(sys_heap_runtime_stats_get(&sHeap, &sysHeapStats))); stats.free = sysHeapStats.free_bytes; stats.used = sysHeapStats.allocated_bytes; stats.maxUsed = sysHeapStats.max_allocated_bytes; return CHIP_NO_ERROR; } void ResetMaxStats() { (void) sys_heap_runtime_stats_reset_max(&sHeap); } #endif // CONFIG_SYS_HEAP_RUNTIME_STATS } // namespace Malloc } // namespace DeviceLayer } // namespace chip #ifdef CONFIG_CHIP_MALLOC_SYS_HEAP_OVERRIDE extern "C" { // Construct the name of a function wrapped with the `--wrap=symbol` GCC option. #define WRAP(f) __wrap_##f // Define a function as an alias of another function. #define ALIAS(f) __attribute((alias(f))) // Mark a function as externally visible so that it is not optimized-away even // if LTO or whole-program optimization is enabled. #define EXTERNALLY_VISIBLE __attribute((externally_visible)) EXTERNALLY_VISIBLE void * WRAP(malloc)(size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc6MallocEj"); EXTERNALLY_VISIBLE void * WRAP(calloc)(size_t num, size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc6CallocEjj"); EXTERNALLY_VISIBLE void * WRAP(realloc)(void * mem, size_t size) ALIAS("_ZN4chip11DeviceLayer6Malloc7ReallocEPvj"); EXTERNALLY_VISIBLE void WRAP(free)(void * mem) ALIAS("_ZN4chip11DeviceLayer6Malloc4FreeEPv"); EXTERNALLY_VISIBLE void * WRAP(_malloc_r)(_reent *, size_t size) { return WRAP(malloc)(size); } EXTERNALLY_VISIBLE void * WRAP(_calloc_r)(_reent *, size_t num, size_t size) { return WRAP(calloc)(num, size); } EXTERNALLY_VISIBLE void * WRAP(_realloc_r)(_reent *, void * mem, size_t size) { return WRAP(realloc)(mem, size); } EXTERNALLY_VISIBLE void WRAP(_free_r)(_reent *, void * mem) { WRAP(free)(mem); } } // extern "C" #endif // CONFIG_CHIP_MALLOC_SYS_HEAP_OVERRIDE