From 6477cde367c4b281536ecc41cd195f1c067ef4b5 Mon Sep 17 00:00:00 2001 From: anth64 Date: Fri, 6 Mar 2026 07:52:34 +0100 Subject: [PATCH] feat(module.c, stk.c): implement pending queue and cascade dependency resolution --- src/module.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/stk.c | 94 ++++++++++++++++++++++++++++++------ 2 files changed, 211 insertions(+), 14 deletions(-) diff --git a/src/module.c b/src/module.c index 1c39fdb..3f547c6 100644 --- a/src/module.c +++ b/src/module.c @@ -47,6 +47,19 @@ static char stk_mod_deps_sym[STK_MOD_FUNC_NAME_BUFFER] = "stk_mod_deps"; 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) { stk_version_t v; @@ -448,6 +461,7 @@ void stk_module_free_memory(void) stk_modules = NULL; } module_count = 0; + stk_pending_free(); } unsigned char stk_module_init_memory(size_t capacity) @@ -506,6 +520,123 @@ void stk_module_unload_all(void) 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) { if (!name || (stk_flags & STK_FLAG_INITIALIZED)) diff --git a/src/stk.c b/src/stk.c index a0d4721..1ea9426 100644 --- a/src/stk.c +++ b/src/stk.c @@ -53,6 +53,9 @@ void stk_module_unload(size_t index); void stk_module_unload_all(void); unsigned char stk_validate_dependencies(size_t count); 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, const char *file) @@ -185,10 +188,21 @@ unsigned char stk_init(void) dep_result = stk_validate_dependencies(module_count); if (dep_result != STK_MOD_INIT_SUCCESS) { - stk_log(STK_LOG_ERROR, "Dependency validation failed: %s", - stk_error_string(dep_result)); - stk_module_unload_all(); - return dep_result; + size_t j; + char mod_tmp_path[STK_PATH_MAX_OS]; + stk_log(STK_LOG_WARN, + "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)); @@ -340,6 +354,7 @@ begin_operations: for (i = 0; i < unload_count; ++i) { stk_log(STK_LOG_INFO, "Unloaded module: %s", stk_modules[unloaded_mod_indices[i]].id); + stk_pending_remove(stk_modules[unloaded_mod_indices[i]].id); stk_module_unload(unloaded_mod_indices[i]); } @@ -366,8 +381,6 @@ begin_operations: stk_log(STK_LOG_ERROR, "Failed to reload module %s: %s", file_list[file_index], stk_error_string(load_result)); - else - stk_log_module(mod_index); } 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", file_list[file_index], stk_error_string(load_result)); - else - stk_log_module(target_index); } if (load_count > unload_count) @@ -427,7 +438,6 @@ append_modules: file_list[file_index], stk_error_string(load_result)); } else { - stk_log_module(module_count + successful_appends); successful_appends++; } } @@ -460,13 +470,64 @@ validate_deps: if (module_count == 0) goto free_poll; - dep_result = stk_validate_dependencies(module_count); - if (dep_result != STK_MOD_INIT_SUCCESS) { - stk_log(STK_LOG_ERROR, "Dependency validation failed: %s", - stk_error_string(dep_result)); - goto free_poll; + { + size_t cascade_indices[STK_PATH_MAX]; + size_t cascade_count; + char cascade_tmp_path[STK_PATH_MAX_OS]; + 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)); if (order) { dep_result = stk_topo_sort(module_count, order); @@ -476,6 +537,11 @@ validate_deps: free(order); } + stk_pending_retry(); + + if (module_count > 0) + stk_log_modules(); + free_poll: free(reloaded_mod_indices); free(reloaded_mod_file_indices);