diff --git a/LAPACKE/include/lapacke.h b/LAPACKE/include/lapacke.h index 3ad436bad..8f63371ab 100644 --- a/LAPACKE/include/lapacke.h +++ b/LAPACKE/include/lapacke.h @@ -39,11 +39,24 @@ extern "C" { #endif /* __cplusplus */ +/* All LAPACKE-internal allocations (workspaces, row-major transposition + * buffers) go through a replaceable allocator. Defining the LAPACKE_malloc / + * LAPACKE_free macros at compile time replaces the allocator entirely. */ + +/** \brief Allocate through the installed allocator (malloc by default). */ +void *LAPACKE_malloc_proxy(size_t size); +/** \brief Release through the installed deallocator (free by default). */ +void LAPACKE_free_proxy(void *ptr); +/** \brief Install a custom allocator: malloc_fn / free_fn must form a + * matching pair; NULL restores the defaults. Mutates global state and is + * not thread-safe. */ +void LAPACKE_set_alloc(void *(*malloc_fn)(size_t), void (*free_fn)(void *)); + #ifndef LAPACKE_malloc -#define LAPACKE_malloc( size ) malloc( size ) +#define LAPACKE_malloc(size) LAPACKE_malloc_proxy(size) #endif #ifndef LAPACKE_free -#define LAPACKE_free( p ) free( p ) +#define LAPACKE_free(p) LAPACKE_free_proxy(p) #endif #define LAPACK_C2INT( x ) (lapack_int)(*((float*)&x )) diff --git a/LAPACKE/src/CMakeLists.txt b/LAPACKE/src/CMakeLists.txt index f1c12d976..843cef7a5 100644 --- a/LAPACKE/src/CMakeLists.txt +++ b/LAPACKE/src/CMakeLists.txt @@ -1208,6 +1208,7 @@ lapacke_dtzrzf_work.c ) set(COMMON_SOURCES +lapacke_alloc.c lapacke_nancheck.c ) set(SOURCES diff --git a/LAPACKE/src/Makefile b/LAPACKE/src/Makefile index 31a8e9185..ad28d3c37 100644 --- a/LAPACKE/src/Makefile +++ b/LAPACKE/src/Makefile @@ -43,6 +43,7 @@ include $(TOPSRCDIR)/make.inc OBJ = \ lapacke_ilaver.o \ +lapacke_alloc.o \ lapacke_nancheck.o OBJ_C = \ diff --git a/LAPACKE/src/lapacke_alloc.c b/LAPACKE/src/lapacke_alloc.c new file mode 100644 index 000000000..e19d1257e --- /dev/null +++ b/LAPACKE/src/lapacke_alloc.c @@ -0,0 +1,61 @@ +/***************************************************************************** + * Replaceable allocator for LAPACKE-internal allocations. + * + * The LAPACKE_malloc / LAPACKE_free macros default to the functions below, + * which forward to a run-time replaceable allocator (malloc / free until + * changed via LAPACKE_set_alloc). Like the nancheck flag, the allocator is + * shared between all APIs, so this file must be compiled exactly once, + * without an API suffix. + *****************************************************************************/ + +#include + +#include "lapacke.h" + +static void *(*lapacke_malloc_fn)(size_t) = malloc; +static void (*lapacke_free_fn)(void *) = free; + +/** + * \brief Allocate memory through the installed allocator. + * + * Default of the LAPACKE_malloc macro. + * + * \param[in] size Allocation size in bytes. + * \return The allocation, or NULL on failure. + */ +void *LAPACKE_malloc_proxy(size_t size) +{ + return lapacke_malloc_fn(size); +} + +/** + * \brief Release memory through the installed deallocator. + * + * Default of the LAPACKE_free macro. + * + * \param[in] ptr Allocation obtained through LAPACKE_malloc_proxy. + */ +void LAPACKE_free_proxy(void *ptr) +{ + lapacke_free_fn(ptr); +} + +/** + * \brief Install a custom allocator for LAPACKE-internal allocations. + * + * Subsequent LAPACKE-internal allocations (workspaces, row-major + * transposition buffers) are made with malloc_fn and released with + * free_fn. The two must form a matching pair: memory allocated with + * malloc_fn is released through free_fn, so pairing an allocator with an + * incompatible deallocator is undefined behavior. The setter mutates + * global state shared by all threads and is not thread-safe; call it + * during setup, like LAPACKE_set_nancheck. + * + * \param[in] malloc_fn Replacement for malloc; NULL restores malloc. + * \param[in] free_fn Replacement for free; NULL restores free. + */ +void LAPACKE_set_alloc(void *(*malloc_fn)(size_t), void (*free_fn)(void *)) +{ + lapacke_malloc_fn = (malloc_fn != NULL) ? malloc_fn : malloc; + lapacke_free_fn = (free_fn != NULL) ? free_fn : free; +}