From 5a4eaafdacb48f2709d2fabdd3a10f9635e23d2b Mon Sep 17 00:00:00 2001 From: Emilio Perez Date: Thu, 19 Oct 2023 17:03:19 +0100 Subject: [PATCH] Provide a way to override frame memory allocation It can be done local to a `NDArrayPool` by overriding `frameMalloc` and `frameFree`. It can also be also done globally by using the static method `setDefaultFrameMemoryFunctions` --- ADApp/ADSrc/NDArray.cpp | 9 ++++++-- ADApp/ADSrc/NDArray.h | 9 ++++++++ ADApp/ADSrc/NDArrayPool.cpp | 43 +++++++++++++++++++++++++++++++++++-- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/ADApp/ADSrc/NDArray.cpp b/ADApp/ADSrc/NDArray.cpp index 2447a9bc6..257d5de7e 100644 --- a/ADApp/ADSrc/NDArray.cpp +++ b/ADApp/ADSrc/NDArray.cpp @@ -64,7 +64,7 @@ NDArray::NDArray(int nDims, size_t *dims, NDDataType_t dataType, size_t dataSize if (pData) { this->pData = pData; } else { - this->pData = malloc(dataSize); + this->pData = defaultFrameMalloc(dataSize); this->dataSize = dataSize; } } @@ -73,7 +73,12 @@ NDArray::NDArray(int nDims, size_t *dims, NDDataType_t dataType, size_t dataSize * Frees the data array, deletes all attributes, frees the attribute list and destroys the mutex. */ NDArray::~NDArray() { - if (this->pData) free(this->pData); + if (this->pData) { + if (this->pNDArrayPool) + this->pNDArrayPool->frameFree(this->pData); + else + defaultFrameFree(this->pData); + } delete this->pAttributeList; } diff --git a/ADApp/ADSrc/NDArray.h b/ADApp/ADSrc/NDArray.h index f7ad79b69..43868b740 100644 --- a/ADApp/ADSrc/NDArray.h +++ b/ADApp/ADSrc/NDArray.h @@ -25,6 +25,11 @@ /** The maximum number of dimensions in an NDArray */ #define ND_ARRAY_MAX_DIMS 10 +typedef void *(*MallocFunc_t)(size_t size); +typedef void (*FreeFunc_t)(void *ptr); +extern MallocFunc_t defaultFrameMalloc; +extern FreeFunc_t defaultFrameFree; + /** Enumeration of color modes for NDArray attribute "colorMode" */ typedef enum { @@ -182,6 +187,10 @@ class ADCORE_API NDArrayPool { size_t getMemorySize(); int getNumFree(); void emptyFreeList(); + static void setDefaultFrameMemoryFunctions(MallocFunc_t newMalloc, + FreeFunc_t newFree); + virtual void* frameMalloc(size_t size); + virtual void frameFree(void *ptr); protected: /** The following methods should be implemented by a pool class diff --git a/ADApp/ADSrc/NDArrayPool.cpp b/ADApp/ADSrc/NDArrayPool.cpp index b28122e53..bea77dad8 100644 --- a/ADApp/ADSrc/NDArrayPool.cpp +++ b/ADApp/ADSrc/NDArrayPool.cpp @@ -29,6 +29,10 @@ static const char *driverName = "NDArrayPool"; +// This provides a way of overriding the default memory functions for frame +// buffer allocation and freeing +MallocFunc_t defaultFrameMalloc = malloc; +FreeFunc_t defaultFrameFree = free; /** eraseNDAttributes is a global flag the controls whether NDArray::clearAttributes() is called * each time a new array is allocated with NDArrayPool->alloc(). @@ -53,6 +57,41 @@ NDArrayPool::NDArrayPool(class asynNDArrayDriver *pDriver, size_t maxMemory) listLock_ = epicsMutexCreate(); } +/** Set default frame buffer allocation and deallocation functions + * \param[in] newMalloc Pointer to a function that will be used by default to + * allocate a frame buffer + * \param[in] newFree Pointer to a function that will be used by default to + * deallocate a frame buffer + * **/ +void NDArrayPool::setDefaultFrameMemoryFunctions( + MallocFunc_t newMalloc, FreeFunc_t newFree) +{ + if (newMalloc) + defaultFrameMalloc = newMalloc; + + if (newFree) + defaultFrameFree = newFree; +} + +/** Used to allocate a frame buffer + * This method can be overriden in subclasses to use custom memory allocation + * \param[in] size Required buffer size + * Returns pointer to buffer of size specified + */ +void* NDArrayPool::frameMalloc(size_t size) +{ + return defaultFrameMalloc(size); +} + +/** Used to free a frame buffer + * This method can be overriden in subclasses to use custom memory deallocation + * \param[in] ptr Pointer to memory that will be deallocated + */ +void NDArrayPool::frameFree(void *ptr) +{ + defaultFrameFree(ptr); +} + /** Create new NDArray object. * This method should be overriden by a pool class that manages objects * that derive from NDArray class. @@ -139,7 +178,7 @@ NDArray* NDArrayPool::alloc(int ndims, size_t *dims, NDDataType_t dataType, size if (pData || (pListElement->dataSize_ > (dataSize * THRESHOLD_SIZE_RATIO))) { // We found an array but it is too large. Set the size to 0 so it will be allocated below. memorySize_ -= pArray->dataSize; - free(pArray->pData); + frameFree(pArray->pData); pArray->pData = NULL; } freeList_.erase(pListElement); @@ -193,7 +232,7 @@ NDArray* NDArrayPool::alloc(int ndims, size_t *dims, NDDataType_t dataType, size "%s: error: reached limit of %ld memory (%d buffers)\n", functionName, (long)maxMemory_, numBuffers_); } else { - pArray->pData = malloc(dataSize); + pArray->pData = frameMalloc(dataSize); if (pArray->pData) { pArray->dataSize = dataSize; pArray->compressedSize = dataSize;