Skip to content

load ctl defaults from env variable/file #1457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 31, 2025
Merged
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
7 changes: 2 additions & 5 deletions src/ctl/ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Expand All @@ -33,8 +34,6 @@

#ifdef _WIN32
#define strtok_r strtok_s
#else
#include <stdio.h>
#endif

#define MAX_CONFIG_FILE_LEN (1 << 20) /* 1 megabyte */
Expand Down Expand Up @@ -578,7 +577,7 @@ static umf_result_t ctl_load_config_helper(struct ctl *ctl, void *ctx,
// we do not need to copy va_list before call as we know that for query_config_input
// ctl_query will not call va_arg on it. Ref 7.15/3 of C99 standard
ret = ctl_query(ctl, ctx, CTL_QUERY_CONFIG_INPUT, name, CTL_QUERY_WRITE,
value, 0, empty_args);
value, strlen(value) + 1, empty_args);

if (ret != UMF_RESULT_SUCCESS && ctx != NULL) {
goto end;
Expand Down Expand Up @@ -621,7 +620,6 @@ umf_result_t ctl_load_config_from_string(struct ctl *ctl, void *ctx,
* This function opens up the config file, allocates a buffer of size equal to
* the size of the file, reads its content and sanitizes it for ctl_load_config.
*/
#ifndef _WIN32 // TODO: implement for Windows
umf_result_t ctl_load_config_from_file(struct ctl *ctl, void *ctx,
const char *cfg_file) {
umf_result_t ret = UMF_RESULT_ERROR_UNKNOWN;
Expand Down Expand Up @@ -679,7 +677,6 @@ umf_result_t ctl_load_config_from_file(struct ctl *ctl, void *ctx,
(void)fclose(fp);
return ret;
}
#endif

/*
* ctl_parse_ll -- (internal) parses and returns a long long signed integer
Expand Down
1 change: 0 additions & 1 deletion src/ctl/ctl_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ struct ctl {
int first_free;
};

void initialize_global_ctl(void);
void ctl_init(void *(*Malloc)(size_t), void (*Free)(void *));

umf_result_t ctl_load_config_from_string(struct ctl *ctl, void *ctx,
Expand Down
28 changes: 25 additions & 3 deletions src/libumf.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "base_alloc_global.h"
#include "ctl/ctl_internal.h"
#include "ipc_cache.h"
#include "libumf.h"
#include "memory_pool_internal.h"
#include "memory_provider_internal.h"
#include "memspace_internal.h"
Expand All @@ -37,7 +38,23 @@ static void initialize_init_mutex(void) { utils_mutex_init(&initMutex); }
static umf_ctl_node_t CTL_NODE(umf)[] = {CTL_CHILD(provider), CTL_CHILD(pool),
CTL_CHILD(logger), CTL_NODE_END};

void initialize_global_ctl(void) { CTL_REGISTER_MODULE(NULL, umf); }
void initialize_ctl(void) {
ctl_init(umf_ba_global_alloc, umf_ba_global_free);

CTL_REGISTER_MODULE(NULL, umf);
const char *env_var = getenv("UMF_CONF");
if (env_var && env_var[0] != '\0') {
LOG_INFO("Loading UMF configuration from environment variable: %s",
env_var);
ctl_load_config_from_string(NULL, NULL, env_var);
}

const char *file_var = getenv("UMF_CONF_FILE");
if (file_var && file_var[0] != '\0') {
LOG_INFO("Loading UMF configuration from file: %s", file_var);
ctl_load_config_from_file(NULL, NULL, file_var);
}
}

umf_result_t umfInit(void) {
utils_init_once(&initMutexOnce, initialize_init_mutex);
Expand All @@ -46,6 +63,8 @@ umf_result_t umfInit(void) {

if (umfRefCount == 0) {
utils_log_init();
initialize_ctl();

umf_result_t umf_result = umfMemoryTrackerCreate(&TRACKER);
if (umf_result != UMF_RESULT_SUCCESS) {
LOG_ERR("Failed to create memory tracker");
Expand All @@ -64,8 +83,6 @@ umf_result_t umfInit(void) {
}

LOG_DEBUG("UMF IPC cache initialized");
ctl_init(umf_ba_global_alloc, umf_ba_global_free);
initialize_global_ctl();
}

umfRefCount++;
Expand Down Expand Up @@ -111,6 +128,8 @@ umf_result_t umfTearDown(void) {
umfMemoryTrackerDestroy(t);
LOG_DEBUG("UMF tracker destroyed");

umfPoolCtlDefaultsDestroy();

umf_ba_destroy_global();
LOG_DEBUG("UMF base allocator destroyed");

Expand All @@ -127,6 +146,7 @@ umf_result_t umfTearDown(void) {
int umfGetCurrentVersion(void) { return UMF_VERSION_CURRENT; }

umf_result_t umfCtlGet(const char *name, void *arg, size_t size, ...) {
libumfInit();
// ctx can be NULL when getting defaults
if (name == NULL || arg == NULL || size == 0) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
Expand All @@ -141,6 +161,7 @@ umf_result_t umfCtlGet(const char *name, void *arg, size_t size, ...) {
}

umf_result_t umfCtlSet(const char *name, void *arg, size_t size, ...) {
libumfInit();
// ctx can be NULL when setting defaults
if (name == NULL || arg == NULL || size == 0) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
Expand All @@ -154,6 +175,7 @@ umf_result_t umfCtlSet(const char *name, void *arg, size_t size, ...) {
}

umf_result_t umfCtlExec(const char *name, void *arg, size_t size, ...) {
libumfInit();
// arg can be NULL when executing a command
// ctx can be NULL when executing defaults
// size can depends on the arg
Expand Down
151 changes: 110 additions & 41 deletions src/memory_pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,21 @@
#include "utils_assert.h"
#include "utils_concurrency.h"
#include "utils_log.h"
#include "utlist.h"

#define UMF_DEFAULT_SIZE 100
#define UMF_DEFAULT_LEN 100
typedef struct ctl_default_entry_t {
char *name;
void *value;
size_t value_size;
umf_ctl_query_source_t source;
struct ctl_default_entry_t *next;
} ctl_default_entry_t;

static ctl_default_entry_t *ctl_default_list = NULL;

utils_mutex_t ctl_mtx;
static UTIL_ONCE_FLAG mem_pool_ctl_initialized = UTIL_ONCE_FLAG_INIT;

char CTL_DEFAULT_ENTRIES[UMF_DEFAULT_SIZE][UMF_DEFAULT_LEN] = {0};
char CTL_DEFAULT_VALUES[UMF_DEFAULT_SIZE][UMF_DEFAULT_LEN] = {0};

static struct ctl umf_pool_ctl_root;

static void pool_ctl_init(void);
Expand Down Expand Up @@ -79,36 +84,76 @@ static umf_result_t CTL_SUBTREE_HANDLER(default)(

utils_mutex_lock(&ctl_mtx);

ctl_default_entry_t *entry = NULL;
LL_FOREACH(ctl_default_list, entry) {
if (strcmp(entry->name, extra_name) == 0) {
break;
}
}

if (queryType == CTL_QUERY_WRITE) {
int i = 0;
for (; i < UMF_DEFAULT_SIZE; i++) {
if (CTL_DEFAULT_ENTRIES[i][0] == '\0' ||
strcmp(CTL_DEFAULT_ENTRIES[i], extra_name) == 0) {
strncpy(CTL_DEFAULT_ENTRIES[i], extra_name, UMF_DEFAULT_LEN);
CTL_DEFAULT_ENTRIES[i][UMF_DEFAULT_LEN - 1] = '\0';
strncpy(CTL_DEFAULT_VALUES[i], arg, UMF_DEFAULT_LEN);
CTL_DEFAULT_VALUES[i][UMF_DEFAULT_LEN - 1] = '\0';
break;
bool is_new_entry = false;
if (entry == NULL) {
entry = umf_ba_global_alloc(sizeof(*entry));
if (entry == NULL) {
utils_mutex_unlock(&ctl_mtx);
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

entry->name = NULL;
entry->value = NULL;
entry->next = NULL;
is_new_entry = true;
}
if (UMF_DEFAULT_SIZE == i) {
LOG_ERR("Default entries array is full");

size_t name_len = strlen(extra_name) + 1;
char *new_name = umf_ba_global_alloc(name_len);
if (new_name == NULL) {
utils_mutex_unlock(&ctl_mtx);
return UMF_RESULT_ERROR_OUT_OF_RESOURCES;
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}
} else if (queryType == CTL_QUERY_READ) {
int i = 0;
for (; i < UMF_DEFAULT_SIZE; i++) {
if (strcmp(CTL_DEFAULT_ENTRIES[i], extra_name) == 0) {
strncpy(arg, CTL_DEFAULT_VALUES[i], size);
break;

memcpy(new_name, extra_name, name_len);
if (entry->name) {
umf_ba_global_free(entry->name);
}
entry->name = new_name;

void *new_value = NULL;
if (size > 0) {
new_value = umf_ba_global_alloc(size);
if (new_value == NULL) {
utils_mutex_unlock(&ctl_mtx);
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}
memcpy(new_value, arg, size);
}
if (UMF_DEFAULT_SIZE == i) {

if (entry->value) {
umf_ba_global_free(entry->value);
}

entry->value = new_value;
entry->value_size = size;
entry->source = source;

if (is_new_entry) {
LL_APPEND(ctl_default_list, entry);
}
} else if (queryType == CTL_QUERY_READ) {
if (entry == NULL) {
LOG_WARN("Wrong path name: %s", extra_name);
utils_mutex_unlock(&ctl_mtx);
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

if (entry->value_size > size) {
LOG_ERR("Provided buffer size %zu is smaller than field size %zu",
size, entry->value_size);
utils_mutex_unlock(&ctl_mtx);
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}
memcpy(arg, entry->value, entry->value_size);
}

utils_mutex_unlock(&ctl_mtx);
Expand Down Expand Up @@ -174,12 +219,11 @@ static const umf_pool_create_flags_t UMF_POOL_CREATE_FLAG_ALL =
// windows do not allow to use uninitialized va_list so this function help us to initialize it.
static umf_result_t default_ctl_helper(const umf_memory_pool_ops_t *ops,
void *ctl, const char *name, void *arg,
...) {
size_t size, ...) {
va_list empty_args;
va_start(empty_args, arg);
umf_result_t ret =
ops->ext_ctl(ctl, CTL_QUERY_PROGRAMMATIC, name, arg, UMF_DEFAULT_LEN,
CTL_QUERY_WRITE, empty_args);
va_start(empty_args, size);
umf_result_t ret = ops->ext_ctl(ctl, CTL_QUERY_PROGRAMMATIC, name, arg,
size, CTL_QUERY_WRITE, empty_args);
va_end(empty_args);
return ret;
}
Expand Down Expand Up @@ -246,18 +290,23 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
}

// Set default property "name" to pool if exists
for (int i = 0; i < UMF_DEFAULT_SIZE; i++) {
const char *pname = NULL;
ret = ops->get_name(NULL, &pname);
if (ret != UMF_RESULT_SUCCESS) {
LOG_ERR("Failed to get pool name");
goto err_pool_init;
}
if (CTL_DEFAULT_ENTRIES[i][0] != '\0' && pname &&
strstr(CTL_DEFAULT_ENTRIES[i], pname)) {

default_ctl_helper(ops, pool->pool_priv, CTL_DEFAULT_ENTRIES[i],
CTL_DEFAULT_VALUES[i]);
const char *pname = NULL;
ret = ops->get_name(NULL, &pname);
if (ret != UMF_RESULT_SUCCESS) {
LOG_ERR("Failed to get pool name");
goto err_pool_init;
}
assert(pname != NULL);
Copy link
Contributor

@KFilipek KFilipek Jul 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Pointers can be directly handled:

assert(pname);


size_t pname_len = strlen(pname);
ctl_default_entry_t *it = NULL;
LL_FOREACH(ctl_default_list, it) {
if (strlen(it->name) > pname_len + 1 &&
strncmp(it->name, pname, pname_len) == 0 &&
it->name[pname_len] == '.') {
const char *ctl_name = it->name + pname_len + 1;
default_ctl_helper(ops, pool->pool_priv, ctl_name, it->value,
it->value_size);
}
}

Expand Down Expand Up @@ -454,3 +503,23 @@ umf_result_t umfPoolGetTag(umf_memory_pool_handle_t hPool, void **tag) {
utils_mutex_unlock(&hPool->lock);
return UMF_RESULT_SUCCESS;
}

void umfPoolCtlDefaultsDestroy(void) {
utils_init_once(&mem_pool_ctl_initialized, pool_ctl_init);

utils_mutex_lock(&ctl_mtx);

ctl_default_entry_t *entry = NULL, *tmp = NULL;
LL_FOREACH_SAFE(ctl_default_list, entry, tmp) {
LL_DELETE(ctl_default_list, entry);
if (entry->name) {
umf_ba_global_free(entry->name);
}
if (entry->value) {
umf_ba_global_free(entry->value);
}
umf_ba_global_free(entry);
}

utils_mutex_unlock(&ctl_mtx);
}
2 changes: 2 additions & 0 deletions src/memory_pool_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ typedef struct umf_memory_pool_t {

extern umf_ctl_node_t CTL_NODE(pool)[];

void umfPoolCtlDefaultsDestroy(void);

#ifdef __cplusplus
}
#endif
Expand Down
20 changes: 20 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,26 @@ if(LINUX)
LIBS ${UMF_UTILS_FOR_TEST})
endif()

build_umf_test(
NAME ctl_env_app
SRCS ctl/ctl_env_app.cpp
LIBS ${UMF_UTILS_FOR_TEST} umf)

file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ctl/ctl_env_config1.cfg
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ctl)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ctl/ctl_env_config2.cfg
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ctl)

add_umf_test(
NAME ctl_env_driver
SRCS ctl/ctl_env_driver.cpp
LIBS ${UMF_UTILS_FOR_TEST})

target_compile_definitions(
test_ctl_env_driver
PRIVATE CTL_ENV_APP="$<TARGET_FILE:test_ctl_env_app>"
CTL_CONF_FILE_DIR="${CMAKE_CURRENT_BINARY_DIR}/ctl")

add_umf_test(
NAME coarse_lib
SRCS coarse_lib.cpp
Expand Down
Loading