Add default memory context and stdlib-like memory management
The BIND 9 memory model always requires a memory context to be used with any functions that want to allocate memory. The BIND 9 memory allocator has several advantages on top of default memory allocator (small-chunk memory allocator, memory limits, statistics, memory tracking, ...), but it also complicates some use scenarios: * Integration our memory allocator with third party libraries that usually requires standard memory functions (f.e. libuv requires malloc, calloc, realloc and free to be available) * Every single application using libisc has to create a memory context first and then pass it to underlying functions * Not even ever internal use case cares about the extra features and would benefit from not having to track the memory allocator. * Integration with external allocator libraries (tcmalloc, jemalloc) is complicated and it mostly loses the benefits of said external allocator by adding yet another layer(s) on top of it. This commit uses the constructor/destructor attribute[1] with gcc/clang and DllMain[2] with MSVC to create a default memory context that's always available and adds isc_malloc(), isc_calloc(), isc_realloc(), isc_free() and isc_strdup() set of functions that operates on top of the default memory context. 1. https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html 2. https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain
This commit is contained in:
@@ -604,6 +604,27 @@ char *ISCMEMFUNC(strndup)(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG);
|
||||
void *ISCMEMPOOLFUNC(get)(isc_mempool_t *_ISC_MEM_FLARG);
|
||||
void ISCMEMPOOLFUNC(put)(isc_mempool_t *, void *_ISC_MEM_FLARG);
|
||||
|
||||
/*
|
||||
* Memory management routines using default memory context
|
||||
*/
|
||||
|
||||
#define isc_malloc(size) isc__malloc((size)_ISC_MEM_FILELINE)
|
||||
#define isc_calloc(num, size) isc__calloc((num), (size)_ISC_MEM_FILELINE)
|
||||
#define isc_realloc(ptr, size) isc__realloc((ptr), (size)_ISC_MEM_FILELINE)
|
||||
#define isc_free(ptr) isc__free((ptr)_ISC_MEM_FILELINE)
|
||||
#define isc_strdup(str) isc__strdup((str)_ISC_MEM_FILELINE)
|
||||
|
||||
void *
|
||||
isc__malloc(size_t size _ISC_MEM_FLARG);
|
||||
void *
|
||||
isc__calloc(size_t num, size_t size _ISC_MEM_FLARG);
|
||||
void *
|
||||
isc__realloc(void *ptr, size_t size _ISC_MEM_FLARG);
|
||||
void
|
||||
isc__free(void *ptr _ISC_MEM_FLARG);
|
||||
char *
|
||||
isc__strdup(const char *str _ISC_MEM_FLARG);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* ISC_MEM_H */
|
||||
|
||||
@@ -48,6 +48,14 @@
|
||||
#define ISC_NONSTRING
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#if __GNUC__
|
||||
#define ISC_CONSTRUCTOR(priority) __attribute__((constructor(priority)))
|
||||
#define ISC_DESTRUCTOR(priority) __attribute__((destructor(priority)))
|
||||
#else
|
||||
#define ISC_CONSTRUCTOR(priority)
|
||||
#define ISC_DESTRUCTOR(priority)
|
||||
#endif
|
||||
|
||||
/*%
|
||||
* The opposite: silent warnings about stored values which are never read.
|
||||
*/
|
||||
@@ -340,6 +348,15 @@ mock_assert(const int result, const char *const expression,
|
||||
#define ISC_ALIGN(x, a) (((x) + (a)-1) & ~((uintmax_t)(a)-1))
|
||||
#endif /* ifdef __GNUC__ */
|
||||
|
||||
/*%
|
||||
* Overflow checks
|
||||
*/
|
||||
#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5
|
||||
#define ISC_MUL_OVERFLOW(a, b, res) __builtin_mul_overflow(a, b, res)
|
||||
#else
|
||||
#define ISC_MUL_OVERFLOW(a, b, res) ((*res) = (a) * (b))
|
||||
#endif
|
||||
|
||||
/*%
|
||||
* Misc
|
||||
*/
|
||||
|
||||
@@ -2520,3 +2520,60 @@ isc__mem_printactive(isc_mem_t *ctx0, FILE *file) {
|
||||
UNUSED(file);
|
||||
#endif /* if ISC_MEM_TRACKLINES */
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines using default memory context
|
||||
*/
|
||||
|
||||
static isc_mem_t *isc__mem_mctx = NULL;
|
||||
|
||||
void
|
||||
isc__mem_initialize(void);
|
||||
void
|
||||
isc__mem_shutdown(void);
|
||||
|
||||
ISC_CONSTRUCTOR(101)
|
||||
void
|
||||
isc__mem_initialize(void) {
|
||||
REQUIRE(isc__mem_mctx == NULL);
|
||||
isc_mem_create(&isc__mem_mctx);
|
||||
isc_mem_setname(isc__mem_mctx, "default", NULL);
|
||||
}
|
||||
|
||||
ISC_DESTRUCTOR(101)
|
||||
void
|
||||
isc__mem_shutdown(void) {
|
||||
REQUIRE(isc__mem_mctx != NULL);
|
||||
isc_mem_destroy(&isc__mem_mctx);
|
||||
isc_mem_checkdestroyed(stderr);
|
||||
}
|
||||
|
||||
void *
|
||||
isc__malloc(size_t size FLARG) {
|
||||
return (isc__mem_allocate(isc__mem_mctx, size FLARG_PASS));
|
||||
}
|
||||
|
||||
void *
|
||||
isc__calloc(size_t num, size_t size FLARG) {
|
||||
size_t numsize;
|
||||
|
||||
ISC_MUL_OVERFLOW(num, size, &numsize);
|
||||
void *ptr = isc__mem_allocate(isc__mem_mctx, numsize FLARG_PASS);
|
||||
memset(ptr, 0, numsize);
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
void *
|
||||
isc__realloc(void *ptr, size_t size FLARG) {
|
||||
return (isc__mem_reallocate(isc__mem_mctx, ptr, size FLARG_PASS));
|
||||
}
|
||||
|
||||
void
|
||||
isc__free(void *ptr FLARG) {
|
||||
isc__mem_free(isc__mem_mctx, ptr FLARG_PASS);
|
||||
}
|
||||
|
||||
char *
|
||||
isc__strdup(const char *s1 FLARG) {
|
||||
return (isc__mem_strdup(isc__mem_mctx, s1 FLARG_PASS));
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
void
|
||||
isc__mem_initialize(void);
|
||||
void
|
||||
isc__mem_shutdown(void);
|
||||
|
||||
/*
|
||||
* Called when we enter the DLL
|
||||
*/
|
||||
@@ -27,6 +32,7 @@ __declspec(dllexport) BOOL WINAPI
|
||||
* Disable DllMain() invocation on Thread creation/destruction
|
||||
*/
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
isc__mem_initialize(); /* priority=101 */
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -34,6 +40,7 @@ __declspec(dllexport) BOOL WINAPI
|
||||
* termination or a call to FreeLibrary.
|
||||
*/
|
||||
case DLL_PROCESS_DETACH:
|
||||
isc__mem_shutdown(); /* priority=101 */
|
||||
break;
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
|
||||
Reference in New Issue
Block a user