feat(module.c, stk.c): implement pending queue and cascade dependency resolution

This commit is contained in:
2026-03-06 07:52:34 +01:00
parent 4f4ae80a14
commit 6477cde367
2 changed files with 211 additions and 14 deletions
+131
View File
@@ -47,6 +47,19 @@ static char stk_mod_deps_sym[STK_MOD_FUNC_NAME_BUFFER] = "stk_mod_deps";
size_t module_count = 0; size_t module_count = 0;
static char (*stk_pending)[STK_PATH_MAX_OS] = NULL;
static size_t stk_pending_count = 0;
void stk_pending_free(void)
{
if (stk_pending) {
free(stk_pending);
stk_pending = NULL;
}
stk_pending_count = 0;
}
static stk_version_t stk_parse_version(const char *str) static stk_version_t stk_parse_version(const char *str)
{ {
stk_version_t v; stk_version_t v;
@@ -448,6 +461,7 @@ void stk_module_free_memory(void)
stk_modules = NULL; stk_modules = NULL;
} }
module_count = 0; module_count = 0;
stk_pending_free();
} }
unsigned char stk_module_init_memory(size_t capacity) unsigned char stk_module_init_memory(size_t capacity)
@@ -506,6 +520,123 @@ void stk_module_unload_all(void)
stk_module_free_memory(); stk_module_free_memory();
} }
void stk_pending_add(const char *path)
{
char (*new_pending)[STK_PATH_MAX_OS];
size_t i;
new_pending = malloc((stk_pending_count + 1) * sizeof(*stk_pending));
if (!new_pending)
return;
for (i = 0; i < stk_pending_count; i++)
memcpy(new_pending[i], stk_pending[i], STK_PATH_MAX_OS);
free(stk_pending);
stk_pending = new_pending;
strncpy(stk_pending[stk_pending_count], path, STK_PATH_MAX_OS - 1);
stk_pending[stk_pending_count][STK_PATH_MAX_OS - 1] = '\0';
stk_pending_count++;
}
void stk_pending_remove(const char *id)
{
size_t i, write;
char pending_id[STK_MOD_ID_BUFFER];
if (!stk_pending_count)
return;
write = 0;
for (i = 0; i < stk_pending_count; i++) {
extract_module_id(stk_pending[i], pending_id);
if (strncmp(pending_id, id, STK_MOD_ID_BUFFER) == 0)
continue;
if (write != i)
memcpy(stk_pending[write], stk_pending[i],
STK_PATH_MAX_OS);
write++;
}
stk_pending_count = write;
}
size_t stk_pending_retry(void)
{
size_t i, d, loaded = 0;
unsigned char deps_satisfied;
unsigned char result;
void *handle;
union {
void *obj;
const char *(*meta_func)(void);
} u;
const stk_dep_t *deps;
size_t dep_count;
int found;
if (!stk_pending_count)
return 0;
for (i = 0; i < stk_pending_count; i++) {
handle = platform_load_library(stk_pending[i]);
if (!handle)
continue;
u.obj = platform_get_symbol(handle, stk_mod_deps_sym);
if (!u.obj) {
platform_unload_library(handle);
goto attempt_load;
}
deps = (const stk_dep_t *)u.obj;
dep_count = 0;
while (deps[dep_count].id[0] != '\0')
dep_count++;
deps_satisfied = 1;
for (d = 0; d < dep_count; d++) {
found = is_mod_loaded(deps[d].id);
if (found < 0) {
deps_satisfied = 0;
break;
}
if (deps[d].version[0] &&
!stk_validate_constraint(
deps[d].version, stk_modules[found].version)) {
deps_satisfied = 0;
break;
}
}
platform_unload_library(handle);
if (!deps_satisfied)
continue;
attempt_load:
if (stk_module_realloc_memory(module_count + 1) != 0)
continue;
result = stk_module_load(stk_pending[i], module_count);
if (result != STK_MOD_INIT_SUCCESS)
continue;
module_count++;
loaded++;
memcpy(stk_pending[i], stk_pending[stk_pending_count - 1],
STK_PATH_MAX_OS);
stk_pending_count--;
i--;
}
if (stk_pending_count == 0)
stk_pending_free();
return loaded;
}
static void stk_set_fn_name(char *dst, const char *name) static void stk_set_fn_name(char *dst, const char *name)
{ {
if (!name || (stk_flags & STK_FLAG_INITIALIZED)) if (!name || (stk_flags & STK_FLAG_INITIALIZED))
+80 -14
View File
@@ -53,6 +53,9 @@ void stk_module_unload(size_t index);
void stk_module_unload_all(void); void stk_module_unload_all(void);
unsigned char stk_validate_dependencies(size_t count); unsigned char stk_validate_dependencies(size_t count);
unsigned char stk_topo_sort(size_t count, size_t *order); unsigned char stk_topo_sort(size_t count, size_t *order);
void stk_pending_add(const char *path);
void stk_pending_remove(const char *id);
size_t stk_pending_retry(void);
static void build_path(char *dest, size_t dest_size, const char *dir, static void build_path(char *dest, size_t dest_size, const char *dir,
const char *file) const char *file)
@@ -185,10 +188,21 @@ unsigned char stk_init(void)
dep_result = stk_validate_dependencies(module_count); dep_result = stk_validate_dependencies(module_count);
if (dep_result != STK_MOD_INIT_SUCCESS) { if (dep_result != STK_MOD_INIT_SUCCESS) {
stk_log(STK_LOG_ERROR, "Dependency validation failed: %s", size_t j;
stk_error_string(dep_result)); char mod_tmp_path[STK_PATH_MAX_OS];
stk_module_unload_all(); stk_log(STK_LOG_WARN,
return dep_result; "Some modules have unmet dependencies, deferring");
for (j = 0; j < module_count; j++) {
if (stk_modules[j].dep_count > 0) {
build_path(mod_tmp_path, sizeof(mod_tmp_path),
stk_tmp_dir, stk_modules[j].id);
strncat(mod_tmp_path, STK_MODULE_EXT,
sizeof(mod_tmp_path) -
strlen(mod_tmp_path) - 1);
stk_pending_add(mod_tmp_path);
stk_module_unload(j);
}
}
} }
order = malloc(module_count * sizeof(size_t)); order = malloc(module_count * sizeof(size_t));
@@ -340,6 +354,7 @@ begin_operations:
for (i = 0; i < unload_count; ++i) { for (i = 0; i < unload_count; ++i) {
stk_log(STK_LOG_INFO, "Unloaded module: %s", stk_log(STK_LOG_INFO, "Unloaded module: %s",
stk_modules[unloaded_mod_indices[i]].id); stk_modules[unloaded_mod_indices[i]].id);
stk_pending_remove(stk_modules[unloaded_mod_indices[i]].id);
stk_module_unload(unloaded_mod_indices[i]); stk_module_unload(unloaded_mod_indices[i]);
} }
@@ -366,8 +381,6 @@ begin_operations:
stk_log(STK_LOG_ERROR, "Failed to reload module %s: %s", stk_log(STK_LOG_ERROR, "Failed to reload module %s: %s",
file_list[file_index], file_list[file_index],
stk_error_string(load_result)); stk_error_string(load_result));
else
stk_log_module(mod_index);
} }
holes_to_fill = (load_count < unload_count) ? load_count : unload_count; holes_to_fill = (load_count < unload_count) ? load_count : unload_count;
@@ -392,8 +405,6 @@ begin_operations:
stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", stk_log(STK_LOG_ERROR, "Failed to load module %s: %s",
file_list[file_index], file_list[file_index],
stk_error_string(load_result)); stk_error_string(load_result));
else
stk_log_module(target_index);
} }
if (load_count > unload_count) if (load_count > unload_count)
@@ -427,7 +438,6 @@ append_modules:
file_list[file_index], file_list[file_index],
stk_error_string(load_result)); stk_error_string(load_result));
} else { } else {
stk_log_module(module_count + successful_appends);
successful_appends++; successful_appends++;
} }
} }
@@ -460,13 +470,64 @@ validate_deps:
if (module_count == 0) if (module_count == 0)
goto free_poll; goto free_poll;
dep_result = stk_validate_dependencies(module_count); {
if (dep_result != STK_MOD_INIT_SUCCESS) { size_t cascade_indices[STK_PATH_MAX];
stk_log(STK_LOG_ERROR, "Dependency validation failed: %s", size_t cascade_count;
stk_error_string(dep_result)); char cascade_tmp_path[STK_PATH_MAX_OS];
goto free_poll; size_t j, k, cascade_write;
do {
cascade_count = 0;
for (j = 0; j < module_count; j++) {
if (stk_modules[j].dep_count == 0)
continue;
for (k = 0; k < stk_modules[j].dep_count; k++) {
if (is_mod_loaded(
stk_modules[j].deps[k].id) <
0) {
cascade_indices
[cascade_count++] = j;
break;
}
}
}
if (cascade_count == 0)
break;
for (j = 0; j < cascade_count; j++) {
size_t idx = cascade_indices[j];
stk_log(STK_LOG_WARN,
"Unloading '%s': unmet dependencies",
stk_modules[idx].id);
build_path(cascade_tmp_path,
sizeof(cascade_tmp_path),
stk_tmp_dir, stk_modules[idx].id);
strncat(cascade_tmp_path, STK_MODULE_EXT,
sizeof(cascade_tmp_path) -
strlen(cascade_tmp_path) - 1);
stk_pending_add(cascade_tmp_path);
stk_module_unload(idx);
}
cascade_write = 0;
for (j = 0; j < module_count; j++) {
if (stk_modules[j].handle != NULL) {
if (cascade_write != j)
stk_modules[cascade_write] =
stk_modules[j];
cascade_write++;
}
}
module_count = cascade_write;
} while (cascade_count > 0);
} }
if (module_count > 0)
stk_module_realloc_memory(module_count);
order = malloc(module_count * sizeof(size_t)); order = malloc(module_count * sizeof(size_t));
if (order) { if (order) {
dep_result = stk_topo_sort(module_count, order); dep_result = stk_topo_sort(module_count, order);
@@ -476,6 +537,11 @@ validate_deps:
free(order); free(order);
} }
stk_pending_retry();
if (module_count > 0)
stk_log_modules();
free_poll: free_poll:
free(reloaded_mod_indices); free(reloaded_mod_indices);
free(reloaded_mod_file_indices); free(reloaded_mod_file_indices);