Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,20 @@ void *VM_TryRealloc(void *ptr, size_t bytes) {
return ztryrealloc_usable(ptr, bytes, NULL);
}

/* Use like posix_memalign(). Memory allocated with this function is reported in
* INFO memory, used for keys eviction according to maxmemory settings
* and in general is taken into account as memory allocated by the server.
* You should avoid using posix_memalign() directly. */
void *VM_Memalign(size_t alignment, size_t bytes) {
return zmemalign_usable(alignment, bytes, NULL);
}

/* Similar to VM_Memalign, but returns NULL in case of allocation failure,
* instead of panicking. */
void *VM_TryMemalign(size_t alignment, size_t bytes) {
return ztrymemalign_usable(alignment, bytes, NULL);
}

/* Use like free() for memory obtained by ValkeyModule_Alloc() and
* ValkeyModule_Realloc(). However you should never try to free with
* ValkeyModule_Free() memory allocated with malloc() inside your module. */
Expand Down Expand Up @@ -14004,6 +14018,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(TryCalloc);
REGISTER_API(Realloc);
REGISTER_API(TryRealloc);
REGISTER_API(Memalign);
REGISTER_API(TryMemalign);
REGISTER_API(Free);
REGISTER_API(Strdup);
REGISTER_API(CreateCommand);
Expand Down
4 changes: 4 additions & 0 deletions src/valkeymodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,8 @@ VALKEYMODULE_API void *(*ValkeyModule_TryRealloc)(void *ptr, size_t bytes)VALKEY
VALKEYMODULE_API void (*ValkeyModule_Free)(void *ptr) VALKEYMODULE_ATTR;
VALKEYMODULE_API void *(*ValkeyModule_Calloc)(size_t nmemb, size_t size)VALKEYMODULE_ATTR;
VALKEYMODULE_API void *(*ValkeyModule_TryCalloc)(size_t nmemb, size_t size)VALKEYMODULE_ATTR;
VALKEYMODULE_API void *(*ValkeyModule_Memalign)(size_t alignment, size_t bytes)VALKEYMODULE_ATTR;
VALKEYMODULE_API void *(*ValkeyModule_TryMemalign)(size_t alignment, size_t bytes)VALKEYMODULE_ATTR;
VALKEYMODULE_API char *(*ValkeyModule_Strdup)(const char *str)VALKEYMODULE_ATTR;
VALKEYMODULE_API int (*ValkeyModule_GetApi)(const char *, void *) VALKEYMODULE_ATTR;
VALKEYMODULE_API int (*ValkeyModule_CreateCommand)(ValkeyModuleCtx *ctx,
Expand Down Expand Up @@ -1969,6 +1971,8 @@ static int ValkeyModule_Init(ValkeyModuleCtx *ctx, const char *name, int ver, in
VALKEYMODULE_GET_API(Free);
VALKEYMODULE_GET_API(Realloc);
VALKEYMODULE_GET_API(TryRealloc);
VALKEYMODULE_GET_API(Memalign);
VALKEYMODULE_GET_API(TryMemalign);
VALKEYMODULE_GET_API(Strdup);
VALKEYMODULE_GET_API(CreateCommand);
VALKEYMODULE_GET_API(GetCommand);
Expand Down
76 changes: 76 additions & 0 deletions src/zmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>

#ifdef __linux__
#include <sys/mman.h>
Expand Down Expand Up @@ -77,12 +78,14 @@ void zlibc_free(void *ptr) {
#define malloc(size) tc_malloc(size)
#define calloc(count, size) tc_calloc(count, size)
#define realloc(ptr, size) tc_realloc(ptr, size)
#define posix_memalign(ptr,alignment,size) tc_posix_memalign(ptr,alignment,size)
#define free(ptr) tc_free(ptr)
/* Explicitly override malloc/free etc when using jemalloc. */
#elif defined(USE_JEMALLOC)
#define malloc(size) je_malloc(size)
#define calloc(count, size) je_calloc(count, size)
#define realloc(ptr, size) je_realloc(ptr, size)
#define posix_memalign(ptr,alignment,size) je_posix_memalign(ptr,alignment,size)
#define free(ptr) je_free(ptr)
#endif

Expand Down Expand Up @@ -369,6 +372,79 @@ void *zrealloc_usable(void *ptr, size_t size, size_t *usable) {
return ptr;
}

static inline void *ztrymemalign_usable_internal(size_t alignment, size_t size, size_t *usable, int *ret) {
/* Possible overflow, return NULL, so that the caller can panic or handle a failed allocation. */
if (size >= SIZE_MAX/2) return NULL;
void *ptr = NULL;

int memalign_ret = posix_memalign(&ptr, alignment, MALLOC_MIN_SIZE(size)+PREFIX_SIZE);
if (ret) *ret = memalign_ret;
if (memalign_ret != 0) return NULL;

#ifdef HAVE_MALLOC_SIZE
size = zmalloc_size(ptr);
update_zmalloc_stat_alloc(size);
if (usable) *usable = size;
return ptr;
#else
*((size_t*)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
if (usable) *usable = size;
return (char*)ptr+PREFIX_SIZE;
#endif
}

static void zmemalign_default_inval(size_t alignment, size_t size) {
fprintf(stderr, "zmemalign: Invalid params trying to zmemalign %zu,%zu bytes\n",
alignment, size);
fflush(stderr);
abort();
}

static void (*zmemalign_inval_handler)(size_t, size_t) = zmemalign_default_inval;

void *zmemalign(size_t alignment, size_t size) {
int ret = 0;
void *ptr = ztrymemalign_usable_internal(alignment, size, NULL, &ret);
if (!ptr) {
if (ret == ENOMEM) zmalloc_oom_handler(size);
else if (ret == EINVAL) zmemalign_inval_handler(alignment, size);
}
return ptr;

}

void *ztrymemalign(size_t alignment, size_t size) {
void *ptr = ztrymemalign_usable_internal(alignment, size, NULL, NULL);
return ptr;
}

void *zmemalign_usable(size_t alignment, size_t size, size_t *usable) {
int ret = 0;
size_t usable_size = 0;
void *ptr = ztrymemalign_usable_internal(alignment, size, &usable_size, &ret);
if (!ptr) {
if (ret == ENOMEM) zmalloc_oom_handler(size);
else if (ret == EINVAL) zmemalign_default_inval(alignment, size);
/* never touch */
}
#ifdef HAVE_MALLOC_SIZE
ptr = extend_to_usable(ptr, usable_size);
#endif
if (usable) *usable = usable_size;
return ptr;
}

void *ztrymemalign_usable(size_t alignment, size_t size, size_t *usable) {
size_t usable_size = 0;
void *ptr = ztrymemalign_usable_internal(alignment, size, &usable_size, NULL);
#ifdef HAVE_MALLOC_SIZE
ptr = extend_to_usable(ptr, usable_size);
#endif
if (usable) *usable = usable_size;
return ptr;
}

/* Provide zmalloc_size() for systems where this function is not provided by
* malloc itself, given that in that case we store a header with this
* information as the first bytes of every allocation. */
Expand Down
4 changes: 4 additions & 0 deletions src/zmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,21 @@ __attribute__((malloc, alloc_size(1), noinline)) void *zmalloc(size_t size);
__attribute__((malloc, alloc_size(1), noinline)) void *zcalloc(size_t size);
__attribute__((malloc, alloc_size(1, 2), noinline)) void *zcalloc_num(size_t num, size_t size);
__attribute__((alloc_size(2), noinline)) void *zrealloc(void *ptr, size_t size);
__attribute__((malloc, alloc_size(2), noinline)) void *zmemalign(size_t alignment, size_t size);
__attribute__((malloc, alloc_size(1), noinline)) void *ztrymalloc(size_t size);
__attribute__((malloc, alloc_size(1), noinline)) void *ztrycalloc(size_t size);
__attribute__((alloc_size(2), noinline)) void *ztryrealloc(void *ptr, size_t size);
__attribute__((malloc, alloc_size(2), noinline)) void *ztrymemalign(size_t alignment, size_t size);
void zfree(void *ptr);
void zfree_with_size(void *ptr, size_t size);
void *zmalloc_usable(size_t size, size_t *usable);
void *zcalloc_usable(size_t size, size_t *usable);
void *zrealloc_usable(void *ptr, size_t size, size_t *usable);
void *zmemalign_usable(size_t alignment, size_t size, size_t *usable);
void *ztrymalloc_usable(size_t size, size_t *usable);
void *ztrycalloc_usable(size_t size, size_t *usable);
void *ztryrealloc_usable(void *ptr, size_t size, size_t *usable);
void *ztrymemalign_usable(size_t alignment, size_t size, size_t *usable);
__attribute__((malloc)) char *zstrdup(const char *s);
size_t zmalloc_used_memory(void);
void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
Expand Down