From 40aad6a8202b0470c1b9781c1e64e0b1e7882b4e Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 14 Mar 2021 19:56:53 -0500 Subject: [PATCH] Progress: controller program. --- level_3/controller/c/controller.h | 8 +- level_3/controller/c/private-common.c | 61 +++--- level_3/controller/c/private-common.h | 69 ++++--- level_3/controller/c/private-controller.c | 329 ++++++++++++++++++++++-------- level_3/controller/c/private-controller.h | 26 +++ level_3/controller/c/private-entry.c | 96 ++++++--- level_3/controller/c/private-entry.h | 41 +++- level_3/controller/c/private-rule.c | 223 ++++++++++++++------ level_3/controller/c/private-rule.h | 12 +- level_3/controller/c/private-thread.c | 33 +-- 10 files changed, 643 insertions(+), 255 deletions(-) diff --git a/level_3/controller/c/controller.h b/level_3/controller/c/controller.h index 789070b..0cc1f62 100644 --- a/level_3/controller/c/controller.h +++ b/level_3/controller/c/controller.h @@ -11,11 +11,13 @@ * This program provides system service management, much like sysvcontroller and controllerng. * This program can be controlled from user-space via the "control" program. * - * @todo research containers and build in container support into this, providing "container" appropriate verbiage for individual rules. - * @todo research namespaces and user_namespaces, they may be important to support. - * * @todo Implement "exit" files that are the opposite of "entry" files whereas rules specified within are all called via the "stop" action type. * This would then allow for switching modes. + * + * @fixme the entire program needs to check the return status on all locks (mutex, r/w locks, etc..) and if there is a problem, print a message and wait (but ideally allow for signals, if enabled). + * + * @todo This currently only exits on memory error. + * For a production "init" program, this should continue to run...so it needs to sleep and wait for resources to become available. */ #ifndef _controller_h diff --git a/level_3/controller/c/private-common.c b/level_3/controller/c/private-common.c index bd3c4d6..3ed2c03 100644 --- a/level_3/controller/c/private-common.c +++ b/level_3/controller/c/private-common.c @@ -11,7 +11,6 @@ extern "C" { f_macro_array_lengths_t_delete_simple(asynchronous->stack) controller_cache_delete_simple(&asynchronous->cache); - controller_rule_delete_simple(&asynchronous->rule); } #endif // _di_controller_asynchronous_delete_simple_ @@ -135,24 +134,26 @@ extern "C" { } #endif // _di_controller_entry_items_delete_simple_ -#ifndef _di_controller_error_print_locked_ - void controller_error_print_locked(const fll_error_print_t error, const f_status_t status, const f_string_t function, const bool fallback, controller_thread_t *thread) { +#ifndef _di_controller_error_print_ + void controller_error_print(const fll_error_print_t print, const f_status_t status, const f_string_t function, const bool fallback, controller_thread_t *thread) { - if (error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread->mutex.print); + if (print.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread->lock.print); - fll_error_print(error, status, function, fallback); + fll_error_print(print, status, function, fallback); - f_thread_mutex_unlock(&thread->mutex.print); + f_thread_mutex_unlock(&thread->lock.print); } } -#endif // _di_controller_error_print_locked_ +#endif // _di_controller_error_print_ #ifndef _di_controller_process_delete_simple_ void controller_process_delete_simple(controller_process_t *process) { f_string_dynamic_resize(0, &process->id); - f_thread_mutex_delete(&process->lock); + + f_thread_lock_delete(&process->lock); + f_thread_lock_attribute_delete(&process->attribute); f_thread_condition_delete(&process->wait); } #endif // _di_controller_process_delete_simple_ @@ -232,24 +233,24 @@ extern "C" { #ifndef _di_controller_rule_delete_simple_ void controller_rule_delete_simple(controller_rule_t *rule) { - f_macro_thread_mutex_t_delete_simple(rule->lock) - f_macro_thread_condition_t_delete_simple(rule->wait) - f_macro_string_maps_t_delete_simple(rule->define) - f_macro_string_maps_t_delete_simple(rule->parameter) - f_macro_string_dynamics_t_delete_simple(rule->environment) - f_macro_string_dynamics_t_delete_simple(rule->need) - f_macro_string_dynamics_t_delete_simple(rule->want) - f_macro_string_dynamics_t_delete_simple(rule->wish) - f_macro_int32s_t_delete_simple(rule->affinity) - f_macro_control_group_t_delete_simple(rule->control_group) - f_macro_int32s_t_delete_simple(rule->groups) - f_macro_limit_sets_t_delete_simple(rule->limits) - f_string_dynamic_resize(0, &rule->id); f_string_dynamic_resize(0, &rule->name); f_string_dynamic_resize(0, &rule->path); f_string_dynamic_resize(0, &rule->script); + f_string_maps_resize(0, &rule->define); + f_string_maps_resize(0, &rule->parameter); + + f_string_dynamics_resize(0, &rule->environment); + f_string_dynamics_resize(0, &rule->need); + f_string_dynamics_resize(0, &rule->want); + f_string_dynamics_resize(0, &rule->wish); + + f_macro_int32s_t_delete_simple(rule->affinity) + f_macro_control_group_t_delete_simple(rule->control_group) + f_macro_int32s_t_delete_simple(rule->groups) + f_macro_limit_sets_t_delete_simple(rule->limits) + f_capability_delete(&rule->capability); controller_rule_items_delete_simple(&rule->items); @@ -259,7 +260,7 @@ extern "C" { #ifndef _di_controller_rule_item_delete_simple_ void controller_rule_item_delete_simple(controller_rule_item_t *item) { - f_string_dynamic_resize(0, item->actions); + controller_rule_actions_delete_simple(&item->actions); } #endif // _di_controller_rule_item_delete_simple_ @@ -343,10 +344,16 @@ extern "C" { #ifndef _di_controller_thread_delete_simple_ void controller_thread_delete_simple(controller_thread_t *thread) { - f_thread_mutex_unlock(&thread->mutex.asynchronous); - f_thread_mutex_unlock(&thread->mutex.print); - f_thread_mutex_unlock(&thread->mutex.process); - f_thread_mutex_unlock(&thread->mutex.rule); + f_thread_mutex_delete(&thread->lock.print); + + f_thread_lock_delete(&thread->lock.asynchronous); + f_thread_lock_attribute_delete(&thread->lock.asynchronous_attribute); + + f_thread_lock_delete(&thread->lock.process); + f_thread_lock_attribute_delete(&thread->lock.process_attribute); + + f_thread_lock_delete(&thread->lock.rule); + f_thread_lock_attribute_delete(&thread->lock.rule_attribute); controller_asynchronouss_resize(0, &thread->asynchronouss); } diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index c284b48..df59d78 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -324,19 +324,28 @@ extern "C" { * The process lock is intended to lock any activity on the processs structure. * The rule lock is intended to lock any activity on the rules structure. */ -#ifndef _di_controller_mutex_t_ +#ifndef _di_controller_lock_t_ typedef struct { - f_thread_mutex_t asynchronous; f_thread_mutex_t print; - f_thread_mutex_t process; - f_thread_mutex_t rule; - } controller_mutex_t; - #define controller_mutex_t_initialize { \ - f_thread_mutex_t_initialize, \ - f_thread_mutex_t_initialize, \ + f_thread_lock_t asynchronous; + f_thread_lock_attribute_t asynchronous_attribute; + + f_thread_lock_t process; + f_thread_lock_attribute_t process_attribute; + + f_thread_lock_t rule; + f_thread_lock_attribute_t rule_attribute; + } controller_lock_t; + + #define controller_lock_t_initialize { \ f_thread_mutex_t_initialize, \ - f_thread_mutex_t_initialize \ + f_thread_lock_t_initialize, \ + f_thread_lock_attribute_t_initialize, \ + f_thread_lock_t_initialize, \ + f_thread_lock_attribute_t_initialize, \ + f_thread_lock_t_initialize, \ + f_thread_lock_attribute_t_initialize \ } #endif // _di_controller_mutex_t_ @@ -613,17 +622,20 @@ extern "C" { */ #ifndef _di_controller_process_t_ typedef struct { - f_status_t status; f_string_dynamic_t id; - f_thread_mutex_t lock; + f_status_t status; + + f_thread_lock_t lock; + f_thread_lock_attribute_t attribute; f_thread_condition_t wait; } controller_process_t; #define controller_process_t_initialize { \ - F_known_not, \ f_string_dynamic_t_initialize \ - f_thread_mutex_t_initialize, \ + F_known_not, \ + f_thread_lock_t_initialize, \ + f_thread_lock_attribute_t_initialize, \ f_thread_condition_t_initialize, \ } @@ -941,9 +953,10 @@ extern "C" { typedef struct { f_thread_id_t id; - f_thread_mutex_t lock; - f_array_length_t index; + f_thread_lock_t lock; + f_thread_lock_attribute_t attribute; + f_array_length_t index; uint8_t state; uint8_t action; uint8_t options; @@ -951,22 +964,22 @@ extern "C" { f_array_lengths_t stack; controller_cache_t cache; - controller_rule_t rule; } controller_asynchronous_t; #define controller_asynchronous_t_initialize { \ f_thread_id_t_initialize, \ - f_thread_mutex_t_initialize, \ + f_thread_lock_t_initialize, \ + f_thread_lock_attribute_t_initialize, \ 0, \ 0, \ 0, \ 0, \ 0, \ f_array_lengths_t_initialize, \ - controller_cache_t_initialize, \ - controller_rule_t_initialize \ + controller_cache_t_initialize \ } + // @fixme remove the clear() macros..clear isn't safe when mixing in mutexes and whatnot that cannot be cleared. #define controller_macro_asynchronous_t_clear(asynchronous) \ f_macro_thread_id_t_clear(asynchronous.id) \ asynchronous.index = 0; \ @@ -975,8 +988,7 @@ extern "C" { asynchronous.options = 0; \ asynchronous.child = 0; \ f_macro_array_lengths_t_clear(asynchronous.stack) \ - controller_macro_cache_t_clear(asynchronous.cache) \ - controller_macro_rule_t_clear(asynchronous.rule) + controller_macro_cache_t_clear(asynchronous.cache) #endif // _di_controller_asynchronous_t_ #ifndef _di_controller_asynchronouss_t_ @@ -1008,7 +1020,7 @@ extern "C" { f_thread_id_t id_rule; f_thread_id_t id_signal; - controller_mutex_t mutex; + controller_lock_t lock; controller_asynchronouss_t asynchronouss; } controller_thread_t; @@ -1018,17 +1030,17 @@ extern "C" { f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ - controller_mutex_t_initialize, \ + controller_lock_t_initialize, \ controller_asynchronouss_t_initialize \ } - #define controller_macro_thread_t_initialize(mutex, asynchronouss) { \ + #define controller_macro_thread_t_initialize(lock, asynchronouss) { \ F_true, \ f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ f_thread_id_t_initialize. \ - mutex, \ + lock, \ asynchronouss \ } @@ -1038,7 +1050,6 @@ extern "C" { f_macro_thread_id_t_clear(thread.id_control); \ f_macro_thread_id_t_clear(thread.id_rule); \ f_macro_thread_id_t_clear(thread.id_signal); \ - controller_macro_mutex_t_clear(thread.mutex), \ controller_macro_asynchronouss_t_clear(thread.asynchronouss) #endif // _di_controller_data_common_t_ @@ -1234,9 +1245,9 @@ extern "C" { * * @see fll_error_print() */ -#ifndef _di_controller_error_print_locked_ - extern void controller_error_print_locked(const fll_error_print_t error, const f_status_t status, const f_string_t function, const bool fallback, controller_thread_t *thread) f_gcc_attribute_visibility_internal; -#endif // _di_controller_error_print_locked_ +#ifndef _di_controller_error_print_ + extern void controller_error_print(const fll_error_print_t print, const f_status_t status, const f_string_t function, const bool fallback, controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_error_print_ /** * Fully deallocate all memory for the given process without caring about return status. diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 3b096b4..2fe90a9 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -69,14 +69,28 @@ extern "C" { } if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + + fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } + return status; } status = f_string_dynamic_terminate_after(&cache->action.name_file); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + + fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } + return status; } @@ -95,13 +109,25 @@ extern "C" { status = f_file_stream_open(path, 0, &file); if (F_status_is_error(status)) { - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file); + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + + fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } } else { status = f_file_stream_read(file, 1, &cache->buffer_file); if (F_status_is_error(status)) { - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file); + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + + fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } } } @@ -113,7 +139,13 @@ extern "C" { status = f_file_stat(path, F_true, &stat_file); if (F_status_is_error(status)) { - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file); + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + + fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } } else { cache->timestamp.seconds = stat_file.st_ctim.tv_sec; @@ -219,6 +251,24 @@ extern "C" { } #endif // _di_controller_file_pid_delete_ +#ifndef _di_controller_find_process_ + f_status_t controller_find_process(const f_string_static_t id, const controller_processs_t processs, f_array_length_t *at) { + + if (!id.used) return F_none; + if (!processs.used) return F_false; + + for (f_array_length_t i = 0; i < processs.used; ++i) { + + if (fl_string_dynamic_compare(id, processs.array[i].id) == F_equal_to) { + *at = i; + return F_true; + } + } // for + + return F_false; + } +#endif // _di_controller_find_process_ + #ifndef _di_controller_get_id_user_ f_status_t controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) { f_number_unsigned_t number = 0; @@ -317,16 +367,28 @@ extern "C" { // always return immediately on memory errors. if (F_status_set_fine(status) == F_memory_not) { - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file); + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); - controller_entry_error_print(thread_data.data->error, cache->action); + fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file); + + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } return status; } - fll_error_file_print(thread_data.data->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file); + if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&thread_data.thread->lock.print); - controller_entry_error_print(thread_data.data->warning, cache->action); + fll_error_file_print(thread_data.data->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file); + + controller_entry_error_print_cache(thread_data.data->warning, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } status = F_none; } @@ -363,7 +425,7 @@ extern "C" { f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); return status; } @@ -378,8 +440,7 @@ extern "C" { status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[0].name, &cache->action.name_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status; } @@ -400,8 +461,7 @@ extern "C" { status2 = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->action.name_action); if (F_status_is_error(status2)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status2; } @@ -410,12 +470,16 @@ extern "C" { if (thread_data.setting->ready == controller_setting_ready_wait) { if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->warning.to.stream, "%s%sMultiple '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); fprintf(thread_data.data->warning.to.stream, "%s%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, controller_string_ready_s, thread_data.data->warning.notable.after->string); fprintf(thread_data.data->warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(thread_data.data->warning, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } @@ -439,13 +503,17 @@ extern "C" { if (cache->ats.array[j] == i) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe entry item named '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.setting->entry.items.array[i].name.string, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - } - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } if (F_status_is_error_not(status)) { status = F_status_set_error(F_recurse); @@ -461,8 +529,7 @@ extern "C" { f_macro_array_lengths_t_increase_by(status2, cache->ats, controller_default_allocation_step) if (F_status_is_error(status2)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); return status2; } @@ -487,8 +554,7 @@ extern "C" { status2 = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[i].name, &cache->action.name_item); if (F_status_is_error(status2)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status2; } @@ -500,13 +566,17 @@ extern "C" { if (error_has || i >= thread_data.setting->entry.items.used) { if (i >= thread_data.setting->entry.items.used) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe entry item named '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].parameters.array[0].string, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s' does not exist.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - } - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } if (F_status_is_error_not(status)) { status = F_status_set_error(F_valid_not); @@ -540,8 +610,7 @@ extern "C" { status2 = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); if (F_status_is_error(status2)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status2; } @@ -572,6 +641,8 @@ extern "C" { controller_entry_actions_t *actions = 0; + controller_process_t *process = 0; + const bool simulate = thread_data.data->parameters[controller_parameter_test].result == f_console_result_found; cache->ats.used = 0; @@ -590,8 +661,7 @@ extern "C" { f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); return status; } @@ -607,19 +677,24 @@ extern "C" { status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[0].name, &cache->action.name_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status; } if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Processing entry item rule '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_main_s, thread_data.data->context.set.title.after->string); fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } + // @todo this function should maintain a read lock on "thread_data.thread->lock.rule", but it must immediately release the read lock before it can do a write lock (which is unfortunate). + // I would much rather gain the write lock and then release the read lock, but that is likely not possible. for (;;) { actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions; @@ -637,8 +712,7 @@ extern "C" { status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->action.name_action); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status; } @@ -648,6 +722,8 @@ extern "C" { if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "The entry item action '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_action.string, thread_data.data->context.set.title.after->string); @@ -660,10 +736,14 @@ extern "C" { } fprintf(thread_data.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } else if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->action.name_action.string); @@ -678,13 +758,17 @@ extern "C" { fprintf(thread_data.data->error.to.stream, "%s and is in a ", thread_data.data->error.context.before->string); fprintf(thread_data.data->error.to.stream, "%s%sfailed%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s state, skipping execution.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - } - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } return F_status_is_error(F_require); } else if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->warning.to.stream, "%s%sThe entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); fprintf(thread_data.data->warning.to.stream, "%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, cache->action.name_action.string); @@ -700,11 +784,15 @@ extern "C" { fprintf(thread_data.data->warning.to.stream, "%s%sfailed%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string); fprintf(thread_data.data->warning.to.stream, "%s state, skipping execution.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(thread_data.data->warning, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } else { if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "The entry item action '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_action.string, thread_data.data->context.set.title.after->string); @@ -717,8 +805,12 @@ extern "C" { } fprintf(thread_data.data->output.stream, "' is in a %sfailed%s state, skipping.%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } else if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->warning.to.stream, "%s%sThe entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); fprintf(thread_data.data->warning.to.stream, "%s%s", thread_data.data->warning.notable.before->string, cache->action.name_action.string); @@ -732,7 +824,9 @@ extern "C" { fprintf(thread_data.data->warning.to.stream, "%s%sfailed%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string); fprintf(thread_data.data->warning.to.stream, "%s state, skipping.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(thread_data.data->warning, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } @@ -744,10 +838,14 @@ extern "C" { if (thread_data.setting->ready == controller_setting_ready_wait) { if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Processing entry item action '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_ready_s, thread_data.data->context.set.title.after->string); fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } else { controller_perform_ready(thread_data, cache); @@ -757,10 +855,14 @@ extern "C" { thread_data.setting->ready = controller_setting_ready_yes; } else if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Ignoring entry item action '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_ready_s, thread_data.data->context.set.title.after->string); fprintf(thread_data.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) { @@ -769,13 +871,17 @@ extern "C" { // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors. if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sInvalid entry item index ", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s detected.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - } - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } return F_status_is_error(F_critical); } @@ -783,8 +889,7 @@ extern "C" { f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); return status; } @@ -807,17 +912,20 @@ extern "C" { status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); return status; } if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Processing entry item '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_item.string, thread_data.data->context.set.title.after->string); fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } // exit inner loop to force restarting and start processing the requested item. @@ -828,8 +936,7 @@ extern "C" { status = controller_rules_increase(&thread_data.setting->rules); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_rules_increase", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, thread_data.thread); return status; } @@ -844,23 +951,27 @@ extern "C" { rule_id_name[actions->array[cache->ats.array[at_j]].parameters.array[0].used] = f_path_separator_s[0]; rule_id_name[rule_id_length] = 0; - f_thread_mutex_lock(&thread_data.thread->mutex.rule); + f_thread_lock_read(&thread_data.thread->lock.rule); at = controller_rule_find_loaded(rule_id, thread_data); - if (at < thread_data.setting->rules.used) { - f_thread_mutex_unlock(&thread_data.thread->mutex.rule); - } + const f_array_length_t used = thread_data.setting->rules.used; + + f_thread_unlock(&thread_data.thread->lock.rule); if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "%s entry item rule '", actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule ? "Processing" : "Considering"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, rule_id.string, thread_data.data->context.set.title.after->string); fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } // the rule is not yet loaded, ensure that it is loaded. - if (at == thread_data.setting->rules.used) { + if (at == used) { // rule execution will re-use the existing cache, so save the current cache. const f_array_length_t cache_line_action = cache->action.line_action; @@ -878,6 +989,8 @@ extern "C" { memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used); memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used); + f_thread_lock_write(&thread_data.thread->lock.rule); + status = controller_rule_read(rule_id, thread_data, cache, &thread_data.setting->rules.array[thread_data.setting->rules.used]); // restore cache. @@ -897,10 +1010,17 @@ extern "C" { cache->action.line_item = cache_line_item; if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action); + + if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } if (!simulate) { - f_thread_mutex_unlock(&thread_data.thread->mutex.rule); + f_thread_unlock(&thread_data.thread->lock.rule); break; } @@ -909,10 +1029,10 @@ extern "C" { thread_data.setting->rules.used++; } - f_thread_mutex_unlock(&thread_data.thread->mutex.rule); + f_thread_unlock(&thread_data.thread->lock.rule); } - if (F_status_is_error_not(status)) { + if (F_status_is_error_not(status) && actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { // rule execution will re-use the existing cache, so save the current cache. const f_array_length_t cache_line_action = cache->action.line_action; @@ -930,39 +1050,62 @@ extern "C" { memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used); memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used); - if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { - rule_options = 0; + rule_options = 0; - if (simulate) { - rule_options |= controller_rule_option_simulate; - } + if (simulate) { + rule_options |= controller_rule_option_simulate; + } - if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) { - rule_options |= controller_rule_option_require; - } + if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) { + rule_options |= controller_rule_option_require; + } - if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_wait) { - rule_options |= controller_rule_option_wait; - } + if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_wait) { + rule_options |= controller_rule_option_wait; + } - // @fixme this logic needs to change. - // determine how to pass rule ids. - // each thread has a main rule, but child threads need to be copied over and passed somehow. - f_thread_mutex_lock(&thread_data.setting->rules.array[at].lock); + if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_asynchronous) { + rule_options |= controller_rule_option_asynchronous; - if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_asynchronous) { - rule_options |= controller_rule_option_asynchronous; + // @todo this function will need to do the same process prep work as is done right before controller_rule_process(). + status = controller_rule_process_asynchronous(at, controller_rule_action_type_start, rule_options, thread_data, cache); + } + else { - status = controller_rule_process_asynchronous(at, controller_rule_action_type_start, rule_options, thread_data, cache); - } - else { - status = controller_rule_process(at, controller_rule_action_type_start, rule_options, thread_data, cache); + f_array_length_t at_process = 0; + + f_thread_lock_read(&thread_data.thread->lock.process); + + if (controller_find_process(rule_id, *thread_data.processs, &at_process) == F_false) { + f_thread_unlock(&thread_data.thread->lock.process); + f_thread_lock_write(&thread_data.thread->lock.process); + + status = controller_processs_increase(thread_data.processs); + + if (F_status_is_error(status)) { + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, thread_data.thread); + } + else { + at_process = thread_data.processs->used; + } } - if (status == F_child || status == F_signal) break; + f_thread_unlock(&thread_data.thread->lock.process); - f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); - f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); + if (F_status_is_error_not(status)) { + f_thread_lock_write(&thread_data.processs->array[at_process].lock); + + controller_rule_t rule = controller_rule_t_initialize; + + status = controller_rule_copy(thread_data.setting->rules.array[at], &rule); + + f_thread_condition_signal(&thread_data.processs->array[at_process].wait); + f_thread_unlock(&thread_data.processs->array[at_process].lock); + + status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, cache); + + controller_rule_delete_simple(&rule); + } } // restore cache. @@ -980,10 +1123,17 @@ extern "C" { cache->action.line_action = cache_line_action; cache->action.line_item = cache_line_item; + + if (status == F_child || status == F_signal) break; } + // @todo this may need to be relocated (currently it may result in multiple error messages due to other messages being printed above.) if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action); + f_thread_mutex_lock(&thread_data.thread->lock.print); + + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); if (!simulate || F_status_set_fine(status) == F_memory_not) { break; @@ -1005,6 +1155,8 @@ extern "C" { code = controller_string_stop_s; } + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Processing entry item action '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_timeout_s, thread_data.data->context.set.title.after->string); @@ -1013,6 +1165,8 @@ extern "C" { fprintf(thread_data.data->output.stream, "' to '"); fprintf(thread_data.data->output.stream, "%s%llu%s", thread_data.data->context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, thread_data.data->context.set.important.after->string); fprintf(thread_data.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) { @@ -1031,13 +1185,17 @@ extern "C" { // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors. if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sInvalid entry item index ", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s detected.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - } - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); + } return F_status_is_error(F_critical); } @@ -1046,12 +1204,16 @@ extern "C" { thread_data.setting->failsafe_rule_id = actions->array[cache->ats.array[at_j]].number; if (simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Processing entry item action '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_failsafe_s, thread_data.data->context.set.title.after->string); fprintf(thread_data.data->output.stream, "' setting value to '"); fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.important.before->string, thread_data.setting->entry.items.array[thread_data.setting->failsafe_rule_id].name.string, thread_data.data->context.set.important.after->string); fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } } @@ -1090,8 +1252,7 @@ extern "C" { status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); break; } @@ -1103,7 +1264,11 @@ extern "C" { } if (F_status_is_error_not(status) && simulate) { + f_thread_mutex_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); + + f_thread_mutex_unlock(&thread_data.thread->lock.print); } return status; @@ -1188,6 +1353,8 @@ extern "C" { } #endif // _di_controller_validate_has_graph_ +controller_processs_t + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index 38eb59a..f6f9a74 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -157,6 +157,30 @@ extern "C" { #endif // _di_controller_file_pid_delete_ /** + * Find an existing process. + * + * Do not confuse this with a process in the context of a PID. + * This is a stucture for the current processing of some rule. + * + * This does not do any locking or unlocking for the processs data, be sure to lock appropriately before and after calling this. + * + * @param id + * The (rule) id to find. + * @param processs + * The array of processes to. + * @param at + * The location within processs the id was found. + * + * @return + * F_none if not given a valid id to search. + * F_false if there is no process found. + * F_true if there is a process found (address is stored in "at"). + */ +#ifndef _di_controller_find_process_ + f_status_t controller_find_process(const f_string_static_t id, const controller_processs_t processs, f_array_length_t *at) f_gcc_attribute_visibility_internal; +#endif // _di_controller_find_process_ + +/** * Convert the string from a string representation of an ID or a user name into the numeric representation of that ID or user name. * * @param buffer @@ -215,6 +239,8 @@ extern "C" { * * This prints messages on errors. * + * This does not do any locking or unlocking for the setting data, be sure to lock appropriately before and after calling this. + * * @param thread_data * The thread data. * @param cache diff --git a/level_3/controller/c/private-entry.c b/level_3/controller/c/private-entry.c index 0834af0..77eb662 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -541,37 +541,49 @@ extern "C" { #endif // _di_controller_entry_actions_read_ #ifndef _di_controller_entry_error_print_ - void controller_entry_error_print(const fll_error_print_t output, const controller_cache_action_t cache) { - - if (output.verbosity != f_console_verbosity_quiet) { - fprintf(output.to.stream, "%c", f_string_eol_s[0]); - fprintf(output.to.stream, "%s%sWhile processing ", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s); - - if (cache.name_action.used) { - fprintf(output.to.stream, "action '"); - fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_action.string, output.notable.after->string); - fprintf(output.to.stream, "%s' on line ", output.context.before->string); - fprintf(output.to.stream, "%s%s%llu%s", output.context.after->string, output.notable.before->string, cache.line_action, output.notable.after->string); - fprintf(output.to.stream, "%s for ", output.context.before->string); - } + void controller_entry_error_print(const fll_error_print_t print, const controller_cache_action_t cache, const f_status_t status, const f_string_t function, const bool fallback, controller_thread_t *thread) { - if (cache.name_item.used) { - fprintf(output.to.stream, "entry item '"); - fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_item.string, output.notable.after->string); - fprintf(output.to.stream, "%s' on line ", output.context.before->string); - fprintf(output.to.stream, "%s%s%llu%s", output.context.after->string, output.notable.before->string, cache.line_item, output.notable.after->string); - fprintf(output.to.stream, "%s for ", output.context.before->string); - } + if (print.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread->lock.print); - if (cache.name_file.used) { - fprintf(output.to.stream, "file '"); - fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, cache.name_file.string, output.notable.after->string); - fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]); - } + fll_error_print(print, status, function, fallback); + controller_entry_error_print_cache(print, cache); + + f_thread_mutex_unlock(&thread->lock.print); } } #endif // _di_controller_entry_error_print_ +#ifndef _di_controller_entry_error_print_cache_ + void controller_entry_error_print_cache(const fll_error_print_t print, const controller_cache_action_t cache) { + + fprintf(print.to.stream, "%c", f_string_eol_s[0]); + fprintf(print.to.stream, "%s%sWhile processing ", print.context.before->string, print.prefix ? print.prefix : f_string_empty_s); + + if (cache.name_action.used) { + fprintf(print.to.stream, "action '"); + fprintf(print.to.stream, "%s%s%s%s", print.context.after->string, print.notable.before->string, cache.name_action.string, print.notable.after->string); + fprintf(print.to.stream, "%s' on line ", print.context.before->string); + fprintf(print.to.stream, "%s%s%llu%s", print.context.after->string, print.notable.before->string, cache.line_action, print.notable.after->string); + fprintf(print.to.stream, "%s for ", print.context.before->string); + } + + if (cache.name_item.used) { + fprintf(print.to.stream, "entry item '"); + fprintf(print.to.stream, "%s%s%s%s", print.context.after->string, print.notable.before->string, cache.name_item.string, print.notable.after->string); + fprintf(print.to.stream, "%s' on line ", print.context.before->string); + fprintf(print.to.stream, "%s%s%llu%s", print.context.after->string, print.notable.before->string, cache.line_item, print.notable.after->string); + fprintf(print.to.stream, "%s for ", print.context.before->string); + } + + if (cache.name_file.used) { + fprintf(print.to.stream, "file '"); + fprintf(print.to.stream, "%s%s%s%s", print.context.after->string, print.notable.before->string, cache.name_file.string, print.notable.after->string); + fprintf(print.to.stream, "%s'.%s%c", print.context.before->string, print.context.after->string, f_string_eol_s[0]); + } + } +#endif // _di_controller_entry_error_print_cache_ + #ifndef _di_controller_entry_items_increase_by_ f_status_t controller_entry_items_increase_by(const f_array_length_t amount, controller_entry_items_t *items) { @@ -647,20 +659,24 @@ extern "C" { status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true); + controller_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true, thread_data); } else { status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true); + controller_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, thread_data); } } } else { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe entry file is empty.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]); + + f_thread_unlock(&thread_data.thread->lock.print); } status = F_status_set_error(F_data_not); @@ -740,12 +756,16 @@ extern "C" { if (fl_string_dynamic_compare(thread_data.setting->entry.items.array[j].name, cache->action.name_item) == F_equal_to) { if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->warning.to.stream, "%s%sIgnoring duplicate entry item '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); fprintf(thread_data.data->warning.to.stream, "%s%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, cache->action.name_file.string, thread_data.data->warning.notable.after->string); fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(thread_data.data->warning, cache->action); + + f_thread_unlock(&thread_data.thread->lock.print); } code |= 0x2; @@ -783,14 +803,18 @@ extern "C" { status = controller_string_dynamic_append_terminated(cache->action.name_item, &thread_data.setting->entry.items.array[at].name); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); + controller_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data); break; } status = controller_entry_actions_read(*range, thread_data, cache, &thread_data.setting->entry.items.array[at].actions); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action); + f_thread_lock(&thread_data.thread->lock.print); + + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_unlock(&thread_data.thread->lock.print); if (F_status_set_fine(status) == F_memory_not) { break; @@ -804,10 +828,14 @@ extern "C" { if (!(code & 0x1)) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe required entry item '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_main_s, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s' was not found.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + + f_thread_unlock(&thread_data.thread->lock.print); } status = F_status_set_error(F_found_not); @@ -857,17 +885,21 @@ extern "C" { status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[i].name, &cache->action.name_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); + controller_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data); break; } if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_lock(&thread_data.thread->lock.print); + fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe required entry item '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[0].string, thread_data.data->error.notable.after->string); fprintf(thread_data.data->error.to.stream, "%s' does not exist.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(thread_data.data->error, cache->action); + controller_entry_error_print_cache(thread_data.data->error, cache->action); + + f_thread_unlock(&thread_data.thread->lock.print); } action->number = 0; diff --git a/level_3/controller/c/private-entry.h b/level_3/controller/c/private-entry.h index 349aa76..e4a8977 100644 --- a/level_3/controller/c/private-entry.h +++ b/level_3/controller/c/private-entry.h @@ -98,21 +98,48 @@ extern "C" { #endif // _di_controller_entry_actions_read_ /** - * Print additional error/warning information in addition to existing error. + * Print the entry related error, locking the print mutex during the print. + * + * @param print + * Designates how printing is to be performed. + * @param cache + * The action cache. + * @param status + * The status code to process. + * Make sure this has F_status_set_fine() called if the status code has any error or warning bits. + * @param function + * The name of the function where the error happened. + * Set to 0 to disable. + * @param fallback + * Set to F_true to print the fallback error message for unknown errors. + * @param thread + * The thread data. + * + * @see fll_error_print() + * @see controller_entry_error_print_cache() + */ +#ifndef _di_controller_entry_error_print_ + extern void controller_entry_error_print(const fll_error_print_t print, const controller_cache_action_t cache, const f_status_t status, const f_string_t function, const bool fallback, controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_entry_error_print_ + +/** + * Print additional error/warning information in addition to existing error that is found within the cache. * * This is explicitly intended to be used in addition to the error message. * - * @param output - * The error or warning output structure. + * This neither locks the thread nor does it check to see if output is enabled or disabled. + * + * @param print + * Designates how printing is to be performed. * @param cache - * A structure for containing and caching relevant data. + * The action cache. * * @see controller_entry_actions_read() * @see controller_entry_read() */ -#ifndef _di_controller_entry_error_print_ - extern void controller_entry_error_print(const fll_error_print_t output, const controller_cache_action_t cache) f_gcc_attribute_visibility_internal; -#endif // _di_controller_entry_error_print_ +#ifndef _di_controller_entry_error_print_cache_ + extern void controller_entry_error_print_cache(const fll_error_print_t print, const controller_cache_action_t cache) f_gcc_attribute_visibility_internal; +#endif // _di_controller_entry_error_print_cache_ /** * Increase the size of the entry items array by the specified amount, but only if necessary. diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index a351cab..8eb18eb 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -399,15 +399,118 @@ extern "C" { #endif // _di_controller_rule_action_read_ #ifndef _di_controller_rule_copy_ - f_status_t controller_rule_copy(controller_rule_t *source, controller_rule_t *destination) { + f_status_t controller_rule_copy(const controller_rule_t source, controller_rule_t *destination) { f_status_t status = F_none; - f_thread_condition_wait(&source->wait, &destination->lock); + destination->timeout_kill = source.timeout_kill; + destination->timeout_start = source.timeout_start; + destination->timeout_stop = source.timeout_stop; - // @todo + destination->has = source.has; + destination->nice = source.nice; + destination->user = source.user; + destination->group = source.group; - f_thread_condition_signal(&source->wait); - f_thread_mutex_unlock(&destination->lock); + destination->timestamp.seconds = source.seconds; + destination->timestamp.nanoseconds = source.nanoseconds; + + destination->path_control.used = 0; + destination->name.used = 0; + destination->path.used = 0; + destination->script.used = 0; + + destination->define.used = 0; + destination->parameter.used = 0; + + destination->environment.used = 0; + destination->need.used = 0; + destination->want.used = 0; + destination->wish.used = 0; + + destination->affinity.used = 0; + destination->capability.used = 0; + destination->control_group.used = 0; + destination->groups.used = 0; + destination->limits.used = 0; + destination->scheduler.used = 0; + + destination->items.used = 0; + + if (source.id.used) { + + status = f_string_dynamic_append(source.id, &dynamic->id); + if (F_status_is_error(status)) return status; + } + + if (source.name.used) { + + status = f_string_dynamic_append(source.name, &dynamic->name); + if (F_status_is_error(status)) return status; + } + + if (source.path.used) { + + status = f_string_dynamic_append(source.path, &dynamic->path); + if (F_status_is_error(status)) return status; + } + + if (source.script.used) { + + status = f_string_dynamic_append(source.script, &dynamic->script); + if (F_status_is_error(status)) return status; + } + + if (source.define.used) { + status = f_string_maps_append(source.define, &destination->define); + } + + if (source.parameter.used) { + status = f_string_maps_append(source.parameter, &destination->parameter); + } + + if (source.environment.used) { + status = f_string_dynamics_append(source.environment, &destination->environment); + } + + if (source.need.used) { + status = f_string_dynamics_append(source.need, &destination->need); + } + + if (source.want.used) { + status = f_string_dynamics_append(source.want, &destination->want); + } + + if (source.wish.used) { + status = f_string_dynamics_append(source.wish, &destination->wish); + } + + if (source.affinity.used) { + status = f_int32s_append(source.affinity, &destination->affinity); + } + + if (source.capability.used) { + // @todo copy capability + } + + if (source.control_group.used) { + // @todo copy control_group + } + + if (source.groups.used) { + status = f_int32s_append(source.groups, &destination->groups); + } + + if (source.limits.used) { + status = f_limit_sets_append(source.limits, &destination->limits); + } + + if (source.scheduler.used) { + // @todo copy scheduler + } + + if (source.items.used) { + // @todo copy items + } return status; } @@ -452,11 +555,11 @@ extern "C" { void controller_rule_error_print_locked(const fll_error_print_t output, const controller_cache_action_t cache, const bool item, controller_thread_t *thread) { if (output.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread->mutex.print); + f_thread_mutex_lock(&thread->lock.print); controller_rule_error_print(output, cache, item); - f_thread_mutex_unlock(&thread->mutex.print); + f_thread_mutex_unlock(&thread->lock.print); } } #endif // _di_controller_rule_error_print_ @@ -705,14 +808,14 @@ extern "C" { else { if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s, thread_data.data->warning.context.after->string, f_string_eol_s[0]); controller_rule_error_print(thread_data.data->warning, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } rule->items.array[i].actions.array[j].status = F_ignore; @@ -760,7 +863,7 @@ extern "C" { if (options & controller_rule_option_simulate) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Simulating execution of '"); @@ -775,7 +878,7 @@ extern "C" { fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->context.reset.string); fprintf(thread_data.data->output.stream, "%s'.%c", thread_data.data->context.reset.string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } // sleep for less than a second to better show simulation of synchronous vs asynchronous. @@ -831,7 +934,7 @@ extern "C" { if (F_status_is_error(status)) { status = F_status_set_fine(status); - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) { controller_rule_error_print_execute(thread_data.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); @@ -843,7 +946,7 @@ extern "C" { fll_error_print(thread_data.data->error, status, "fll_execute_program", F_true); } - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); status = F_status_set_error(status); } @@ -869,7 +972,7 @@ extern "C" { if (options & controller_rule_option_simulate) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->output.stream, "Simulating execution of '"); @@ -884,7 +987,7 @@ extern "C" { fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->context.reset.string); fprintf(thread_data.data->output.stream, "%s'.%c", thread_data.data->context.reset.string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } // sleep for less than a second to better show simulation of synchronous vs asynchronous. @@ -940,7 +1043,7 @@ extern "C" { if (F_status_is_error(status)) { status = F_status_set_fine(status); - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) { controller_rule_error_print_execute(thread_data.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); @@ -952,7 +1055,7 @@ extern "C" { fll_error_print(thread_data.data->error, status, "fll_execute_program", F_true); } - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return F_status_set_error(status); } @@ -1381,7 +1484,9 @@ extern "C" { #endif // _di_controller_rule_path_ #ifndef _di_controller_rule_process_ - f_status_t controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) { + f_status_t controller_rule_process(const controller_rule_t rule, const f_array_length_t at_process, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) { + + // @todo need to update accordingly with new parameters "rule" and "at_process". switch (action) { case controller_rule_action_type_freeze: @@ -1398,7 +1503,7 @@ extern "C" { default: if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sUnsupported action type '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); @@ -1407,19 +1512,19 @@ extern "C" { controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } return F_status_set_error(F_parameter); } if (index >= thread_data.setting->rules.used) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_parameter, "controller_rule_process", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return F_status_set_error(F_parameter); } @@ -1429,12 +1534,12 @@ extern "C" { f_macro_array_lengths_t_increase_by(status, thread_data.thread->asynchronouss.array[thread_data.id].stack, controller_default_allocation_step) if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return status; } @@ -1445,7 +1550,7 @@ extern "C" { if (thread_data.thread->asynchronouss.array[thread_data.id].stack.array[i] == index) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe rule '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); @@ -1454,7 +1559,7 @@ extern "C" { controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } // never continue on recursion errors even in simulate mode. @@ -1473,12 +1578,12 @@ extern "C" { } if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return status; } @@ -1486,12 +1591,12 @@ extern "C" { status = f_string_dynamic_append(thread_data.setting->rules.array[index].id, &cache->action.name_file); if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return status; } @@ -1503,12 +1608,12 @@ extern "C" { } if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return status; } @@ -1516,12 +1621,12 @@ extern "C" { status = f_string_dynamic_terminate_after(&cache->action.name_file); if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return status; } @@ -1571,25 +1676,25 @@ extern "C" { if (at == thread_data.setting->rules.used) { if (i == 0) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "was not found"); status = F_status_set_error(F_found_not); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); if (!(options & controller_rule_option_simulate)) break; } else { if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "was not found"); controller_rule_error_print(thread_data.data->warning, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } } @@ -1616,12 +1721,12 @@ extern "C" { f_macro_array_lengths_t_increase_by(status, thread_data.thread->asynchronouss.array[thread_data.id].stack, controller_default_allocation_step) if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); @@ -1676,12 +1781,12 @@ extern "C" { if (F_status_is_error(status)) { if (i == 0 || i == 1 || F_status_set_fine(status) == F_memory_not) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "failed during execution"); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) { f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); @@ -1692,12 +1797,12 @@ extern "C" { } else { if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution"); controller_rule_error_print(thread_data.data->warning, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } } @@ -1709,25 +1814,25 @@ extern "C" { if (F_status_is_error(thread_data.setting->rules.array[at].status)) { if (i == 0 || i == 1) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "is in a failed state"); status = F_status_set_error(F_found_not); controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); if (!(options & controller_rule_option_simulate)) break; } else { if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state"); controller_rule_error_print(thread_data.data->warning, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } } } @@ -1779,7 +1884,7 @@ extern "C" { if (missing) { if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(thread_data.data->error.to.stream, "%s%sThe rule '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); @@ -1790,7 +1895,7 @@ extern "C" { controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } status = F_status_set_error(F_parameter); @@ -1840,10 +1945,10 @@ extern "C" { #ifndef _di_controller_rule_process_asynchronous_ f_status_t controller_rule_process_asynchronous(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) { - f_thread_mutex_lock(&thread_data->mutex.asynchronous); + f_thread_mutex_lock(&thread_data->lock.asynchronous); if (!thread_data.thread->enabled) { - f_thread_mutex_unlock(&thread_data.thread->mutex.asynchronous); + f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous); return F_signal; } @@ -1851,7 +1956,7 @@ extern "C" { f_status_t status = controller_asynchronouss_increase(&thread_data.thread->asynchronouss); if (F_status_is_error(status)) { - f_thread_mutex_unlock(&thread_data.thread->mutex.asynchronous); + f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous); return status; } @@ -1888,7 +1993,7 @@ extern "C" { thread_data.thread->asynchronouss.used--; } - f_thread_mutex_unlock(&thread_data.thread->mutex.asynchronous); + f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous); if (F_status_is_error(status)) { return status; @@ -3800,7 +3905,7 @@ extern "C" { controller_data_t *data = thread_data.thread->data; controller_setting_t *setting = thread_data.thread->setting; - f_thread_mutex_lock(&thread_data.thread->mutex.print); + f_thread_mutex_lock(&thread_data.thread->lock.print); switch (action) { case controller_rule_action_type_kill: @@ -3821,7 +3926,7 @@ extern "C" { controller_rule_error_print(data->error, cache->action, F_true); } - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); return; } @@ -4097,7 +4202,7 @@ extern "C" { setting->rules.array[index].status = F_complete; - f_thread_mutex_unlock(&thread_data.thread->mutex.print); + f_thread_mutex_unlock(&thread_data.thread->lock.print); } #endif // _di_controller_rule_simulate_ @@ -4125,7 +4230,7 @@ extern "C" { if (!thread->enabled) break; - if (f_thread_mutex_lock_try(&thread->mutex.asynchronous) == F_none) { + if (f_thread_mutex_lock_try(&thread->lock.asynchronous) == F_none) { if (thread->asynchronouss.array[i].state != controller_asynchronous_state_joined) { f_thread_join(thread->asynchronouss.array[i].id, 0); @@ -4139,7 +4244,7 @@ extern "C" { controller_macro_cache_action_t_clear(thread->asynchronouss.array[i].cache); } - f_thread_mutex_unlock(&thread->mutex.asynchronous); + f_thread_mutex_unlock(&thread->lock.asynchronous); } } // for } diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index cb26b97..12852ee 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -132,6 +132,10 @@ extern "C" { /** * Copy a rule, allocating new space as necessary. * + * This does not do any locking or unlocking for the rule data, be sure to lock appropriately before and after calling this. + * + * @todo finish writing this. + * * @param source * The source rule to copy from. * @param destination @@ -370,6 +374,8 @@ extern "C" { * Looks up the rules starting from the end so that the latest loaded version of any given rule is found and used first. * The rule thread should be locked before calling this to ensure the rule is not loaded after this search. * + * This does not do any locking or unlocking, be sure to lock appropriately before and after calling this. + * * @param rule_id * The string identifying the rule. * This is constructed from the path parts to the file without the file extension and without the settings directory prefix. @@ -533,6 +539,10 @@ extern "C" { * * This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array. * + * @param rule + * The rule information at the time the rule process started. + * @param at_process + * The position within the processs array representing this rule process. * @param action * The action to perform based on the action type codes. * @@ -558,7 +568,7 @@ extern "C" { * F_signal on (exit) signal received. */ #ifndef _di_controller_rule_process_ - extern f_status_t controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_process(const controller_rule_t rule, const f_array_length_t at_process, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_process_ /** diff --git a/level_3/controller/c/private-thread.c b/level_3/controller/c/private-thread.c index 914f6b4..b6bb159 100644 --- a/level_3/controller/c/private-thread.c +++ b/level_3/controller/c/private-thread.c @@ -27,7 +27,7 @@ extern "C" { thread.cache_main = thread_main->cache_main; thread.cache_action = &asynchronous->cache; thread.data = thread_main->data; - thread.mutex = thread_main->mutex; + thread.lock = thread_main->lock; thread.setting = thread_main->setting; thread.stack = &asynchronous->stack; @@ -49,7 +49,7 @@ extern "C" { thread->enabled = F_false; - f_thread_mutex_lock(&thread->mutex.asynchronous); + f_thread_mutex_lock(&thread->lock.asynchronous); for (f_array_length_t i = 0; i < thread->asynchronouss.used; ++i) { @@ -75,7 +75,7 @@ extern "C" { thread->asynchronouss.used = 0; - f_thread_mutex_unlock(&thread->mutex.asynchronous); + f_thread_mutex_unlock(&thread->lock.asynchronous); } #endif // _di_controller_thread_asynchronous_cancel_ @@ -91,7 +91,7 @@ extern "C" { for (; thread_data->thread->enabled; ) { sleep(interval); - if (f_thread_mutex_lock_try(&thread_data->thread->mutex.asynchronous) == F_none) { + if (f_thread_mutex_lock_try(&thread_data->thread->lock.asynchronous) == F_none) { controller_thread_t *thread = &thread_data->thread; if (thread->asynchronouss.used) { @@ -146,7 +146,7 @@ extern "C" { controller_asynchronouss_resize(thread->asynchronouss.used, &thread->asynchronouss); } - f_thread_mutex_unlock(&thread->mutex.asynchronous); + f_thread_mutex_unlock(&thread->lock.asynchronous); } } // for @@ -180,29 +180,26 @@ extern "C" { status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &data_main); } - if (F_status_is_error_not(status)) { - status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &data_main); - } - if (F_status_is_error(status)) { if (data->error.verbosity != f_console_verbosity_quiet) { - controller_error_print_locked(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread); + controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread); } } else { if (data->parameters[controller_parameter_daemon].result == f_console_result_found) { + setting->ready = controller_setting_ready_done; if (f_file_exists(setting->path_pid.string) == F_true) { if (data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread.mutex.print); + f_thread_mutex_lock(&thread.lock.print); fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(data->error.to.stream, "%s%sThe pid file '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s); fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, setting->path_pid.string, data->error.notable.after->string); fprintf(data->error.to.stream, "%s' must not already exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread.mutex.print); + f_thread_mutex_unlock(&thread.lock.print); } setting->ready = controller_setting_ready_abort; @@ -225,14 +222,14 @@ extern "C" { if (f_file_exists(setting->path_pid.string) == F_true) { if (data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread.mutex.print); + f_thread_mutex_lock(&thread.lock.print); fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(data->error.to.stream, "%s%sThe pid file '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s); fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, setting->path_pid.string, data->error.notable.after->string); fprintf(data->error.to.stream, "%s' must not already exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread.mutex.print); + f_thread_mutex_unlock(&thread.lock.print); } setting->ready = controller_setting_ready_fail; @@ -278,6 +275,10 @@ extern "C" { status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &data_main); } + if (F_status_is_error_not(status)) { + status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &data_main); + } + if (F_status_is_error(status)) { if (data->error.verbosity != f_console_verbosity_quiet) { controller_error_print_locked(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread); @@ -337,8 +338,8 @@ extern "C" { controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments; // @todo - // f_thread_mutex_lock(&thread_data->mutex.rule); - // f_thread_mutex_unlock(&thread_data->mutex.rule); + // f_thread_mutex_lock(&thread_data->lock.rule); + // f_thread_mutex_unlock(&thread_data->lock.rule); return 0; } -- 1.8.3.1