diff --git a/src/module.c b/src/module.c index dfd6580..e473b7d 100644 --- a/src/module.c +++ b/src/module.c @@ -206,12 +206,15 @@ unsigned char stk_validate_dependencies(size_t count) return result; } -unsigned char stk_topo_sort(size_t count, size_t *order) +typedef int (*stk_dep_query_fn)(size_t i, size_t j, void *ctx); + +static unsigned char stk_kahn_sort(size_t count, size_t *order, + stk_dep_query_fn has_dep, void *ctx, + void (*on_cycle)(size_t i)) { size_t *in_degree = NULL; size_t *queue = NULL; - size_t head, tail, sorted, i, d; - int dep_index; + size_t head, tail, sorted, i, j; unsigned char result = STK_MOD_INIT_SUCCESS; if (count == 0) @@ -229,11 +232,9 @@ unsigned char stk_topo_sort(size_t count, size_t *order) in_degree[i] = 0; for (i = 0; i < count; i++) - for (d = 0; d < stk_modules[i].dep_count; d++) { - dep_index = is_mod_loaded(stk_modules[i].deps[d].id); - if (dep_index >= 0) + for (j = 0; j < count; j++) + if (i != j && has_dep(i, j, ctx)) in_degree[i]++; - } head = tail = sorted = 0; @@ -246,48 +247,59 @@ unsigned char stk_topo_sort(size_t count, size_t *order) order[sorted++] = mod; for (i = 0; i < count; i++) { - for (d = 0; d < stk_modules[i].dep_count; d++) { - dep_index = - is_mod_loaded(stk_modules[i].deps[d].id); - if (dep_index != (int)mod) - continue; - if (--in_degree[i] == 0) - queue[tail++] = i; - break; - } + if (i == mod || !has_dep(i, mod, ctx)) + continue; + if (--in_degree[i] == 0) + queue[tail++] = i; } } if (sorted != count) { - size_t j; + size_t k; int in_order; for (i = 0; i < count; i++) { in_order = 0; - for (j = 0; j < sorted; j++) { - if (order[j] == i) { + for (k = 0; k < sorted; k++) { + if (order[k] == i) { in_order = 1; break; } } - - if (!in_order) - stk_log(STK_LOG_ERROR, - "Circular dependency detected with %s", - stk_modules[i].id); + if (!in_order && on_cycle) + on_cycle(i); } - result = STK_MOD_DEP_CIRCULAR_ERROR; } -done: - if (in_degree) - free(in_degree); - if (queue) - free(queue); +done: + free(in_degree); + free(queue); return result; } -unsigned char stk_module_load(const char *path, int index) +static int stk_loaded_has_dep(size_t i, size_t j, void *ctx) +{ + size_t d; + (void)ctx; + for (d = 0; d < stk_modules[i].dep_count; d++) + if (is_mod_loaded(stk_modules[i].deps[d].id) == (int)j) + return 1; + return 0; +} + +static void stk_log_cycle(size_t i) +{ + stk_log(STK_LOG_ERROR, "Circular dependency detected with %s", + stk_modules[i].id); +} + +unsigned char stk_topo_sort(size_t count, size_t *order) +{ + return stk_kahn_sort(count, order, stk_loaded_has_dep, NULL, + stk_log_cycle); +} + +unsigned char stk_module_preload(const char *path, int index) { void *handle; char module_id[STK_MOD_ID_BUFFER]; @@ -323,37 +335,6 @@ unsigned char stk_module_load(const char *path, int index) extract_module_id(path, module_id); - u.obj = platform_get_symbol(handle, stk_mod_deps_sym); - if (u.obj) { - const stk_dep_t *early_deps = (const stk_dep_t *)u.obj; - size_t early_dep_count = 0; - size_t di; - int found; - - while (early_deps[early_dep_count].id[0] != '\0') - early_dep_count++; - - for (di = 0; di < early_dep_count; di++) { - found = is_mod_loaded(early_deps[di].id); - if (found < 0) { - platform_unload_library(handle); - return STK_MOD_DEP_NOT_FOUND_ERROR; - } - if (early_deps[di].version[0] && - !stk_validate_constraint( - early_deps[di].version, - stk_modules[found].version)) { - platform_unload_library(handle); - return STK_MOD_DEP_VERSION_MISMATCH_ERROR; - } - } - } - - if (stk_modules[index].init() != STK_MOD_INIT_SUCCESS) { - platform_unload_library(handle); - return STK_MOD_INIT_FAILURE; - } - stk_modules[index].handle = handle; len = strlen(module_id); @@ -444,6 +425,70 @@ skip_deps: return STK_MOD_INIT_SUCCESS; } +void stk_module_discard(size_t index) +{ + platform_unload_library(stk_modules[index].handle); + stk_modules[index].handle = NULL; + stk_modules[index].init = NULL; + stk_modules[index].shutdown = NULL; + stk_modules[index].id[0] = '\0'; + stk_modules[index].name[0] = '\0'; + stk_modules[index].version[0] = '\0'; + stk_modules[index].desc[0] = '\0'; + if (stk_modules[index].deps) { + free(stk_modules[index].deps); + stk_modules[index].deps = NULL; + } + stk_modules[index].dep_count = 0; +} + +unsigned char stk_module_activate(size_t index) +{ + if (stk_modules[index].init() != STK_MOD_INIT_SUCCESS) { + stk_module_discard(index); + return STK_MOD_INIT_FAILURE; + } + return STK_MOD_INIT_SUCCESS; +} + +unsigned char stk_validate_dependencies_single(size_t index) +{ + size_t d; + int found; + + if (stk_modules[index].dep_count == 0) + return STK_MOD_INIT_SUCCESS; + + for (d = 0; d < stk_modules[index].dep_count; d++) { + found = is_mod_loaded(stk_modules[index].deps[d].id); + if (found < 0) + return STK_MOD_DEP_NOT_FOUND_ERROR; + if (stk_modules[index].deps[d].version[0] && + !stk_validate_constraint(stk_modules[index].deps[d].version, + stk_modules[found].version)) + return STK_MOD_DEP_VERSION_MISMATCH_ERROR; + } + + return STK_MOD_INIT_SUCCESS; +} + +unsigned char stk_module_load(const char *path, int index) +{ + unsigned char result; + + result = stk_module_preload(path, index); + if (result != STK_MOD_INIT_SUCCESS) + return result; + + result = stk_validate_dependencies_single(index); + if (result != STK_MOD_INIT_SUCCESS) { + stk_module_discard(index); + return result; + } + + return stk_module_activate(index); +} + unsigned char stk_module_load_init(const char *path, int index) { int result; @@ -537,20 +582,227 @@ unsigned char stk_module_realloc_memory(size_t new_capacity) return 0; } +typedef struct { + int *file_indices; + char (*file_names)[STK_PATH_MAX]; + const char *tmp_dir; +} stk_batch_dep_ctx_t; + +static int stk_batch_has_dep(size_t i, size_t j, void *ctx) +{ + stk_batch_dep_ctx_t *c = (stk_batch_dep_ctx_t *)ctx; + char id_j[STK_MOD_ID_BUFFER]; + char tmp_i[STK_PATH_MAX_OS]; + void *h; + const stk_dep_t *deps; + size_t d, dep_count; + union { + void *obj; + } u; + int result = 0; + + extract_module_id(c->file_names[c->file_indices[j]], id_j); + + tmp_i[0] = '\0'; + strncat(tmp_i, c->tmp_dir, STK_PATH_MAX_OS - 1); + strncat(tmp_i, STK_PATH_SEP_STR, STK_PATH_MAX_OS - strlen(tmp_i) - 1); + strncat(tmp_i, c->file_names[c->file_indices[i]], + STK_PATH_MAX_OS - strlen(tmp_i) - 1); + + h = platform_load_library(tmp_i); + if (!h) + return 0; + + u.obj = platform_get_symbol(h, stk_mod_deps_sym); + if (u.obj) { + deps = (const stk_dep_t *)u.obj; + dep_count = 0; + while (deps[dep_count].id[0] != '\0') + dep_count++; + for (d = 0; d < dep_count; d++) { + if (strncmp(deps[d].id, id_j, STK_MOD_ID_BUFFER) == 0) { + result = 1; + break; + } + } + } + + platform_unload_library(h); + return result; +} + +void stk_sort_load_order(int *file_indices, size_t n, + char (*file_names)[STK_PATH_MAX], const char *tmp_dir) +{ + size_t *order = NULL; + int *result = NULL; + stk_batch_dep_ctx_t ctx; + size_t i; + + if (n <= 1) + return; + + order = malloc(n * sizeof(size_t)); + result = malloc(n * sizeof(int)); + if (!order || !result) + goto cleanup; + + ctx.file_indices = file_indices; + ctx.file_names = file_names; + ctx.tmp_dir = tmp_dir; + + if (stk_kahn_sort(n, order, stk_batch_has_dep, &ctx, NULL) != + STK_MOD_INIT_SUCCESS) + goto cleanup; + + for (i = 0; i < n; i++) + result[i] = file_indices[order[i]]; + for (i = 0; i < n; i++) + file_indices[i] = result[i]; + +cleanup: + free(order); + free(result); +} + +void stk_collect_dependents(size_t *indices, size_t *count) +{ + size_t i, d; + int in_set, changed; + + do { + changed = 0; + for (i = 0; i < module_count; i++) { + in_set = 0; + { + size_t k; + for (k = 0; k < *count; k++) { + if (indices[k] == i) { + in_set = 1; + break; + } + } + } + if (in_set) + continue; + + for (d = 0; d < stk_modules[i].dep_count; d++) { + int dep_idx = + is_mod_loaded(stk_modules[i].deps[d].id); + if (dep_idx < 0) + continue; + { + size_t k; + for (k = 0; k < *count; k++) { + if (indices[k] == + (size_t)dep_idx) { + indices[(*count)++] = i; + changed = 1; + goto next_module; + } + } + } + } + next_module:; + } + } while (changed); +} + +void stk_sort_unload_order(size_t *indices, size_t n) +{ + size_t *topo = NULL; + size_t *result = NULL; + size_t i, j, k; + int in_set; + + if (n <= 1) + return; + + topo = malloc(module_count * sizeof(size_t)); + result = malloc(n * sizeof(size_t)); + + if (!topo || !result) + goto fallback; + + if (stk_topo_sort(module_count, topo) != STK_MOD_INIT_SUCCESS) + goto fallback; + + k = 0; + for (i = module_count; i > 0; --i) { + size_t mod = topo[i - 1]; + in_set = 0; + for (j = 0; j < n; j++) { + if (indices[j] == mod) { + in_set = 1; + break; + } + } + if (in_set) + result[k++] = mod; + } + + if (k == n) { + for (i = 0; i < n; i++) + indices[i] = result[i]; + } + + free(topo); + free(result); + return; + +fallback: + free(topo); + free(result); + for (i = 0; i < n / 2; i++) { + size_t tmp = indices[i]; + indices[i] = indices[n - 1 - i]; + indices[n - 1 - i] = tmp; + } +} + void stk_module_unload_all(void) { size_t i; - for (i = module_count; i > 0; --i) - stk_module_unload(i - 1); + size_t *order = NULL; + if (module_count == 0) + goto free_mem; + + order = malloc(module_count * sizeof(size_t)); + if (order) { + for (i = 0; i < module_count; i++) + order[i] = i; + stk_sort_unload_order(order, module_count); + for (i = 0; i < module_count; i++) + stk_module_unload(order[i]); + free(order); + } else { + for (i = module_count; i > 0; --i) + stk_module_unload(i - 1); + } + +free_mem: stk_module_free_memory(); } void stk_pending_add(const char *path) { char (*new_pending)[STK_PATH_MAX_OS]; + char incoming_id[STK_MOD_ID_BUFFER]; + char existing_id[STK_MOD_ID_BUFFER]; size_t i; + extract_module_id(path, incoming_id); + + for (i = 0; i < stk_pending_count; i++) { + extract_module_id(stk_pending[i], existing_id); + if (strncmp(existing_id, incoming_id, STK_MOD_ID_BUFFER) == 0) { + strncpy(stk_pending[i], path, STK_PATH_MAX_OS - 1); + stk_pending[i][STK_PATH_MAX_OS - 1] = '\0'; + return; + } + } + new_pending = malloc((stk_pending_count + 1) * sizeof(*stk_pending)); if (!new_pending) return; @@ -566,6 +818,74 @@ void stk_pending_add(const char *path) stk_pending_count++; } +void stk_pending_add_batch(const char (*paths)[STK_PATH_MAX_OS], size_t count) +{ + char (*new_pending)[STK_PATH_MAX_OS]; + char incoming_id[STK_MOD_ID_BUFFER]; + char existing_id[STK_MOD_ID_BUFFER]; + size_t i, j, new_count; + + if (!paths || count == 0) + return; + + new_count = 0; + for (i = 0; i < count; i++) { + int found = 0; + extract_module_id(paths[i], incoming_id); + + for (j = 0; j < stk_pending_count; j++) { + extract_module_id(stk_pending[j], existing_id); + if (strncmp(existing_id, incoming_id, + STK_MOD_ID_BUFFER) == 0) { + strncpy(stk_pending[j], paths[i], + STK_PATH_MAX_OS - 1); + stk_pending[j][STK_PATH_MAX_OS - 1] = '\0'; + found = 1; + break; + } + } + + if (!found) + new_count++; + } + + if (new_count == 0) + return; + + new_pending = + malloc((stk_pending_count + new_count) * 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; + + for (i = 0; i < count; i++) { + int found = 0; + extract_module_id(paths[i], incoming_id); + + for (j = 0; j < stk_pending_count; j++) { + extract_module_id(stk_pending[j], existing_id); + if (strncmp(existing_id, incoming_id, + STK_MOD_ID_BUFFER) == 0) { + found = 1; + break; + } + } + + if (!found) { + strncpy(stk_pending[stk_pending_count], paths[i], + 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; @@ -593,6 +913,7 @@ size_t stk_pending_retry(void) unsigned char deps_satisfied; unsigned char result; void *handle; + void *test; union { void *obj; const char *(*meta_func)(void); @@ -600,11 +921,41 @@ size_t stk_pending_retry(void) const stk_dep_t *deps; size_t dep_count; int found; + size_t write; + char pending_id[STK_MOD_ID_BUFFER]; if (!stk_pending_count) return 0; + write = 0; for (i = 0; i < stk_pending_count; i++) { + test = platform_load_library(stk_pending[i]); + if (test) { + platform_unload_library(test); + if (write != i) + memcpy(stk_pending[write], stk_pending[i], + STK_PATH_MAX_OS); + write++; + } + } + stk_pending_count = write; + + if (!stk_pending_count) { + stk_pending_free(); + return 0; + } + + for (i = 0; i < stk_pending_count; i++) { + extract_module_id(stk_pending[i], pending_id); + if (is_mod_loaded(pending_id) >= 0) { + memcpy(stk_pending[i], + stk_pending[stk_pending_count - 1], + STK_PATH_MAX_OS); + stk_pending_count--; + i--; + continue; + } + handle = platform_load_library(stk_pending[i]); if (!handle) continue; diff --git a/src/stk.c b/src/stk.c index f3865ef..58e5529 100644 --- a/src/stk.c +++ b/src/stk.c @@ -45,6 +45,10 @@ void extract_module_id(const char *path, char *out_id); int is_mod_loaded(const char *module_id); size_t stk_module_count(void); +unsigned char stk_module_preload(const char *path, int index); +unsigned char stk_module_activate(size_t index); +unsigned char stk_validate_dependencies_single(size_t index); +void stk_module_discard(size_t index); unsigned char stk_module_load(const char *path, int index); unsigned char stk_module_load_init(const char *path, int index); unsigned char stk_module_init_memory(size_t capacity); @@ -54,8 +58,13 @@ 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_add_batch(const char (*paths)[STK_PATH_MAX_OS], size_t count); void stk_pending_remove(const char *id); size_t stk_pending_retry(void); +void stk_sort_unload_order(size_t *indices, size_t n); +void stk_collect_dependents(size_t *indices, size_t *count); +void stk_sort_load_order(int *file_indices, size_t n, + char (*file_names)[STK_PATH_MAX], const char *tmp_dir); static void build_path(char *dest, size_t dest_size, const char *dir, const char *file) @@ -168,13 +177,15 @@ unsigned char stk_init(void) continue; } - load_result = stk_module_load_init(tmp_path, successful_loads); + load_result = stk_module_preload(tmp_path, successful_loads); if (load_result != STK_MOD_INIT_SUCCESS) { - stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", - files[i], stk_error_string(load_result)); + stk_log(STK_LOG_ERROR, + "Failed to preload module %s: %s", files[i], + stk_error_string(load_result)); } else { successful_loads++; + module_count++; } } @@ -186,32 +197,59 @@ unsigned char stk_init(void) if (module_count == 0) goto scanned; - dep_result = stk_validate_dependencies(module_count); - if (dep_result != STK_MOD_INIT_SUCCESS) { - size_t j; + { + size_t j, write; char mod_tmp_path[STK_PATH_MAX_OS]; - stk_log(STK_LOG_WARN, - "Some modules have unmet dependencies, deferring"); + + order = malloc(module_count * sizeof(size_t)); + if (order) { + dep_result = stk_topo_sort(module_count, order); + if (dep_result != STK_MOD_INIT_SUCCESS) + stk_log(STK_LOG_ERROR, + "Dependency sort failed: %s", + stk_error_string(dep_result)); + } else { + order = malloc(module_count * sizeof(size_t)); + if (order) + for (j = 0; j < module_count; j++) + order[j] = j; + } + for (j = 0; j < module_count; j++) { - if (stk_modules[j].dep_count > 0) { + size_t idx = order ? order[j] : j; + dep_result = stk_validate_dependencies_single(idx); + if (dep_result != STK_MOD_INIT_SUCCESS) { build_path(mod_tmp_path, sizeof(mod_tmp_path), - stk_tmp_dir, stk_modules[j].id); + stk_tmp_dir, stk_modules[idx].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); + stk_module_discard(idx); + continue; + } + if (stk_module_activate(idx) != STK_MOD_INIT_SUCCESS) { + stk_log(STK_LOG_ERROR, + "Failed to init module %s", + stk_modules[idx].id); + stk_module_discard(idx); } } - } - order = malloc(module_count * sizeof(size_t)); - if (order) { - dep_result = stk_topo_sort(module_count, order); - if (dep_result != STK_MOD_INIT_SUCCESS) - stk_log(STK_LOG_ERROR, "Dependency sort failed: %s", - stk_error_string(dep_result)); - free(order); + if (order) { + free(order); + order = NULL; + } + + write = 0; + for (j = 0; j < module_count; j++) { + if (stk_modules[j].handle != NULL) { + if (write != j) + stk_modules[write] = stk_modules[j]; + write++; + } + } + module_count = write; } scanned: @@ -224,6 +262,8 @@ scanned: return STK_INIT_WATCH_ERROR; } + stk_pending_retry(); + stk_log(STK_LOG_INFO, "stk v%s initialized, watching %s/", STK_VERSION_STRING, stk_mod_dir); if (module_count > 0) @@ -262,7 +302,6 @@ size_t stk_poll(void) int *reloaded_mod_indices = NULL, *reloaded_mod_file_indices = NULL, *unloaded_mod_indices = NULL, *loaded_mod_indices = NULL; size_t remaining_loads, new_capacity, holes_to_fill; - size_t write_pos, read_pos; char full_path[STK_PATH_MAX_OS], tmp_path[STK_PATH_MAX_OS]; char mod_id[STK_MOD_ID_BUFFER]; int load_result; @@ -270,6 +309,19 @@ size_t stk_poll(void) char (*module_ids)[STK_MOD_ID_BUFFER] = NULL; unsigned char dep_result; size_t *order = NULL; + size_t *unload_order = NULL; + size_t expanded_count; + size_t index, oi; + int is_orig; + char dep_tmp_path[STK_PATH_MAX_OS]; + size_t write; + size_t li; + int fi; + int file_index, mod_index, target_index; + 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; if (module_count > 0) { module_ids = malloc(module_count * sizeof(*module_ids)); @@ -351,16 +403,70 @@ handle_grow: goto free_poll; 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]); + unload_order = malloc(module_count * sizeof(size_t)); + if (unload_order) { + expanded_count = unload_count; + + for (i = 0; i < unload_count; i++) + unload_order[i] = (size_t)unloaded_mod_indices[i]; + + stk_collect_dependents(unload_order, &expanded_count); + stk_sort_unload_order(unload_order, expanded_count); + + for (i = 0; i < expanded_count; i++) { + index = unload_order[i]; + + stk_log(STK_LOG_INFO, "Unloaded module: %s", + stk_modules[index].id); + stk_pending_remove(stk_modules[index].id); + + is_orig = 0; + for (oi = 0; oi < unload_count; oi++) { + if ((size_t)unloaded_mod_indices[oi] == index) { + is_orig = 1; + break; + } + } + if (!is_orig) { + build_path(dep_tmp_path, sizeof(dep_tmp_path), + stk_tmp_dir, stk_modules[index].id); + strncat(dep_tmp_path, STK_MODULE_EXT, + sizeof(dep_tmp_path) - + strlen(dep_tmp_path) - 1); + stk_pending_add(dep_tmp_path); + } + + stk_module_unload(index); + } + free(unload_order); + unload_order = NULL; + } else { + 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]); + } + } + + if (unload_count > 0) { + write = 0; + for (i = 0; i < module_count; i++) { + if (stk_modules[i].handle != NULL) { + if (write != i) + stk_modules[write] = stk_modules[i]; + write++; + } + } + module_count = write; + if (module_count > 0) + stk_module_realloc_memory(module_count); } for (i = 0; i < reload_count; ++i) { - int file_index = reloaded_mod_file_indices[i]; - int mod_index = reloaded_mod_indices[i]; + file_index = reloaded_mod_file_indices[i]; + mod_index = reloaded_mod_indices[i]; build_path(full_path, sizeof(full_path), stk_mod_dir, file_list[file_index]); @@ -384,56 +490,58 @@ begin_operations: } holes_to_fill = (load_count < unload_count) ? load_count : unload_count; - for (i = 0; i < holes_to_fill; ++i) { - int target_index = unloaded_mod_indices[i]; - int file_index = loaded_mod_indices[i]; + for (li = 0; li < load_count; li++) { + fi = loaded_mod_indices[li]; build_path(full_path, sizeof(full_path), stk_mod_dir, - file_list[file_index]); + file_list[fi]); + build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir, + file_list[fi]); + platform_copy_file(full_path, tmp_path); + } + + if (load_count > 1) + stk_sort_load_order(loaded_mod_indices, load_count, file_list, + stk_tmp_dir); + + for (i = 0; i < holes_to_fill; ++i) { + target_index = unloaded_mod_indices[i]; + file_index = loaded_mod_indices[i]; + build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir, file_list[file_index]); - if (platform_copy_file(full_path, tmp_path) != - STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(STK_LOG_ERROR, "Failed to copy %s for loading", - file_list[file_index]); - continue; - } - load_result = stk_module_load(tmp_path, target_index); - if (load_result != STK_MOD_INIT_SUCCESS) + if (load_result == STK_MOD_DEP_NOT_FOUND_ERROR || + load_result == STK_MOD_DEP_VERSION_MISMATCH_ERROR) { + stk_pending_add(tmp_path); + } else if (load_result != STK_MOD_INIT_SUCCESS) { stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", file_list[file_index], stk_error_string(load_result)); + } else { + module_count++; + } } if (load_count > unload_count) goto append_modules; - if (unload_count > load_count) - goto trim_arrays; - goto validate_deps; append_modules: for (; i < load_count; ++i) { - int file_index = loaded_mod_indices[i]; + file_index = loaded_mod_indices[i]; - build_path(full_path, sizeof(full_path), stk_mod_dir, - file_list[file_index]); build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir, file_list[file_index]); - if (platform_copy_file(full_path, tmp_path) != - STK_PLATFORM_OPERATION_SUCCESS) { - stk_log(STK_LOG_ERROR, "Failed to copy %s for loading", - file_list[file_index]); - continue; - } - load_result = stk_module_load(tmp_path, module_count + successful_appends); - if (load_result != STK_MOD_INIT_SUCCESS) { + if (load_result == STK_MOD_DEP_NOT_FOUND_ERROR || + load_result == STK_MOD_DEP_VERSION_MISMATCH_ERROR) { + stk_pending_add(tmp_path); + } else if (load_result != STK_MOD_INIT_SUCCESS) { stk_log(STK_LOG_ERROR, "Failed to load module %s: %s", file_list[file_index], stk_error_string(load_result)); @@ -449,81 +557,54 @@ append_modules: goto validate_deps; -trim_arrays: - write_pos = unloaded_mod_indices[holes_to_fill]; - for (i = holes_to_fill + 1; i < unload_count; ++i) { - if (unloaded_mod_indices[i] < write_pos) - write_pos = unloaded_mod_indices[i]; - } - - for (read_pos = write_pos + 1; read_pos < module_count; ++read_pos) { - if (stk_modules[read_pos].handle != NULL) { - stk_modules[write_pos] = stk_modules[read_pos]; - ++write_pos; - } - } - - module_count = write_pos; - stk_module_realloc_memory(module_count); - validate_deps: if (module_count == 0) 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; - 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; - } + 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; + if (cascade_count == 0) + break; - for (j = 0; j < cascade_count; j++) { - size_t index = cascade_indices[j]; - stk_log(STK_LOG_WARN, - "Unloading '%s': unmet dependencies", - stk_modules[index].id); - build_path(cascade_tmp_path, - sizeof(cascade_tmp_path), - stk_tmp_dir, stk_modules[index].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(index); + for (j = 0; j < cascade_count; j++) { + index = cascade_indices[j]; + stk_log(STK_LOG_WARN, + "Unloading '%s': unmet dependencies", + stk_modules[index].id); + build_path(cascade_tmp_path, sizeof(cascade_tmp_path), + stk_tmp_dir, stk_modules[index].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(index); + } + + 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; - 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); - } + } while (cascade_count > 0); if (module_count > 0) stk_module_realloc_memory(module_count); @@ -537,12 +618,12 @@ validate_deps: free(order); } +free_poll: stk_pending_retry(); if (module_count > 0) stk_log_modules(); -free_poll: free(reloaded_mod_indices); free(reloaded_mod_file_indices); free(unloaded_mod_indices);