Skip to content

Commit ae0180c

Browse files
committed
load ctl defaults from env variable/file
1 parent fe3aea6 commit ae0180c

File tree

9 files changed

+358
-48
lines changed

9 files changed

+358
-48
lines changed

src/ctl/ctl.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <limits.h>
2121
#include <stdarg.h>
2222
#include <stdint.h>
23+
#include <stdio.h>
2324
#include <stdlib.h>
2425
#include <string.h>
2526

@@ -33,8 +34,6 @@
3334

3435
#ifdef _WIN32
3536
#define strtok_r strtok_s
36-
#else
37-
#include <stdio.h>
3837
#endif
3938

4039
#define MAX_CONFIG_FILE_LEN (1 << 20) /* 1 megabyte */
@@ -566,7 +565,7 @@ static umf_result_t ctl_load_config_helper(struct ctl *ctl, void *ctx,
566565
// we do not need to copy va_list before call as we know that for query_config_input
567566
// ctl_query will not call va_arg on it. Ref 7.15/3 of C99 standard
568567
ret = ctl_query(ctl, ctx, CTL_QUERY_CONFIG_INPUT, name, CTL_QUERY_WRITE,
569-
value, 0, empty_args);
568+
value, strlen(value) + sizeof('\0'), empty_args);
570569

571570
if (ret != UMF_RESULT_SUCCESS && ctx != NULL) {
572571
goto end;
@@ -609,7 +608,6 @@ umf_result_t ctl_load_config_from_string(struct ctl *ctl, void *ctx,
609608
* This function opens up the config file, allocates a buffer of size equal to
610609
* the size of the file, reads its content and sanitizes it for ctl_load_config.
611610
*/
612-
#ifndef _WIN32 // TODO: implement for Windows
613611
umf_result_t ctl_load_config_from_file(struct ctl *ctl, void *ctx,
614612
const char *cfg_file) {
615613
umf_result_t ret = UMF_RESULT_ERROR_UNKNOWN;
@@ -667,7 +665,6 @@ umf_result_t ctl_load_config_from_file(struct ctl *ctl, void *ctx,
667665
(void)fclose(fp);
668666
return ret;
669667
}
670-
#endif
671668

672669
/*
673670
* ctl_parse_ll -- (internal) parses and returns a long long signed integer

src/libumf.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,21 @@ static void initialize_init_mutex(void) { utils_mutex_init(&initMutex); }
3838
static umf_ctl_node_t CTL_NODE(umf)[] = {CTL_CHILD(provider), CTL_CHILD(pool),
3939
CTL_NODE_END};
4040

41-
void initialize_global_ctl(void) { CTL_REGISTER_MODULE(NULL, umf); }
41+
void initialize_ctl(void) {
42+
CTL_REGISTER_MODULE(NULL, umf);
43+
const char *env_var = getenv("UMF_CONF");
44+
if (env_var && env_var[0] != '\0') {
45+
LOG_INFO("Loading UMF configuration from environment variable: %s",
46+
env_var);
47+
ctl_load_config_from_string(NULL, NULL, env_var);
48+
}
49+
50+
const char *file_var = getenv("UMF_CONF_FILE");
51+
if (file_var && file_var[0] != '\0') {
52+
LOG_INFO("Loading UMF configuration from file: %s", file_var);
53+
ctl_load_config_from_file(NULL, NULL, file_var);
54+
}
55+
}
4256

4357
umf_result_t umfInit(void) {
4458
utils_init_once(&initMutexOnce, initialize_init_mutex);
@@ -47,6 +61,8 @@ umf_result_t umfInit(void) {
4761

4862
if (umfRefCount == 0) {
4963
utils_log_init();
64+
initialize_ctl();
65+
5066
umf_result_t umf_result = umfMemoryTrackerCreate(&TRACKER);
5167
if (umf_result != UMF_RESULT_SUCCESS) {
5268
LOG_ERR("Failed to create memory tracker");
@@ -65,7 +81,6 @@ umf_result_t umfInit(void) {
6581
}
6682

6783
LOG_DEBUG("UMF IPC cache initialized");
68-
initialize_global_ctl();
6984
}
7085

7186
umfRefCount++;
@@ -111,6 +126,8 @@ umf_result_t umfTearDown(void) {
111126
umfMemoryTrackerDestroy(t);
112127
LOG_DEBUG("UMF tracker destroyed");
113128

129+
umfPoolCtlDefaultsDestroy();
130+
114131
umf_ba_destroy_global();
115132
LOG_DEBUG("UMF base allocator destroyed");
116133

src/memory_pool.c

Lines changed: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,21 @@
2424
#include "utils_assert.h"
2525
#include "utils_concurrency.h"
2626
#include "utils_log.h"
27+
#include "utlist.h"
2728

28-
#define UMF_DEFAULT_SIZE 100
29-
#define UMF_DEFAULT_LEN 100
29+
typedef struct ctl_default_entry_t {
30+
char *name;
31+
void *value;
32+
size_t value_size;
33+
umf_ctl_query_source_t source;
34+
struct ctl_default_entry_t *next;
35+
} ctl_default_entry_t;
36+
37+
static ctl_default_entry_t *ctl_default_list = NULL;
3038

3139
utils_mutex_t ctl_mtx;
3240
static UTIL_ONCE_FLAG mem_pool_ctl_initialized = UTIL_ONCE_FLAG_INIT;
3341

34-
char CTL_DEFAULT_ENTRIES[UMF_DEFAULT_SIZE][UMF_DEFAULT_LEN] = {0};
35-
char CTL_DEFAULT_VALUES[UMF_DEFAULT_SIZE][UMF_DEFAULT_LEN] = {0};
36-
3742
static struct ctl umf_pool_ctl_root;
3843

3944
static void ctl_init(void);
@@ -79,36 +84,74 @@ static umf_result_t CTL_SUBTREE_HANDLER(default)(
7984

8085
utils_mutex_lock(&ctl_mtx);
8186

87+
ctl_default_entry_t *entry = NULL;
88+
LL_FOREACH(ctl_default_list, entry) {
89+
if (strcmp(entry->name, extra_name) == 0) {
90+
break;
91+
}
92+
}
93+
8294
if (queryType == CTL_QUERY_WRITE) {
83-
int i = 0;
84-
for (; i < UMF_DEFAULT_SIZE; i++) {
85-
if (CTL_DEFAULT_ENTRIES[i][0] == '\0' ||
86-
strcmp(CTL_DEFAULT_ENTRIES[i], extra_name) == 0) {
87-
strncpy(CTL_DEFAULT_ENTRIES[i], extra_name, UMF_DEFAULT_LEN);
88-
CTL_DEFAULT_ENTRIES[i][UMF_DEFAULT_LEN - 1] = '\0';
89-
strncpy(CTL_DEFAULT_VALUES[i], arg, UMF_DEFAULT_LEN);
90-
CTL_DEFAULT_VALUES[i][UMF_DEFAULT_LEN - 1] = '\0';
91-
break;
95+
bool is_new_entry = false;
96+
if (entry == NULL) {
97+
entry = umf_ba_global_alloc(sizeof(*entry));
98+
if (entry == NULL) {
99+
utils_mutex_unlock(&ctl_mtx);
100+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
92101
}
102+
103+
entry->name = NULL;
104+
entry->value = NULL;
105+
entry->next = NULL;
106+
is_new_entry = true;
93107
}
94-
if (UMF_DEFAULT_SIZE == i) {
95-
LOG_ERR("Default entries array is full");
108+
109+
size_t name_len = strlen(extra_name) + 1;
110+
char *new_name = umf_ba_global_alloc(name_len);
111+
if (new_name == NULL) {
96112
utils_mutex_unlock(&ctl_mtx);
97-
return UMF_RESULT_ERROR_OUT_OF_RESOURCES;
113+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
98114
}
99-
} else if (queryType == CTL_QUERY_READ) {
100-
int i = 0;
101-
for (; i < UMF_DEFAULT_SIZE; i++) {
102-
if (strcmp(CTL_DEFAULT_ENTRIES[i], extra_name) == 0) {
103-
strncpy(arg, CTL_DEFAULT_VALUES[i], size);
104-
break;
115+
116+
memcpy(new_name, extra_name, name_len);
117+
if (entry->name) {
118+
umf_ba_global_free(entry->name);
119+
}
120+
entry->name = new_name;
121+
122+
void *new_value = NULL;
123+
if (size > 0) {
124+
new_value = umf_ba_global_alloc(size);
125+
if (new_value == NULL) {
126+
utils_mutex_unlock(&ctl_mtx);
127+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
105128
}
129+
memcpy(new_value, arg, size);
106130
}
107-
if (UMF_DEFAULT_SIZE == i) {
131+
132+
if (entry->value) {
133+
umf_ba_global_free(entry->value);
134+
}
135+
136+
entry->value = new_value;
137+
entry->value_size = size;
138+
entry->source = source;
139+
140+
if (is_new_entry) {
141+
LL_APPEND(ctl_default_list, entry);
142+
}
143+
} else if (queryType == CTL_QUERY_READ) {
144+
if (entry == NULL) {
108145
LOG_WARN("Wrong path name: %s", extra_name);
109146
utils_mutex_unlock(&ctl_mtx);
110147
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
111148
}
149+
150+
if (entry->value_size < size) {
151+
utils_mutex_unlock(&ctl_mtx);
152+
LOG_ERR("arg size too small");
153+
}
154+
memcpy(arg, entry->value, entry->value_size);
112155
}
113156

114157
utils_mutex_unlock(&ctl_mtx);
@@ -174,12 +217,11 @@ static const umf_pool_create_flags_t UMF_POOL_CREATE_FLAG_ALL =
174217
// windows do not allow to use uninitialized va_list so this function help us to initialize it.
175218
static umf_result_t default_ctl_helper(const umf_memory_pool_ops_t *ops,
176219
void *ctl, const char *name, void *arg,
177-
...) {
220+
size_t size, ...) {
178221
va_list empty_args;
179-
va_start(empty_args, arg);
180-
umf_result_t ret =
181-
ops->ext_ctl(ctl, CTL_QUERY_PROGRAMMATIC, name, arg, UMF_DEFAULT_LEN,
182-
CTL_QUERY_WRITE, empty_args);
222+
va_start(empty_args, size);
223+
umf_result_t ret = ops->ext_ctl(ctl, CTL_QUERY_PROGRAMMATIC, name, arg,
224+
size, CTL_QUERY_WRITE, empty_args);
183225
va_end(empty_args);
184226
return ret;
185227
}
@@ -246,18 +288,23 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops,
246288
}
247289

248290
// Set default property "name" to pool if exists
249-
for (int i = 0; i < UMF_DEFAULT_SIZE; i++) {
250-
const char *pname = NULL;
251-
ret = ops->get_name(NULL, &pname);
252-
if (ret != UMF_RESULT_SUCCESS) {
253-
LOG_ERR("Failed to get pool name");
254-
goto err_pool_init;
255-
}
256-
if (CTL_DEFAULT_ENTRIES[i][0] != '\0' && pname &&
257-
strstr(CTL_DEFAULT_ENTRIES[i], pname)) {
258-
259-
default_ctl_helper(ops, pool->pool_priv, CTL_DEFAULT_ENTRIES[i],
260-
CTL_DEFAULT_VALUES[i]);
291+
const char *pname = NULL;
292+
ret = ops->get_name(NULL, &pname);
293+
if (ret != UMF_RESULT_SUCCESS) {
294+
LOG_ERR("Failed to get pool name");
295+
goto err_pool_init;
296+
}
297+
assert(pname != NULL);
298+
299+
size_t pname_len = strlen(pname);
300+
ctl_default_entry_t *it = NULL;
301+
LL_FOREACH(ctl_default_list, it) {
302+
if (strlen(it->name) > pname_len + sizeof('.') &&
303+
strncmp(it->name, pname, pname_len) == 0 &&
304+
it->name[pname_len] == '.') {
305+
const char *ctl_name = it->name + pname_len + 1;
306+
default_ctl_helper(ops, pool->pool_priv, ctl_name, it->value,
307+
it->value_size);
261308
}
262309
}
263310

@@ -454,3 +501,23 @@ umf_result_t umfPoolGetTag(umf_memory_pool_handle_t hPool, void **tag) {
454501
utils_mutex_unlock(&hPool->lock);
455502
return UMF_RESULT_SUCCESS;
456503
}
504+
505+
void umfPoolCtlDefaultsDestroy(void) {
506+
utils_init_once(&mem_pool_ctl_initialized, ctl_init);
507+
508+
utils_mutex_lock(&ctl_mtx);
509+
510+
ctl_default_entry_t *entry = NULL, *tmp = NULL;
511+
LL_FOREACH_SAFE(ctl_default_list, entry, tmp) {
512+
LL_DELETE(ctl_default_list, entry);
513+
if (entry->name) {
514+
umf_ba_global_free(entry->name);
515+
}
516+
if (entry->value) {
517+
umf_ba_global_free(entry->value);
518+
}
519+
umf_ba_global_free(entry);
520+
}
521+
522+
utils_mutex_unlock(&ctl_mtx);
523+
}

src/memory_pool_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ typedef struct umf_memory_pool_t {
4747

4848
extern umf_ctl_node_t CTL_NODE(pool)[];
4949

50+
void umfPoolCtlDefaultsDestroy(void);
51+
5052
#ifdef __cplusplus
5153
}
5254
#endif

test/CMakeLists.txt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,48 @@ if(LINUX)
222222
LIBS ${UMF_UTILS_FOR_TEST})
223223
endif()
224224

225+
add_umf_executable(
226+
NAME ctl_env_app
227+
SRCS ctl/ctl_env_app.cpp
228+
LIBS ${UMF_UTILS_FOR_TEST} umf)
229+
230+
target_include_directories(
231+
ctl_env_app
232+
PRIVATE ${UMF_CMAKE_SOURCE_DIR}/include
233+
${UMF_CMAKE_SOURCE_DIR}/src
234+
${UMF_CMAKE_SOURCE_DIR}/src/base_alloc
235+
${UMF_CMAKE_SOURCE_DIR}/src/coarse
236+
${UMF_CMAKE_SOURCE_DIR}/src/utils
237+
${UMF_TEST_DIR}/common
238+
${UMF_TEST_DIR})
239+
240+
if(WINDOWS)
241+
# add PATH to DLL on Windows
242+
set(DLL_PATH_LIST
243+
"${DLL_PATH_LIST};PATH=path_list_append:${CMAKE_BINARY_DIR}/bin/;PATH=path_list_append:${CMAKE_BINARY_DIR}/bin/$<CONFIG>/"
244+
)
245+
246+
# append PATH to DLLs NOTE: this would work only for the CMake ver >= #
247+
# 3.22. For the older versions, the PATH variable should be set in the test
248+
# script)
249+
set_property(TEST ctl_env_app PROPERTY ENVIRONMENT_MODIFICATION
250+
"${DLL_PATH_LIST}")
251+
endif()
252+
253+
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ctl/ctl_env_config1.cfg
254+
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ctl)
255+
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ctl/ctl_env_config2.cfg
256+
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ctl)
257+
258+
add_umf_test(
259+
NAME ctl_env_driver
260+
SRCS ctl/ctl_env_driver.cpp
261+
LIBS ${UMF_UTILS_FOR_TEST})
262+
263+
target_compile_definitions(
264+
test_ctl_env_driver PRIVATE UMF_TEST_DIR="${UMF_TEST_DIR}"
265+
CTL_ENV_APP="$<TARGET_FILE:ctl_env_app>")
266+
225267
add_umf_test(
226268
NAME coarse_lib
227269
SRCS coarse_lib.cpp

0 commit comments

Comments
 (0)