diff --git a/src/mesh/MemoryPool.h b/src/mesh/MemoryPool.h index ea7c8f583..0c5ba6c71 100644 --- a/src/mesh/MemoryPool.h +++ b/src/mesh/MemoryPool.h @@ -6,6 +6,7 @@ #include #include "PointerQueue.h" +#include "configuration.h" // For LOG_WARN, LOG_DEBUG, LOG_HEAP template class Allocator { @@ -14,13 +15,14 @@ template class Allocator Allocator() : deleter([this](T *p) { this->release(p); }) {} virtual ~Allocator() {} - /// Return a queable object which has been prefilled with zeros. Panic if no buffer is available + /// Return a queable object which has been prefilled with zeros. Return nullptr if no buffer is available /// Note: this method is safe to call from regular OR ISR code T *allocZeroed() { T *p = allocZeroed(0); - - assert(p); // FIXME panic instead + if (!p) { + LOG_WARN("Failed to allocate zeroed memory"); + } return p; } @@ -39,10 +41,12 @@ template class Allocator T *allocCopy(const T &src, TickType_t maxWait = portMAX_DELAY) { T *p = alloc(maxWait); - assert(p); + if (!p) { + LOG_WARN("Failed to allocate memory for copy"); + return nullptr; + } - if (p) - *p = src; + *p = src; return p; } @@ -83,7 +87,9 @@ template class MemoryDynamic : public Allocator /// Return a buffer for use by others virtual void release(T *p) override { - assert(p); + if (p == nullptr) + return; + LOG_HEAP("Freeing 0x%x", p); free(p); @@ -98,3 +104,59 @@ template class MemoryDynamic : public Allocator return p; } }; + +/** + * A static memory pool that uses a fixed buffer instead of heap allocation + */ +template class MemoryPool : public Allocator +{ + private: + T pool[MaxSize]; + bool used[MaxSize]; + + public: + MemoryPool() + { + // Initialize the used array to false (all slots free) + for (int i = 0; i < MaxSize; i++) { + used[i] = false; + } + } + + /// Return a buffer for use by others + virtual void release(T *p) override + { + if (!p) { + LOG_DEBUG("Failed to release memory, pointer is null"); + return; + } + + // Find the index of this pointer in our pool + int index = p - pool; + if (index >= 0 && index < MaxSize) { + assert(used[index]); // Should be marked as used + used[index] = false; + LOG_HEAP("Released static pool item %d at 0x%x", index, p); + } else { + LOG_WARN("Pointer 0x%x not from our pool!", p); + } + } + + protected: + // Alloc some storage from our static pool + virtual T *alloc(TickType_t maxWait) override + { + // Find first free slot + for (int i = 0; i < MaxSize; i++) { + if (!used[i]) { + used[i] = true; + LOG_HEAP("Allocated static pool item %d at 0x%x", i, &pool[i]); + return &pool[i]; + } + } + + // No free slots available - return nullptr instead of asserting + LOG_WARN("No free slots available in static memory pool!"); + return nullptr; + } +};