From 156954deceea1ad77237426deae4ebab7a110ae4 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 20 Jan 2021 22:43:49 -0600 Subject: [PATCH] Progress: controller program thread support. This is the initial pass at getting the thread support implemented. There were several necessary changes in how the cache is defined and used. This is very much incomplete. All of the printf functions after a certain point need to be protected by a print mutex. I need to figure out if and how to handle child processes from an execv() call from inside a thread. Ideally it needs to gracefully exit and cleanup resources in the child process. Just like with the child process and execv() the signal/interrupt handling needs to be handled in a way that gracefully exits as appropriate. Prior to adding thread support, I added signal support and tested that it works. These interrupt signals work but have not been tested or reviewed now that the threading is added. A quick execution of this code shows that there are invalid reads (and therefore segfaults). I need to pick up here and make sure all of the resources are being properly managed. --- level_3/controller/c/controller.c | 93 +-- level_3/controller/c/private-common.c | 81 +++ level_3/controller/c/private-common.h | 263 +++++++- level_3/controller/c/private-control.c | 1 + level_3/controller/c/private-controller.c | 332 ++++----- level_3/controller/c/private-controller.h | 20 +- level_3/controller/c/private-entry.c | 97 +-- level_3/controller/c/private-entry.h | 2 +- level_3/controller/c/private-rule.c | 1039 ++++++++++++++++------------- level_3/controller/c/private-rule.h | 109 +-- level_3/controller/c/private-thread.c | 300 +++++++++ level_3/controller/c/private-thread.h | 121 ++++ level_3/controller/data/build/settings | 2 +- level_3/fake/c/main.c | 15 +- 14 files changed, 1669 insertions(+), 806 deletions(-) create mode 100644 level_3/controller/c/private-common.c create mode 100644 level_3/controller/c/private-thread.c create mode 100644 level_3/controller/c/private-thread.h diff --git a/level_3/controller/c/controller.c b/level_3/controller/c/controller.c index 63ba882..026be34 100644 --- a/level_3/controller/c/controller.c +++ b/level_3/controller/c/controller.c @@ -3,6 +3,7 @@ #include "private-control.h" #include "private-entry.h" #include "private-rule.h" +#include "private-thread.h" #include "private-controller.h" #ifdef __cplusplus @@ -145,6 +146,8 @@ extern "C" { controller_setting_t setting = controller_setting_t_initialize; controller_cache_t cache = controller_cache_t_initialize; + controller_mutex_t mutex = controller_mutex_t_initialize; + controller_thread_t thread = controller_macro_thread_t_initialize(&cache, &cache.action, data, &mutex, &setting, &cache.stack); f_string_static_t entry_name = f_string_static_t_initialize; @@ -273,19 +276,7 @@ extern "C" { } } - // a control file path is required. - if (!setting.path_control.used) { - status = f_string_append(controller_path_control, controller_path_control_length, &setting.path_control); - - if (F_status_is_error(status)) { - if (data->error.verbosity != f_console_verbosity_quiet) { - fll_error_print(data->error, F_status_set_fine(status), "f_string_append", F_true); - } - } - } - if (data->parameters[controller_parameter_daemon].result == f_console_result_found) { - if (data->parameters[controller_parameter_validate].result == f_console_result_found) { if (data->error.verbosity != f_console_verbosity_quiet) { fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); @@ -298,73 +289,39 @@ extern "C" { status = F_status_set_error(F_parameter); } + } - if (F_status_is_error_not(status)) { - setting.ready = controller_setting_ready_done; - - if (f_file_exists(setting.path_pid.string) == F_true) { - if (data->error.verbosity != f_console_verbosity_quiet) { - 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]); - } + if (F_status_is_error_not(status)) { + f_signal_set_fill(&data->signal.set); - status = F_status_set_error(F_available_not); - setting.ready = controller_setting_ready_abort; - } - - // @todo wait here until told to quit, listening for "control" commands (and listening for signals). - // @todo clear cache periodically while waiting. - // controller_macro_cache_t_delete_simple(cache); - } - } - else { + status = f_thread_signal_mask(SIG_BLOCK, &data->signal.set, 0); if (F_status_is_error_not(status)) { - status = controller_entry_read(*data, setting, entry_name, &cache, &setting.entry); + status = f_signal_open(&data->signal); } + // if there is an error opening a signal descriptor, then do not handle signals. if (F_status_is_error(status)) { - setting.ready = controller_setting_ready_fail; + f_signal_mask(SIG_UNBLOCK, &data->signal.set, 0); + f_signal_close(&data->signal); } - else { - status = controller_preprocess_entry(*data, &setting, &cache); - - if (data->parameters[controller_parameter_validate].result == f_console_result_none || data->parameters[controller_parameter_test].result == f_console_result_found) { - if (f_file_exists(setting.path_pid.string) == F_true) { - if (data->error.verbosity != f_console_verbosity_quiet) { - 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]); - } - - status = F_status_set_error(F_available_not); - setting.ready = controller_setting_ready_abort; - } + // a control file path is required. + if (!setting.path_control.used) { + status = f_string_append(controller_path_control, controller_path_control_length, &setting.path_control); - if (F_status_is_error_not(status)) { - status = controller_process_entry(data, &setting, &cache); - } - - if (!(status == F_child || status == F_signal)) { - if (F_status_is_error(status)) { - setting.ready = controller_setting_ready_fail; - } - else { - setting.ready = controller_setting_ready_done; - - // @todo wait here until told to quit, listening for "control" commands (and listening for signals). - // @todo clear cache periodically while waiting. - // controller_macro_cache_t_delete_simple(cache); - } + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, F_status_set_fine(status), "f_string_append", F_true); } } } } + if (F_status_is_error_not(status)) { + status = controller_thread_main(entry_name, &cache, &thread); + } + // ensure a newline is always put at the end of the program execution, unless in quiet mode. if (!(status == F_child || status == F_signal) && data->error.verbosity != f_console_verbosity_quiet) { if (F_status_is_error(status)) { @@ -372,10 +329,14 @@ extern "C" { } } + f_signal_close(&data->signal); + controller_file_pid_delete(*data, setting.path_pid); - controller_macro_setting_t_delete_simple(setting); - controller_macro_cache_t_delete_simple(cache); + controller_macro_setting_t_delete_simple(setting) + controller_macro_cache_t_delete_simple(cache) + controller_macro_mutex_t_delete_simple(mutex) + controller_macro_thread_t_delete_simple(thread) controller_delete_data(data); diff --git a/level_3/controller/c/private-common.c b/level_3/controller/c/private-common.c new file mode 100644 index 0000000..c1f869d --- /dev/null +++ b/level_3/controller/c/private-common.c @@ -0,0 +1,81 @@ +#include "controller.h" +#include "private-common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_asynchronouss_increase_ + f_status_t controller_asynchronouss_increase(controller_asynchronouss_t *asynchronouss) { + + if (asynchronouss->used + 1 > asynchronouss->size) { + f_array_length_t size = asynchronouss->used + controller_thread_asynchronous_allocation_step; + + if (size > f_array_length_t_size) { + if (asynchronouss->used + 1 > f_array_length_t_size) { + return F_status_set_error(F_array_too_large); + } + + size = f_array_length_t_size; + } + + return controller_asynchronouss_resize(size, asynchronouss); + } + + return F_data_not; + } +#endif // _di_controller_asynchronous_increase_ + +#ifndef _di_controller_asynchronouss_resize_ + f_status_t controller_asynchronouss_resize(const f_array_length_t length, controller_asynchronouss_t *asynchronouss) { + + f_status_t status = F_none; + + for (f_array_length_t i = length; i < asynchronouss->size; ++i) { + controller_macro_asynchronous_t_delete_simple(asynchronouss->array[i]); + } // for + + status = f_memory_resize(asynchronouss->size, length, sizeof(controller_asynchronous_t), (void **) & asynchronouss->array); + + if (F_status_is_error_not(status)) { + asynchronouss->size = length; + + if (asynchronouss->used > asynchronouss->size) { + asynchronouss->used = length; + } + } + + return status; + } +#endif // _di_controller_asynchronouss_resize_ + +#ifndef _di_controller_rules_increase_ + f_status_t controller_rules_increase(controller_rules_t *rules) { + + if (rules->used + 1 > rules->size) { + f_array_length_t size = rules->used + controller_default_allocation_step; + + if (size > f_string_length_t_size) { + if (rules->used + 1 > f_array_length_t_size) { + return F_status_set_error(F_array_too_large); + } + + size = f_array_length_t_size; + } + + const f_status_t status = f_memory_resize(rules->size, size, sizeof(controller_rule_t), (void **) & rules->array); + + if (F_status_is_error_not(status)) { + rules->size = size; + } + + return status; + } + + return F_none; + } +#endif // _di_controller_rules_increase_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index 5f931ec..69940b3 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -295,6 +295,29 @@ extern "C" { }; #endif // _di_controller_resource_limit_t_ +#ifndef _di_controller_mutex_t_ + typedef struct { + f_thread_mutex_t asynchronous; + f_thread_mutex_t cache; + f_thread_mutex_t print; + 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_mutex_t_initialize, \ + f_thread_mutex_t_initialize, \ + } + + #define controller_macro_mutex_t_delete_simple(mutex) \ + f_thread_mutex_delete(&mutex.asynchronous); \ + f_thread_mutex_delete(&mutex.cache); \ + f_thread_mutex_delete(&mutex.print); \ + f_thread_mutex_delete(&mutex.rule); +#endif // _di_controller_mutex_t_ + #ifndef _di_controller_rule_action_t_ #define controller_rule_action_method_string_extended "FSS-0001 (Extended)" #define controller_rule_action_method_string_extended_list "FSS-0003 (Extended List)" @@ -457,7 +480,8 @@ extern "C" { typedef struct { f_status_t status; - f_number_signed_t process; // @todo: for background/threaded support (ideally should hold the process id, but remove if this ends up not being the strategy) (this can also be used by the parent/main process to check to see if the child no longer a child of this process). + + f_thread_mutex_t lock; f_number_unsigned_t timeout_kill; f_number_unsigned_t timeout_start; @@ -491,13 +515,14 @@ extern "C" { f_execute_scheduler_t scheduler; controller_rule_items_t items; + + void *asynchronous; } controller_rule_t; #define controller_rule_t_initialize \ { \ F_known_not, \ - 0, \ - 0, \ + f_thread_mutex_t_initialize, \ 0, \ 0, \ 0, \ @@ -522,9 +547,11 @@ extern "C" { f_limit_sets_t_initialize, \ f_execute_scheduler_t_initialize, \ controller_rule_items_initialize, \ + 0, \ } #define controller_macro_rule_t_delete_simple(rule) \ + f_macro_thread_mutex_t_delete_simple(rule.lock) \ f_macro_string_dynamic_t_delete_simple(rule.id) \ f_macro_string_dynamic_t_delete_simple(rule.name) \ f_macro_string_dynamic_t_delete_simple(rule.path) \ @@ -710,8 +737,8 @@ extern "C" { typedef struct { bool interruptable; - bool lock; // @todo: this is intended for mutex write locking of this setting for thread safety, remove this if another approach is used. uint8_t ready; + int signal; f_number_unsigned_t timeout_kill; f_number_unsigned_t timeout_start; @@ -731,7 +758,7 @@ extern "C" { #define controller_setting_t_initialize \ { \ F_false, \ - F_false, \ + 0, \ 0, \ 3, \ 3, \ @@ -753,11 +780,45 @@ extern "C" { controller_macro_rules_t_delete_simple(setting.rules) #endif // _di_controller_setting_t -#ifndef _di_controller_cache_t_ +#ifndef _di_controller_cache_action_t_ typedef struct { f_string_length_t line_action; f_string_length_t line_item; + f_string_dynamic_t name_action; + f_string_dynamic_t name_file; + f_string_dynamic_t name_item; + + f_string_dynamic_t generic; + } controller_cache_action_t; + + #define controller_cache_action_t_initialize \ + { \ + 0, \ + 0, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + } + + #define controller_macro_cache_action_t_clear(cache) \ + cache.line_action = 0; \ + cache.line_item = 0; \ + cache.name_action.used = 0; \ + cache.name_file.used = 0; \ + cache.name_item.used = 0; \ + cache.generic.used = 0; + + #define controller_macro_cache_action_t_delete_simple(cache) \ + f_macro_string_dynamic_t_delete_simple(cache.name_action) \ + f_macro_string_dynamic_t_delete_simple(cache.name_file) \ + f_macro_string_dynamic_t_delete_simple(cache.name_item) \ + f_macro_string_dynamic_t_delete_simple(cache.generic) +#endif // _di_controller_cache_action_t_ + +#ifndef _di_controller_cache_t_ + typedef struct { f_time_spec_t timestamp; f_string_range_t range_action; @@ -776,18 +837,13 @@ extern "C" { f_string_dynamic_t buffer_file; f_string_dynamic_t buffer_item; - f_string_dynamic_t buffer_other; f_string_dynamic_t buffer_path; - f_string_dynamic_t name_action; - f_string_dynamic_t name_file; - f_string_dynamic_t name_item; + controller_cache_action_t action; } controller_cache_t; #define controller_cache_t_initialize \ { \ - 0, \ - 0, \ f_time_spec_t_initialize, \ f_string_range_t_initialize, \ f_array_lengths_t_initialize, \ @@ -802,10 +858,7 @@ extern "C" { f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ + controller_cache_action_t_initialize, \ } #define controller_macro_cache_t_delete_simple(cache) \ @@ -820,13 +873,183 @@ extern "C" { f_macro_fss_objects_t_delete_simple(cache.object_items) \ f_macro_string_dynamic_t_delete_simple(cache.buffer_file) \ f_macro_string_dynamic_t_delete_simple(cache.buffer_item) \ - f_macro_string_dynamic_t_delete_simple(cache.buffer_other) \ f_macro_string_dynamic_t_delete_simple(cache.buffer_path) \ - f_macro_string_dynamic_t_delete_simple(cache.name_action) \ - f_macro_string_dynamic_t_delete_simple(cache.name_file) \ - f_macro_string_dynamic_t_delete_simple(cache.name_item) + controller_macro_cache_action_t_delete_simple(cache.action) #endif // _di_controller_cache_t_ +#ifndef _di_controller_asynchronous_t_ + enum { + controller_asynchronous_state_active = 1, + controller_asynchronous_state_done, + controller_asynchronous_state_joined, + }; + + typedef struct { + f_thread_id_t id; + f_array_length_t index; + + uint8_t state; + uint8_t action; + uint8_t options; + + void *thread; + f_array_lengths_t stack; + controller_cache_action_t cache; + } controller_asynchronous_t; + + #define controller_asynchronous_t_initialize { f_thread_id_t_initialize, 0, 0, 0, 0, 0, f_array_lengths_t_initialize, controller_cache_action_t_initialize } + + #define controller_macro_asynchronous_t_clear(asynchronous) \ + f_macro_thread_id_t_clear(asynchronous.id) \ + asynchronous.index = 0; \ + asynchronous.state = 0; \ + asynchronous.action = 0; \ + asynchronous.options = 0; \ + asynchronous.thread = 0; \ + f_macro_array_lengths_t_clear(asynchronous.stack) \ + controller_macro_cache_action_t_clear(asynchronous.cache) + + #define controller_macro_asynchronous_t_delete_simple(asynchronous) \ + controller_macro_cache_action_t_delete_simple(asynchronous.cache) \ + f_macro_array_lengths_t_delete_simple(asynchronous.stack) +#endif // _di_controller_asynchronous_t_ + +#ifndef _di_controller_asynchronouss_t_ + typedef struct { + controller_asynchronous_t *array; + + f_array_length_t size; + f_array_length_t used; + } controller_asynchronouss_t; + + #define controller_asynchronouss_t_initialize \ + { \ + 0, \ + 0, \ + 0, \ + } + + #define controller_macro_asynchronouss_t_delete_simple(asynchronouss) \ + asynchronouss.used = asynchronouss.size; \ + while (asynchronouss.used) { \ + asynchronouss.used--; \ + controller_macro_asynchronous_t_delete_simple(asynchronouss.array[asynchronouss.used]) \ + } \ + f_memory_delete(asynchronouss.size, sizeof(controller_asynchronous_t), (void **) & asynchronouss.array); \ + asynchronouss.size = 0; +#endif // _di_controller_asynchronouss_t_ + +#ifndef _di_controller_thread_t_ + #define controller_thread_cache_cleanup_interval_long 3600 // 1 hour in seconds. + #define controller_thread_cache_cleanup_interval_short 180 // 3 minutes in seconds. + #define controller_thread_asynchronous_allocation_step 16 // Total number of asynchronous threads increase by. + #define controller_thread_asynchronous_total 65535 // Total number of asynchronous threads allowed at any one time. + + typedef struct { + controller_cache_t *cache_main; + controller_cache_action_t *cache_action; + controller_data_t *data; + controller_mutex_t *mutex; + controller_setting_t *setting; + f_array_lengths_t *stack; + controller_asynchronouss_t asynchronouss; + } controller_thread_t; + + #define controller_thread_t_initialize { 0, 0, 0, 0, 0, 0, controller_asynchronouss_t_initialize } + + #define controller_macro_thread_t_initialize(cache_main, cache_action, data, mutex, setting, stack) { cache_main, cache_action, data, mutex, setting, stack, controller_asynchronouss_t_initialize } + + #define controller_macro_thread_t_clear(thread) \ + thread.cache_main = 0; \ + thread.cache_action = 0; \ + thread.data = 0; \ + thread.mutex = 0; \ + thread.setting = 0; \ + thread.stack = 0; \ + thread.asynchronouss.used = 0; + + #define controller_macro_thread_t_delete_simple(thread) \ + controller_asynchronouss_resize(0, &thread.asynchronouss); +#endif // _di_controller_thread_t_ + +/** + * Resize the asynchronouss array to a larger size. + * + * This will resize making the string larger based on the given length. + * If the given length is too large for the buffer, then attempt to set max buffer size (f_array_length_t_size). + * If already set to the maximum buffer size, then the resize will fail. + * + * @param amount + * A positive number representing how much to increase the size by. + * @param asynchronouss + * The asynchronous array to resize. + * + * @return + * F_none on success. + * F_data_not on success, but there is no reason to increase size (used + amount <= size). + * + * F_memory_not (with error bit) on out of memory. + * F_parameter (with error bit) if a parameter is invalid. + * F_array_too_large (with error bit) if the new array length is too large. + */ + +/** + * Increase the size of the asynchronouss array, but only if necessary. + * + * If the given length is too large for the buffer, then attempt to set max buffer size (f_array_length_t_size). + * If already set to the maximum buffer size, then the resize will fail. + * + * @param asynchronouss + * The asynchronous array to resize. + * + * @return + * F_none on success. + * F_data_not on success, but there is no reason to increase size (used + controller_thread_asynchronous_allocation_step <= size). + * + * F_array_too_large (with error bit) if the new array length is too large. + * F_memory_not (with error bit) on out of memory. + * F_parameter (with error bit) if a parameter is invalid. + */ +#ifndef _di_controller_asynchronouss_increase_ + extern f_status_t controller_asynchronouss_increase(controller_asynchronouss_t *asynchronouss); +#endif // _di_controller_asynchronouss_increase_ + +/** + * Resize the string asynchronouss array. + * + * @param length + * The new size to use. + * @param asynchronouss + * The asynchronous array to resize. + * + * @return + * F_none on success. + * + * F_memory_not (with error bit) on out of memory. + * F_parameter (with error bit) if a parameter is invalid. + */ +#ifndef _di_controller_asynchronouss_resize_ + extern f_status_t controller_asynchronouss_resize(const f_array_length_t length, controller_asynchronouss_t *asynchronouss); +#endif // _di_controller_asynchronouss_resize_ + +/** + * Increase the size of the rules array, but only if necessary. + * + * @param rules + * The rules to resize. + * + * @return + * F_none on success. + * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length. + * + * Errors (with error bit) from: f_memory_resize(). + * + * @see f_memory_resize() + */ +#ifndef _di_controller_rules_increase_ + extern f_status_t controller_rules_increase(controller_rules_t *rules) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_increase_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/controller/c/private-control.c b/level_3/controller/c/private-control.c index 8008106..c4323b8 100644 --- a/level_3/controller/c/private-control.c +++ b/level_3/controller/c/private-control.c @@ -1,6 +1,7 @@ #include "controller.h" #include "private-common.h" #include "private-control.h" +#include "private-thread.h" #ifdef __cplusplus extern "C" { diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index d058d40..b3a5139 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -3,6 +3,7 @@ #include "private-control.h" #include "private-entry.h" #include "private-rule.h" +#include "private-thread.h" #include "private-controller.h" #ifdef __cplusplus @@ -44,27 +45,27 @@ extern "C" { f_status_t status = F_none; f_file_t file = f_file_t_initialize; - cache->name_file.used = 0; + cache->action.name_file.used = 0; cache->buffer_file.used = 0; f_macro_time_spec_t_clear(cache->timestamp); - status = f_string_append(path_prefix, path_prefix_length, &cache->name_file); + status = f_string_append(path_prefix, path_prefix_length, &cache->action.name_file); if (F_status_is_error_not(status)) { - status = f_string_append(f_path_separator_s, f_path_separator_length, &cache->name_file); + status = f_string_append(f_path_separator_s, f_path_separator_length, &cache->action.name_file); } if (F_status_is_error_not(status)) { - status = f_string_append(path_name.string, path_name.used, &cache->name_file); + status = f_string_append(path_name.string, path_name.used, &cache->action.name_file); } if (F_status_is_error_not(status)) { - status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &cache->name_file); + status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &cache->action.name_file); } if (F_status_is_error_not(status)) { - status = f_string_append(path_suffix, path_suffix_length, &cache->name_file); + status = f_string_append(path_suffix, path_suffix_length, &cache->action.name_file); } if (F_status_is_error(status)) { @@ -72,19 +73,19 @@ extern "C" { return status; } - status = f_string_dynamic_terminate_after(&cache->name_file); + status = f_string_dynamic_terminate_after(&cache->action.name_file); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); return status; } - const f_string_length_t path_length = setting.path_setting.used ? setting.path_setting.used + f_path_separator_length + cache->name_file.used : cache->name_file.used; + const f_string_length_t path_length = setting.path_setting.used ? setting.path_setting.used + f_path_separator_length + cache->action.name_file.used : cache->action.name_file.used; char path[path_length + 1]; if (setting.path_setting.used) { memcpy(path, setting.path_setting.string, setting.path_setting.used); - memcpy(path + setting.path_setting.used + f_path_separator_length, cache->name_file.string, cache->name_file.used); + memcpy(path + setting.path_setting.used + f_path_separator_length, cache->action.name_file.string, cache->action.name_file.used); path[setting.path_setting.used] = f_path_separator_s[0]; } @@ -229,15 +230,15 @@ extern "C" { status = F_status_set_fine(status); if (status == F_number) { - cache->buffer_other.used = 0; + cache->action.generic.used = 0; - status = f_string_dynamic_partial_append_nulless(buffer, range, &cache->buffer_other); + status = f_string_dynamic_partial_append_nulless(buffer, range, &cache->action.generic); if (F_status_is_error(status)) { return F_status_set_error(status); } - status = f_account_id_user_by_name(cache->buffer_other.string, id); + status = f_account_id_user_by_name(cache->action.generic.string, id); if (F_status_is_error(status)) { return F_status_set_error(status); @@ -271,15 +272,15 @@ extern "C" { status = F_status_set_fine(status); if (status == F_number) { - cache->buffer_other.used = 0; + cache->action.generic.used = 0; - status = f_string_dynamic_partial_append_nulless(buffer, range, &cache->buffer_other); + status = f_string_dynamic_partial_append_nulless(buffer, range, &cache->action.generic); if (F_status_is_error(status)) { return F_status_set_error(status); } - status = f_account_id_group_by_name(cache->buffer_other.string, id); + status = f_account_id_group_by_name(cache->action.generic.string, id); if (F_status_is_error(status)) { return F_status_set_error(status); @@ -318,14 +319,14 @@ extern "C" { if (F_status_set_fine(status) == F_memory_not) { fll_error_file_print(data.error, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file); - controller_entry_error_print(data.error, *cache); + controller_entry_error_print(data.error, cache->action); return status; } fll_error_file_print(data.warning, F_status_set_fine(status), "controller_file_pid_create", F_true, setting->path_pid.string, "create", fll_error_file_type_file); - controller_entry_error_print(data.warning, *cache); + controller_entry_error_print(data.warning, cache->action); status = F_none; } @@ -336,7 +337,7 @@ extern "C" { #endif // _di_controller_perform_ready_ #ifndef _di_controller_preprocess_entry_ - f_status_t controller_preprocess_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) { + f_status_t controller_preprocess_entry(controller_cache_t *cache, controller_thread_t *thread) { f_status_t status = F_none; f_status_t status2 = F_none; @@ -346,6 +347,8 @@ extern "C" { f_array_length_t at_i = 0; f_array_length_t at_j = 1; + controller_data_t *data = thread->data; + controller_setting_t *setting = thread->setting; controller_entry_actions_t *actions = 0; uint8_t error_has = F_false; @@ -353,15 +356,16 @@ extern "C" { setting->ready = controller_setting_ready_no; cache->ats.used = 0; - cache->line_action = 0; - cache->line_item = 0; - cache->name_action.used = 0; - cache->name_item.used = 0; + + thread->cache_action->line_action = 0; + thread->cache_action->line_item = 0; + thread->cache_action->name_action.used = 0; + thread->cache_action->name_item.used = 0; f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); + fll_error_print(data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); return status; } @@ -370,14 +374,14 @@ extern "C" { cache->ats.array[1] = 0; cache->ats.used = 2; - cache->line_item = setting->entry.items.array[0].line; - cache->name_item.used = 0; + thread->cache_action->line_item = setting->entry.items.array[0].line; + thread->cache_action->name_item.used = 0; - status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &cache->name_item); + status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &thread->cache_action->name_item); if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data.error, *cache); + fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -388,14 +392,18 @@ extern "C" { for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) { - cache->line_action = actions->array[cache->ats.array[at_j]].line; - cache->name_action.used = 0; + if (setting->signal) { + return F_signal; + } - status2 = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action); + thread->cache_action->line_action = actions->array[cache->ats.array[at_j]].line; + thread->cache_action->name_action.used = 0; + + status2 = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &thread->cache_action->name_action); if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data.error, *cache); + fll_error_print(data->error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); + controller_entry_error_print(data->error, *thread->cache_action); return status2; } @@ -403,13 +411,13 @@ extern "C" { if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) { if (setting->ready == controller_setting_ready_wait) { - if (data.warning.verbosity == f_console_verbosity_debug) { - fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.warning.to.stream, "%s%sMultiple '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s); - fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, controller_string_ready_s, data.warning.notable.after->string); - fprintf(data.warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]); + if (data->warning.verbosity == f_console_verbosity_debug) { + fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(data->warning.to.stream, "%s%sMultiple '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s); + fprintf(data->warning.to.stream, "%s%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, controller_string_ready_s, data->warning.notable.after->string); + fprintf(data->warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(data.warning, *cache); + controller_entry_error_print(data->warning, *thread->cache_action); } } @@ -432,14 +440,14 @@ extern "C" { for (j = 2; j < cache->ats.used; j += 2) { if (cache->ats.array[j] == i) { - if (data.error.verbosity != f_console_verbosity_quiet) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sThe entry item named '", 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->entry.items.array[i].name.string, data.error.notable.after->string); - fprintf(data.error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data->error.to.stream, "%s%sThe entry item named '", 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->entry.items.array[i].name.string, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); } - controller_entry_error_print(data.error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); if (F_status_is_error_not(status)) { status = F_status_set_error(F_recurse); @@ -455,8 +463,8 @@ 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(data.error, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true); - controller_entry_error_print(data.error, *cache); + fll_error_print(data->error, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true); + controller_entry_error_print(data->error, *thread->cache_action); return status2; } @@ -472,17 +480,17 @@ extern "C" { cache->ats.array[at_j] = 0; cache->ats.used += 2; - cache->name_action.used = 0; - cache->line_action = 0; + thread->cache_action->name_action.used = 0; + thread->cache_action->line_action = 0; - cache->name_item.used = 0; - cache->line_item = setting->entry.items.array[i].line; + thread->cache_action->name_item.used = 0; + thread->cache_action->line_item = setting->entry.items.array[i].line; - status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[i].name, &cache->name_item); + status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[i].name, &thread->cache_action->name_item); if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data.error, *cache); + fll_error_print(data->error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); + controller_entry_error_print(data->error, *thread->cache_action); return status2; } @@ -493,14 +501,14 @@ extern "C" { if (error_has || i >= setting->entry.items.used) { if (i >= setting->entry.items.used) { - if (data.error.verbosity != f_console_verbosity_quiet) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sThe entry item named '", 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, actions->array[cache->ats.array[at_j]].parameters.array[0].string, data.error.notable.after->string); - fprintf(data.error.to.stream, "%s' does not exist.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data->error.to.stream, "%s%sThe entry item named '", 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, actions->array[cache->ats.array[at_j]].parameters.array[0].string, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' does not exist.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); } - controller_entry_error_print(data.error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); if (F_status_is_error_not(status)) { status = F_status_set_error(F_valid_not); @@ -513,8 +521,8 @@ extern "C" { } } // for - cache->line_action = 0; - cache->name_action.used = 0; + thread->cache_action->line_action = 0; + thread->cache_action->name_action.used = 0; // end of actions found, so drop to previous loop in stack. if (cache->ats.array[at_j] == actions->used) { @@ -528,14 +536,14 @@ extern "C" { cache->ats.used -= 2; cache->ats.array[at_j]++; - cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; - cache->name_item.used = 0; + thread->cache_action->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; + thread->cache_action->name_item.used = 0; - status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item); + status2 = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &thread->cache_action->name_item); if (F_status_is_error(status2)) { - fll_error_print(data.error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data.error, *cache); + fll_error_print(data->error, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true); + controller_entry_error_print(data->error, *thread->cache_action); return status2; } @@ -552,7 +560,7 @@ extern "C" { #endif // _di_controller_preprocess_entry_ #ifndef _di_controller_process_entry_ - f_status_t controller_process_entry(controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) { + f_status_t controller_process_entry(controller_cache_t *cache, controller_thread_t *thread) { f_status_t status = F_none; f_array_length_t i = 0; @@ -564,18 +572,21 @@ extern "C" { uint8_t rule_options = 0; + controller_data_t *data = thread->data; + controller_setting_t *setting = thread->setting; controller_entry_actions_t *actions = 0; const bool simulate = data->parameters[controller_parameter_test].result == f_console_result_found; const bool validate = data->parameters[controller_parameter_validate].result == f_console_result_found; cache->ats.used = 0; - cache->line_action = 0; - cache->line_item = 0; - cache->name_action.used = 0; - cache->name_item.used = 0; cache->stack.used = 0; + thread->cache_action->line_action = 0; + thread->cache_action->line_item = 0; + thread->cache_action->name_action.used = 0; + thread->cache_action->name_item.used = 0; + if (setting->ready == controller_setting_ready_yes) { status = controller_perform_ready(*data, setting, cache); if (F_status_is_error(status)) return status; @@ -585,7 +596,7 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -595,14 +606,14 @@ extern "C" { cache->ats.array[1] = 0; cache->ats.used = 2; - cache->line_item = setting->entry.items.array[0].line; - cache->name_item.used = 0; + thread->cache_action->line_item = setting->entry.items.array[0].line; + thread->cache_action->name_item.used = 0; - status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &cache->name_item); + status = controller_string_dynamic_append_terminated(setting->entry.items.array[0].name, &thread->cache_action->name_item); if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -620,14 +631,19 @@ extern "C" { for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) { - cache->line_action = actions->array[cache->ats.array[at_j]].line; - cache->name_action.used = 0; + if (setting->signal) { + status = F_signal; + break; + } + + thread->cache_action->line_action = actions->array[cache->ats.array[at_j]].line; + thread->cache_action->name_action.used = 0; - status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->name_action); + status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &thread->cache_action->name_action); if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -639,7 +655,7 @@ extern "C" { if (simulate) { fprintf(data->output.stream, "%c", f_string_eol_s[0]); fprintf(data->output.stream, "The entry item action '"); - fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_action.string, data->context.set.title.after->string); + fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, thread->cache_action->name_action.string, data->context.set.title.after->string); if (actions->array[cache->ats.array[at_j]].parameters.used) { fprintf(data->output.stream, f_string_space_s); @@ -655,7 +671,7 @@ extern "C" { if (data->error.verbosity != f_console_verbosity_quiet) { fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); fprintf(data->error.to.stream, "%s%sThe entry item action '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s); - fprintf(data->error.to.stream, "%s%s%s", data->error.context.after->string, data->error.notable.before->string, cache->name_action.string); + fprintf(data->error.to.stream, "%s%s%s", data->error.context.after->string, data->error.notable.before->string, thread->cache_action->name_action.string); if (actions->array[cache->ats.array[at_j]].parameters.used) { fprintf(data->error.to.stream, f_string_space_s); @@ -669,14 +685,14 @@ extern "C" { fprintf(data->error.to.stream, "%s state, skipping execution.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); } - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return F_status_is_error(F_require); } else if (data->warning.verbosity == f_console_verbosity_debug) { fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(data->warning.to.stream, "%s%sThe entry item action '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s); - fprintf(data->warning.to.stream, "%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, cache->name_action.string); + fprintf(data->warning.to.stream, "%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, thread->cache_action->name_action.string); if (actions->array[cache->ats.array[at_j]].parameters.used) { fprintf(data->warning.to.stream, f_string_space_s); @@ -689,14 +705,14 @@ extern "C" { fprintf(data->warning.to.stream, "%s%sfailed%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string); fprintf(data->warning.to.stream, "%s state, skipping execution.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(data->warning, *cache); + controller_entry_error_print(data->warning, *thread->cache_action); } } else { if (simulate) { fprintf(data->output.stream, "%c", f_string_eol_s[0]); fprintf(data->output.stream, "The entry item action '"); - fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_action.string, data->context.set.title.after->string); + fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, thread->cache_action->name_action.string, data->context.set.title.after->string); if (actions->array[cache->ats.array[at_j]].parameters.used) { fprintf(data->output.stream, f_string_space_s); @@ -710,7 +726,7 @@ extern "C" { else if (data->warning.verbosity == f_console_verbosity_debug) { fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(data->warning.to.stream, "%s%sThe entry item action '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s); - fprintf(data->warning.to.stream, "%s%s", data->warning.notable.before->string, cache->name_action.string); + fprintf(data->warning.to.stream, "%s%s", data->warning.notable.before->string, thread->cache_action->name_action.string); if (actions->array[cache->ats.array[at_j]].parameters.used) { fprintf(data->warning.to.stream, f_string_space_s); @@ -721,7 +737,7 @@ extern "C" { fprintf(data->warning.to.stream, "%s%sfailed%s", data->warning.context.after->string, data->warning.notable.before->string, data->warning.notable.after->string); fprintf(data->warning.to.stream, "%s state, skipping.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(data->warning, *cache); + controller_entry_error_print(data->warning, *thread->cache_action); } } @@ -764,7 +780,7 @@ extern "C" { fprintf(data->error.to.stream, "%s detected.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); } - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return F_status_is_error(F_critical); } @@ -773,7 +789,7 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -787,17 +803,17 @@ extern "C" { cache->ats.used += 2; - cache->name_action.used = 0; - cache->line_action = 0; + thread->cache_action->name_action.used = 0; + thread->cache_action->line_action = 0; - cache->name_item.used = 0; - cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; + thread->cache_action->name_item.used = 0; + thread->cache_action->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; - status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item); + status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &thread->cache_action->name_item); if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -805,7 +821,7 @@ extern "C" { if (simulate) { fprintf(data->output.stream, "%c", f_string_eol_s[0]); fprintf(data->output.stream, "Processing entry item '"); - fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, cache->name_item.string, data->context.set.title.after->string); + fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, thread->cache_action->name_item.string, data->context.set.title.after->string); fprintf(data->output.stream, "'.%c", f_string_eol_s[0]); } @@ -818,7 +834,7 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "controller_rules_increase", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return status; } @@ -846,41 +862,45 @@ extern "C" { if (at == setting->rules.used) { // rule execution will re-use the existing cache, so save the current cache. - const f_array_length_t cache_line_action = cache->line_action; - const f_array_length_t cache_line_item = cache->line_item; + const f_array_length_t cache_line_action = thread->cache_action->line_action; + const f_array_length_t cache_line_item = thread->cache_action->line_item; - const f_string_length_t cache_name_action_used = cache->name_action.used; - const f_string_length_t cache_name_item_used = cache->name_item.used; - const f_string_length_t cache_name_file_used = cache->name_file.used; + const f_string_length_t cache_name_action_used = thread->cache_action->name_action.used; + const f_string_length_t cache_name_item_used = thread->cache_action->name_item.used; + const f_string_length_t cache_name_file_used = thread->cache_action->name_file.used; char cache_name_action[cache_name_action_used]; char cache_name_item[cache_name_item_used]; char cache_name_file[cache_name_file_used]; - memcpy(cache_name_action, cache->name_action.string, cache->name_action.used); - memcpy(cache_name_item, cache->name_item.string, cache->name_item.used); - memcpy(cache_name_file, cache->name_file.string, cache->name_file.used); + memcpy(cache_name_action, thread->cache_action->name_action.string, thread->cache_action->name_action.used); + memcpy(cache_name_item, thread->cache_action->name_item.string, thread->cache_action->name_item.used); + memcpy(cache_name_file, thread->cache_action->name_file.string, thread->cache_action->name_file.used); + + f_thread_mutex_lock(&thread->mutex->rule); - status = controller_rule_read(*data, *setting, rule_id, cache, &setting->rules.array[setting->rules.used]); + status = controller_rule_read(*data, *setting, rule_id, thread, cache, &setting->rules.array[setting->rules.used]); + + f_thread_mutex_unlock(&thread->mutex->rule); // restore cache. - memcpy(cache->name_action.string, cache_name_action, cache_name_action_used); - memcpy(cache->name_item.string, cache_name_item, cache_name_item_used); - memcpy(cache->name_file.string, cache_name_file, cache_name_file_used); + memcpy(thread->cache_action->name_action.string, cache_name_action, cache_name_action_used); + memcpy(thread->cache_action->name_item.string, cache_name_item, cache_name_item_used); + memcpy(thread->cache_action->name_file.string, cache_name_file, cache_name_file_used); - cache->name_action.string[cache_name_action_used] = 0; - cache->name_item.string[cache_name_item_used] = 0; - cache->name_file.string[cache_name_file_used] = 0; + thread->cache_action->name_action.string[cache_name_action_used] = 0; + thread->cache_action->name_item.string[cache_name_item_used] = 0; + thread->cache_action->name_file.string[cache_name_file_used] = 0; - cache->name_action.used = cache_name_action_used; - cache->name_item.used = cache_name_item_used; - cache->name_file.used = cache_name_file_used; + thread->cache_action->name_action.used = cache_name_action_used; + thread->cache_action->name_item.used = cache_name_item_used; + thread->cache_action->name_file.used = cache_name_file_used; - cache->line_action = cache_line_action; - cache->line_item = cache_line_item; + thread->cache_action->line_action = cache_line_action; + thread->cache_action->line_item = cache_line_item; if (F_status_is_error(status)) { - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); if (!simulate) break; } @@ -892,20 +912,20 @@ extern "C" { if (F_status_is_error_not(status)) { // rule execution will re-use the existing cache, so save the current cache. - const f_array_length_t cache_line_action = cache->line_action; - const f_array_length_t cache_line_item = cache->line_item; + const f_array_length_t cache_line_action = thread->cache_action->line_action; + const f_array_length_t cache_line_item = thread->cache_action->line_item; - const f_string_length_t cache_name_action_used = cache->name_action.used; - const f_string_length_t cache_name_item_used = cache->name_item.used; - const f_string_length_t cache_name_file_used = cache->name_file.used; + const f_string_length_t cache_name_action_used = thread->cache_action->name_action.used; + const f_string_length_t cache_name_item_used = thread->cache_action->name_item.used; + const f_string_length_t cache_name_file_used = thread->cache_action->name_file.used; char cache_name_action[cache_name_action_used]; char cache_name_item[cache_name_item_used]; char cache_name_file[cache_name_file_used]; - memcpy(cache_name_action, cache->name_action.string, cache->name_action.used); - memcpy(cache_name_item, cache->name_item.string, cache->name_item.used); - memcpy(cache_name_file, cache->name_file.string, cache->name_file.used); + memcpy(cache_name_action, thread->cache_action->name_action.string, thread->cache_action->name_action.used); + memcpy(cache_name_item, thread->cache_action->name_item.string, thread->cache_action->name_item.used); + memcpy(cache_name_file, thread->cache_action->name_file.string, thread->cache_action->name_file.used); if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { rule_options = 0; @@ -914,10 +934,6 @@ extern "C" { rule_options |= controller_rule_option_simulate; } - 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_require) { rule_options |= controller_rule_option_require; } @@ -926,31 +942,37 @@ extern "C" { rule_options |= controller_rule_option_wait; } - // @todo: this will also need to support the asynchronous/wait behavior. - status = controller_rule_process(at, controller_rule_action_type_start, rule_options, data, setting, cache); + if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_asynchronous) { + rule_options |= controller_rule_option_asynchronous; + + status = controller_rule_process_asynchronous(at, controller_rule_action_type_start, rule_options, thread); + } + else { + status = controller_rule_process(at, controller_rule_action_type_start, rule_options, thread); + } if (status == F_child || status == F_signal) break; } // restore cache. - memcpy(cache->name_action.string, cache_name_action, cache_name_action_used); - memcpy(cache->name_item.string, cache_name_item, cache_name_item_used); - memcpy(cache->name_file.string, cache_name_file, cache_name_file_used); + memcpy(thread->cache_action->name_action.string, cache_name_action, cache_name_action_used); + memcpy(thread->cache_action->name_item.string, cache_name_item, cache_name_item_used); + memcpy(thread->cache_action->name_file.string, cache_name_file, cache_name_file_used); - cache->name_action.string[cache_name_action_used] = 0; - cache->name_item.string[cache_name_item_used] = 0; - cache->name_file.string[cache_name_file_used] = 0; + thread->cache_action->name_action.string[cache_name_action_used] = 0; + thread->cache_action->name_item.string[cache_name_item_used] = 0; + thread->cache_action->name_file.string[cache_name_file_used] = 0; - cache->name_action.used = cache_name_action_used; - cache->name_item.used = cache_name_item_used; - cache->name_file.used = cache_name_file_used; + thread->cache_action->name_action.used = cache_name_action_used; + thread->cache_action->name_item.used = cache_name_item_used; + thread->cache_action->name_file.used = cache_name_file_used; - cache->line_action = cache_line_action; - cache->line_item = cache_line_item; + thread->cache_action->line_action = cache_line_action; + thread->cache_action->line_item = cache_line_item; } if (F_status_is_error(status)) { - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); if (!simulate || F_status_set_fine(status) == F_memory_not) { break; @@ -1004,7 +1026,7 @@ extern "C" { fprintf(data->error.to.stream, "%s detected.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); } - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); return F_status_is_error(F_critical); } @@ -1024,10 +1046,14 @@ extern "C" { } } // for + if (setting->signal) { + status = F_signal; + } + if (status == F_child || status == F_signal) break; - cache->line_action = 0; - cache->name_action.used = 0; + thread->cache_action->line_action = 0; + thread->cache_action->name_action.used = 0; if (F_status_is_error(status)) { if (!simulate || F_status_set_fine(status) == F_memory_not) { @@ -1047,14 +1073,14 @@ extern "C" { cache->ats.used -= 2; cache->ats.array[at_j]++; - cache->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; - cache->name_item.used = 0; + thread->cache_action->line_item = setting->entry.items.array[cache->ats.array[at_i]].line; + thread->cache_action->name_item.used = 0; - status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &cache->name_item); + status = controller_string_dynamic_append_terminated(setting->entry.items.array[cache->ats.array[at_i]].name, &thread->cache_action->name_item); if (F_status_is_error(status)) { fll_error_print(data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); - controller_entry_error_print(data->error, *cache); + controller_entry_error_print(data->error, *thread->cache_action); break; } diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index 62e5e2b..a173406 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -238,12 +238,10 @@ extern "C" { /** * Pre-process all items for the loaded entry. * - * @param data - * The program data. - * @param setting - * The controller settings data. * @param cache - * The cache. + * The main/global cache to use. + * @param thread + * The thread data. * * @return * F_none on success. @@ -262,18 +260,16 @@ extern "C" { * @see f_string_dynamic_terminate_after() */ #ifndef _di_controller_preprocess_entry_ - extern f_status_t controller_preprocess_entry(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_preprocess_entry(controller_cache_t *cache, controller_thread_t *thread) f_gcc_attribute_visibility_internal; #endif // _di_controller_preprocess_entry_ /** * Process (execute) all items for the loaded entry. * - * @param data - * The program data. - * @param setting - * The controller settings data. * @param cache - * The cache. + * The main/global cache to use. + * @param thread + * The thread data. * * @return * F_none on success. @@ -288,7 +284,7 @@ extern "C" { * @see controller_string_dynamic_append_terminated() */ #ifndef _di_controller_process_entry_ - extern f_status_t controller_process_entry(controller_data_t *data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_process_entry(controller_cache_t *cache, controller_thread_t *thread) f_gcc_attribute_visibility_internal; #endif // _di_controller_process_entry_ /** diff --git a/level_3/controller/c/private-entry.c b/level_3/controller/c/private-entry.c index e1cc196..4679ef7 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -2,6 +2,7 @@ #include "private-common.h" #include "private-controller.h" #include "private-entry.h" +#include "private-thread.h" #ifdef __cplusplus extern "C" { @@ -152,8 +153,8 @@ extern "C" { for (; i < cache->object_actions.used; ++i) { - cache->line_action = 0; - cache->name_action.used = 0; + cache->action.line_action = 0; + cache->action.name_action.used = 0; action = &actions->array[actions->used]; action->type = 0; @@ -163,49 +164,49 @@ extern "C" { action->status = F_known_not; action->parameters.used = 0; - status = f_fss_count_lines(cache->buffer_file, cache->object_actions.array[i].start, &cache->line_action); + status = f_fss_count_lines(cache->buffer_file, cache->object_actions.array[i].start, &cache->action.line_action); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } - action->line = ++cache->line_action; + action->line = ++cache->action.line_action; - status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_actions.array[i], &cache->name_action); + status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_actions.array[i], &cache->action.name_action); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); break; } - if (fl_string_dynamic_compare_string(controller_string_consider_s, cache->name_action, controller_string_consider_length) == F_equal_to) { + if (fl_string_dynamic_compare_string(controller_string_consider_s, cache->action.name_action, controller_string_consider_length) == F_equal_to) { actions->array[actions->used].type = controller_entry_action_type_consider; } - else if (fl_string_dynamic_compare_string(controller_string_failsafe_s, cache->name_action, controller_string_failsafe_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_failsafe_s, cache->action.name_action, controller_string_failsafe_length) == F_equal_to) { actions->array[actions->used].type = controller_entry_action_type_failsafe; } - else if (fl_string_dynamic_compare_string(controller_string_item_s, cache->name_action, controller_string_item_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_item_s, cache->action.name_action, controller_string_item_length) == F_equal_to) { actions->array[actions->used].type = controller_entry_action_type_item; } - else if (fl_string_dynamic_compare_string(controller_string_ready_s, cache->name_action, controller_string_ready_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_ready_s, cache->action.name_action, controller_string_ready_length) == F_equal_to) { actions->array[actions->used].type = controller_entry_action_type_ready; } - else if (fl_string_dynamic_compare_string(controller_string_rule_s, cache->name_action, controller_string_rule_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_rule_s, cache->action.name_action, controller_string_rule_length) == F_equal_to) { actions->array[actions->used].type = controller_entry_action_type_rule; } - else if (fl_string_dynamic_compare_string(controller_string_timeout_s, cache->name_action, controller_string_timeout_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_timeout_s, cache->action.name_action, controller_string_timeout_length) == F_equal_to) { actions->array[actions->used].type = controller_entry_action_type_timeout; } else { if (data.warning.verbosity == f_console_verbosity_debug) { fprintf(data.warning.to.stream, "%s%sUnknown entry item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s); fprintf(data.warning.to.stream, "%s%s", data.warning.context.after->string, data.warning.notable.before->string); - f_print_dynamic(data.warning.to.stream, cache->name_action); + f_print_dynamic(data.warning.to.stream, cache->action.name_action); fprintf(data.warning.to.stream, "%s", data.warning.notable.after->string); fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(data.warning, *cache); + controller_entry_error_print(data.warning, cache->action); } continue; @@ -239,11 +240,11 @@ extern "C" { if (data.error.verbosity != f_console_verbosity_quiet) { fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); fprintf(data.error.to.stream, "%s%sThe entry item action '", 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, cache->name_action.string, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, cache->action.name_action.string, data.error.notable.after->string); fprintf(data.error.to.stream, "%s' requires ", data.error.context.before->string); if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) { - fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, cache->line_action, data.error.notable.after->string); + fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, cache->action.line_action, data.error.notable.after->string); fprintf(data.error.to.stream, "%s or more parameters.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); } else { @@ -540,7 +541,7 @@ 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_t cache) { + 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]); @@ -599,8 +600,8 @@ extern "C" { entry->status = F_known_not; entry->items.used = 0; - cache->line_action = 0; - cache->line_item = 0; + cache->action.line_action = 0; + cache->action.line_item = 0; f_macro_time_spec_t_clear(cache->timestamp); @@ -630,9 +631,9 @@ extern "C" { cache->buffer_file.used = 0; cache->buffer_path.used = 0; - cache->name_file.used = 0; - cache->name_action.used = 0; - cache->name_item.used = 0; + cache->action.name_file.used = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; status = controller_file_load(data, setting, controller_string_entries_s, entry_name, controller_string_entry_s, controller_string_entries_length, controller_string_entry_length, cache); @@ -682,6 +683,10 @@ extern "C" { for (; i < cache->object_items.used; ++i) { + if (setting.signal) { + return F_signal; + } + if (code & 0x2) { code -= 0x2; } @@ -689,8 +694,8 @@ extern "C" { at = 0; range = 0; - cache->line_action = 0; - cache->line_item = 0; + cache->action.line_action = 0; + cache->action.line_item = 0; cache->comments.used = 0; cache->delimits.used = 0; @@ -702,8 +707,8 @@ extern "C" { cache->buffer_path.used = 0; - cache->name_action.used = 0; - cache->name_item.used = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; status = controller_entry_items_increase_by(controller_default_allocation_step, &entry->items); @@ -712,32 +717,32 @@ extern "C" { break; } - status = controller_string_dynamic_partial_append_terminated(cache->buffer_file, cache->object_items.array[i], &cache->name_item); + status = controller_string_dynamic_partial_append_terminated(cache->buffer_file, cache->object_items.array[i], &cache->action.name_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_partial_append_terminated", F_true); break; } - status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->line_item); + status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->action.line_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } - cache->line_item++; + cache->action.line_item++; for (j = (code & 0x1) ? 1 : 0; j < entry->items.used; ++j) { - if (fl_string_dynamic_compare(entry->items.array[j].name, cache->name_item) == F_equal_to) { + if (fl_string_dynamic_compare(entry->items.array[j].name, cache->action.name_item) == F_equal_to) { if (data.warning.verbosity == f_console_verbosity_debug) { fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]); fprintf(data.warning.to.stream, "%s%sIgnoring duplicate entry item '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s); - fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->name_file.string, data.warning.notable.after->string); + fprintf(data.warning.to.stream, "%s%s%s%s", data.warning.context.after->string, data.warning.notable.before->string, cache->action.name_file.string, data.warning.notable.after->string); fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(data.warning, *cache); + controller_entry_error_print(data.warning, cache->action); } code |= 0x2; @@ -749,7 +754,7 @@ extern "C" { range = &cache->content_items.array[i].array[0]; - if (fl_string_dynamic_compare_string(controller_string_main_s, cache->name_item, controller_string_main_length) == F_equal_to) { + if (fl_string_dynamic_compare_string(controller_string_main_s, cache->action.name_item, controller_string_main_length) == F_equal_to) { code |= 0x1; at = 0; @@ -770,9 +775,9 @@ extern "C" { entry->items.used = 2; } - entry->items.array[at].line = cache->line_item; + entry->items.array[at].line = cache->action.line_item; - status = controller_string_dynamic_append_terminated(cache->name_item, &entry->items.array[at].name); + status = controller_string_dynamic_append_terminated(cache->action.name_item, &entry->items.array[at].name); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); @@ -782,7 +787,7 @@ extern "C" { status = controller_entry_actions_read(data, setting, *range, cache, &entry->items.array[at].actions); if (F_status_is_error(status)) { - controller_entry_error_print(data.error, *cache); + controller_entry_error_print(data.error, cache->action); if (F_status_set_fine(status) == F_memory_not) { break; @@ -791,8 +796,8 @@ extern "C" { } // for if (F_status_is_error_not(status)) { - cache->name_action.used = 0; - cache->name_item.used = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; if (!(code & 0x1)) { if (data.error.verbosity != f_console_verbosity_quiet) { @@ -817,6 +822,10 @@ extern "C" { for (j = 0; j < entry->items.array[i].actions.used; ++j) { + if (setting.signal) { + return F_signal; + } + action = &entry->items.array[i].actions.array[j]; // only process actions that don't already have an error. @@ -839,10 +848,10 @@ extern "C" { if (missing & 0x1) { missing |= 0x2; - cache->line_action = action->line; - cache->line_item = entry->items.array[i].line; + cache->action.line_action = action->line; + cache->action.line_item = entry->items.array[i].line; - status = controller_string_dynamic_append_terminated(entry->items.array[i].name, &cache->name_item); + status = controller_string_dynamic_append_terminated(entry->items.array[i].name, &cache->action.name_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true); @@ -855,7 +864,7 @@ extern "C" { fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, action->parameters.array[0].string, data.error.notable.after->string); fprintf(data.error.to.stream, "%s' does not exist.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print(data.error, *cache); + controller_entry_error_print(data.error, cache->action); } action->number = 0; @@ -864,8 +873,8 @@ extern "C" { // @fixme review how entry->status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing). //entry->status = controller_status_simplify(F_found_not); - cache->name_action.used = 0; - cache->name_item.used = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; } else { action->number = k; @@ -885,7 +894,7 @@ extern "C" { } if (F_status_is_error(status)) { - controller_entry_error_print(data.error, *cache); + controller_entry_error_print(data.error, cache->action); entry->status = controller_status_simplify(F_status_set_fine(status)); } diff --git a/level_3/controller/c/private-entry.h b/level_3/controller/c/private-entry.h index f200cfb..40d0988 100644 --- a/level_3/controller/c/private-entry.h +++ b/level_3/controller/c/private-entry.h @@ -113,7 +113,7 @@ extern "C" { * @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_t cache) f_gcc_attribute_visibility_internal; + 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_ /** diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index a6939e3..6b22013 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -2,6 +2,7 @@ #include "private-common.h" #include "private-controller.h" #include "private-rule.h" +#include "private-thread.h" #ifdef __cplusplus extern "C" { @@ -217,7 +218,7 @@ extern "C" { } else { actions->array[actions->used].type = type; - actions->array[actions->used].line = cache->line_action; + actions->array[actions->used].line = cache->action.line_action; actions->array[actions->used].parameters.used = 0; actions->array[actions->used].status = F_known_not; @@ -327,7 +328,7 @@ extern "C" { // "script" types use the entire content as a single string piped to the script, so merge all arguments together. actions->array[actions->used].type = type; - actions->array[actions->used].line = cache->line_action; + actions->array[actions->used].line = cache->action.line_action; actions->array[actions->used].parameters.used = 0; actions->array[actions->used].status = F_known_not; @@ -389,7 +390,7 @@ extern "C" { fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]); fprintf(data.warning.to.stream, "%s%sAction is empty, nothing to do.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.warning, *cache, F_true); + controller_rule_error_print(data.warning, cache->action, F_true); } } @@ -398,7 +399,7 @@ extern "C" { #endif // _di_controller_rule_action_read_ #ifndef _di_controller_rule_error_print_ - void controller_rule_error_print(const fll_error_print_t output, const controller_cache_t cache, const bool item) { + void controller_rule_error_print(const fll_error_print_t output, const controller_cache_action_t cache, const bool item) { if (output.verbosity != f_console_verbosity_quiet) { fprintf(output.to.stream, "%c", f_string_eol_s[0]); @@ -496,7 +497,7 @@ extern "C" { #endif // _di_controller_rule_error_print_need_want_wish_ #ifndef _di_controller_rule_execute_ - f_status_t controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t type, const bool simulate, controller_data_t *data, controller_setting_t *setting) { + f_status_t controller_rule_execute(const f_array_length_t index, const uint8_t type, const bool simulate, controller_thread_t *thread) { f_status_t status = F_none; f_status_t success = F_false; @@ -504,7 +505,7 @@ extern "C" { f_array_length_t j = 0; f_array_length_t k = 0; - controller_rule_t *rule = &setting->rules.array[index]; + controller_rule_t *rule = &thread->setting->rules.array[index]; controller_rule_item_t *item = 0; controller_rule_action_t *action = 0; @@ -516,7 +517,7 @@ extern "C" { f_string_maps_t environment = f_string_maps_t_initialize; const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize; - fl_execute_parameter_t parameter = fl_macro_execute_parameter_t_initialize(0, &environment, &signals, 0); + fl_execute_parameter_t parameter = fl_macro_execute_parameter_t_initialize(fl_execute_parameter_option_threadsafe, &environment, &signals, 0); fl_execute_as_t as = fl_execute_as_t_initialize; if (rule->affinity.used) { @@ -535,7 +536,7 @@ extern "C" { status = fll_control_group_prepare(rule->control_group); if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true); rule->status = F_status_set_error(F_failure); return status; @@ -570,7 +571,7 @@ extern "C" { status = fl_environment_load_names(rule->environment, &environment); if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "fl_environment_load_names", F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "fl_environment_load_names", F_true); rule->status = F_status_set_error(F_failure); return status; @@ -578,12 +579,22 @@ extern "C" { for (i = 0; i < rule->items.used; ++i) { + if (thread->setting->signal) { + status = F_signal; + break; + } + if (rule->items.array[i].type == controller_rule_item_type_setting) continue; item = &rule->items.array[i]; for (j = 0; j < item->actions.used; ++j) { + if (thread->setting->signal) { + status = F_signal; + break; + } + if (item->actions.array[j].type != type) continue; action = &item->actions.array[j]; @@ -597,7 +608,7 @@ extern "C" { parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_foreground(item->type, *action, simulate, 0, action->parameters, 0, ¶meter, &as, data); + status = controller_rule_execute_foreground(item->type, *action, simulate, 0, action->parameters, 0, ¶meter, &as, thread->data); if (status == F_child) { break; @@ -618,7 +629,7 @@ extern "C" { parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_foreground(item->type, *action, simulate, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, ¶meter, &as, data); + status = controller_rule_execute_foreground(item->type, *action, simulate, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, ¶meter, &as, thread->data); if (status == F_child) { break; @@ -638,7 +649,7 @@ extern "C" { parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_pid_with(item->type, *action, simulate, 0, action->parameters, 0, ¶meter, &as, data); + status = controller_rule_execute_pid_with(item->type, *action, simulate, 0, action->parameters, 0, ¶meter, &as, thread->data); if (F_status_is_error(status)) { action->status = F_status_set_error(F_failure); @@ -650,11 +661,11 @@ extern "C" { } else { - if (data->warning.verbosity == f_console_verbosity_debug) { - fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s, data->warning.context.after->string, f_string_eol_s[0]); + if (thread->data->warning.verbosity == f_console_verbosity_debug) { + fprintf(thread->data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(thread->data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", thread->data->warning.context.before->string, thread->data->warning.prefix ? thread->data->warning.prefix : f_string_empty_s, thread->data->warning.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data->warning, cache, F_true); + controller_rule_error_print(thread->data->warning, *thread->cache_action, F_true); } action->status = F_ignore; @@ -674,7 +685,7 @@ extern "C" { f_macro_string_maps_t_delete_simple(environment); - if (status == F_child) { + if (status == F_child || status == F_signal) { return status; } @@ -957,65 +968,65 @@ extern "C" { break; } - status = f_fss_count_lines(cache->buffer_item, cache->range_action.start, &cache->line_action); + status = f_fss_count_lines(cache->buffer_item, cache->range_action.start, &cache->action.line_action); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } - cache->line_action += ++item->line; - cache->name_action.used = 0; + cache->action.line_action += ++item->line; + cache->action.name_action.used = 0; - status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->range_action, &cache->name_action); + status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->range_action, &cache->action.name_action); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); break; } - if (fl_string_dynamic_compare_string(controller_string_create_s, cache->name_action, controller_string_create_length) == F_equal_to) { + if (fl_string_dynamic_compare_string(controller_string_create_s, cache->action.name_action, controller_string_create_length) == F_equal_to) { type = controller_rule_action_type_create; } - else if (fl_string_dynamic_compare_string(controller_string_group_s, cache->name_action, controller_string_group_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_group_s, cache->action.name_action, controller_string_group_length) == F_equal_to) { type = controller_rule_action_type_group; } - else if (fl_string_dynamic_compare_string(controller_string_kill_s, cache->name_action, controller_string_kill_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_kill_s, cache->action.name_action, controller_string_kill_length) == F_equal_to) { type = controller_rule_action_type_kill; } - else if (fl_string_dynamic_compare_string(controller_string_pause_s, cache->name_action, controller_string_pause_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_pause_s, cache->action.name_action, controller_string_pause_length) == F_equal_to) { type = controller_rule_action_type_pause; } - else if (fl_string_dynamic_compare_string(controller_string_restart_s, cache->name_action, controller_string_restart_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_restart_s, cache->action.name_action, controller_string_restart_length) == F_equal_to) { type = controller_rule_action_type_restart; } - else if (fl_string_dynamic_compare_string(controller_string_resume_s, cache->name_action, controller_string_resume_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_resume_s, cache->action.name_action, controller_string_resume_length) == F_equal_to) { type = controller_rule_action_type_resume; } - else if (fl_string_dynamic_compare_string(controller_string_reload_s, cache->name_action, controller_string_reload_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_reload_s, cache->action.name_action, controller_string_reload_length) == F_equal_to) { type = controller_rule_action_type_reload; } - else if (fl_string_dynamic_compare_string(controller_string_start_s, cache->name_action, controller_string_start_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_start_s, cache->action.name_action, controller_string_start_length) == F_equal_to) { type = controller_rule_action_type_start; } - else if (fl_string_dynamic_compare_string(controller_string_stop_s, cache->name_action, controller_string_stop_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_stop_s, cache->action.name_action, controller_string_stop_length) == F_equal_to) { type = controller_rule_action_type_stop; } - else if (fl_string_dynamic_compare_string(controller_string_use_s, cache->name_action, controller_string_use_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_use_s, cache->action.name_action, controller_string_use_length) == F_equal_to) { type = controller_rule_action_type_use; } - else if (fl_string_dynamic_compare_string(controller_string_user_s, cache->name_action, controller_string_user_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_user_s, cache->action.name_action, controller_string_user_length) == F_equal_to) { type = controller_rule_action_type_user; } else { if (data.warning.verbosity == f_console_verbosity_debug) { fprintf(data.warning.to.stream, "%s%sUnknown rule item action '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s); fprintf(data.warning.to.stream, "%s%s", data.warning.context.after->string, data.warning.notable.before->string); - f_print_dynamic(data.warning.to.stream, cache->name_action); + f_print_dynamic(data.warning.to.stream, cache->action.name_action); fprintf(data.warning.to.stream, "%s", data.warning.notable.after->string); fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.warning, *cache, F_true); + controller_rule_error_print(data.warning, cache->action, F_true); } continue; @@ -1027,7 +1038,7 @@ extern "C" { fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); fprintf(data.error.to.stream, "%s%sFSS Extended List is not allowed for the rule item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); - f_print_dynamic(data.error.to.stream, cache->name_action); + f_print_dynamic(data.error.to.stream, cache->action.name_action); fprintf(data.error.to.stream, "%s", data.error.notable.after->string); fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); } @@ -1275,7 +1286,7 @@ 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_data_t *data, controller_setting_t *setting, controller_cache_t *cache) { + f_status_t controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_t *thread) { switch (action) { case controller_rule_action_type_freeze: @@ -1291,48 +1302,48 @@ extern "C" { default: - if (data->error.verbosity != f_console_verbosity_quiet) { - fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data->error.to.stream, "%s%sUnsupported action type '", 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, controller_rule_action_type_name(action), data->error.notable.after->string); - fprintf(data->error.to.stream, "%s' while attempting to execute rule.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fprintf(thread->data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(thread->data->error.to.stream, "%s%sUnsupported action type '", thread->data->error.context.before->string, thread->data->error.prefix ? thread->data->error.prefix : f_string_empty_s); + fprintf(thread->data->error.to.stream, "%s%s%s%s", thread->data->error.context.after->string, thread->data->error.notable.before->string, controller_rule_action_type_name(action), thread->data->error.notable.after->string); + fprintf(thread->data->error.to.stream, "%s' while attempting to execute rule.%s%c", thread->data->error.context.before->string, thread->data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data->error, *cache, F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); } return F_status_set_error(F_parameter); } - if (index >= setting->rules.used) { - fll_error_print(data->error, F_parameter, "controller_rule_process", F_true); - controller_rule_error_print(data->error, *cache, F_true); + if (index >= thread->setting->rules.used) { + fll_error_print(thread->data->error, F_parameter, "controller_rule_process", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); return F_status_set_error(F_parameter); } f_status_t status = F_none; - f_macro_array_lengths_t_increase_by(status, cache->stack, controller_default_allocation_step) + f_macro_array_lengths_t_increase_by(status, (*thread->stack), controller_default_allocation_step) if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_rule_error_print(data->error, *cache, F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); return status; } f_array_length_t i = 0; - for (; i < cache->stack.used; ++i) { + for (; i < thread->stack->used; ++i) { - if (cache->stack.array[i] == index) { - if (data->error.verbosity != f_console_verbosity_quiet) { - fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data->error.to.stream, "%s%sThe rule '", 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->rules.array[i].name.string, data->error.notable.after->string); - fprintf(data->error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); + if (thread->stack->array[i] == index) { + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fprintf(thread->data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(thread->data->error.to.stream, "%s%sThe rule '", thread->data->error.context.before->string, thread->data->error.prefix ? thread->data->error.prefix : f_string_empty_s); + fprintf(thread->data->error.to.stream, "%s%s%s%s", thread->data->error.context.after->string, thread->data->error.notable.before->string, thread->setting->rules.array[i].name.string, thread->data->error.notable.after->string); + fprintf(thread->data->error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", thread->data->error.context.before->string, thread->data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data->error, *cache, F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); } // never continue on recursion errors even in simulate mode. @@ -1340,60 +1351,60 @@ extern "C" { } } - cache->name_action.used = 0; - cache->name_item.used = 0; - cache->name_file.used = 0; + thread->cache_action->name_action.used = 0; + thread->cache_action->name_item.used = 0; + thread->cache_action->name_file.used = 0; - status = f_string_append(controller_string_rules_s, controller_string_rules_length, &cache->name_file); + status = f_string_append(controller_string_rules_s, controller_string_rules_length, &thread->cache_action->name_file); if (F_status_is_error_not(status)) { - status = f_string_append(f_path_separator_s, f_path_separator_length, &cache->name_file); + status = f_string_append(f_path_separator_s, f_path_separator_length, &thread->cache_action->name_file); } if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "f_string_append", F_true); - controller_rule_error_print(data->error, *cache, F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "f_string_append", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); return status; } - status = f_string_dynamic_append(setting->rules.array[index].id, &cache->name_file); + status = f_string_dynamic_append(thread->setting->rules.array[index].id, &thread->cache_action->name_file); if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); - controller_rule_error_print(data->error, *cache, F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); return status; } - status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &cache->name_file); + status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &thread->cache_action->name_file); if (F_status_is_error_not(status)) { - status = f_string_append(controller_string_rule_s, controller_string_rule_length, &cache->name_file); + status = f_string_append(controller_string_rule_s, controller_string_rule_length, &thread->cache_action->name_file); } if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "f_string_append", F_true); - controller_rule_error_print(data->error, *cache, F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "f_string_append", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); return status; } - status = f_string_dynamic_terminate_after(&cache->name_file); + status = f_string_dynamic_terminate_after(&thread->cache_action->name_file); if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); - controller_rule_error_print(data->error, *cache, F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); return status; } - cache->stack.array[cache->stack.used++] = index; + thread->stack->array[thread->stack->used++] = index; - controller_rule_t *rule = &setting->rules.array[index]; + controller_rule_t *rule = &thread->setting->rules.array[index]; - if ((options & controller_rule_option_simulate) && data->parameters[controller_parameter_validate].result == f_console_result_found) { - controller_rule_simulate(*data, index, controller_rule_action_type_start, options, cache, setting); + if ((options & controller_rule_option_simulate) && thread->data->parameters[controller_parameter_validate].result == f_console_result_found) { + controller_rule_simulate(index, controller_rule_action_type_start, options, thread); } { @@ -1416,111 +1427,110 @@ extern "C" { for (i = 0; i < 3; ++i) { for (j = 0; j < dynamics[i]->used; ++j) { - at = controller_rule_find_loaded(*data, *setting, dynamics[i]->array[j]); + at = controller_rule_find_loaded(*thread->data, *thread->setting, dynamics[i]->array[j]); - if (at == setting->rules.used) { + if (at == thread->setting->rules.used) { if (i == 0) { - controller_rule_error_print_need_want_wish(data->error, strings[i], dynamics[i]->array[j].string, "was not found"); + controller_rule_error_print_need_want_wish(thread->data->error, strings[i], dynamics[i]->array[j].string, "was not found"); status = F_status_set_error(F_found_not); - controller_rule_error_print(data->error, *cache, F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); if (!(options & controller_rule_option_simulate)) break; } else { - if (data->warning.verbosity == f_console_verbosity_debug) { - controller_rule_error_print_need_want_wish(data->warning, strings[i], dynamics[i]->array[j].string, "was not found"); - controller_rule_error_print(data->warning, *cache, F_true); + if (thread->data->warning.verbosity == f_console_verbosity_debug) { + controller_rule_error_print_need_want_wish(thread->data->warning, strings[i], dynamics[i]->array[j].string, "was not found"); + controller_rule_error_print(thread->data->warning, *thread->cache_action, F_true); } } } - if (F_status_is_error_not(status) && at < setting->rules.used) { + if (F_status_is_error_not(status) && at < thread->setting->rules.used) { - // @todo: this will also need to support the asynchronous/wait behavior. - //if (setting->rules.array[at].status == F_busy) { ... if wait then block ... } + controller_rule_wait_for(at, thread); // when the status is unknown, then the rule has not been executed, so attempt to execute it. - if (setting->rules.array[at].status == F_known_not) { + if (thread->setting->rules.array[at].status == F_known_not) { - f_macro_array_lengths_t_increase_by(status, cache->stack, controller_default_allocation_step) + f_macro_array_lengths_t_increase_by(status, (*thread->stack), controller_default_allocation_step) if (F_status_is_error(status)) { - fll_error_print(data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_rule_error_print(data->error, *cache, F_true); + fll_error_print(thread->data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); // always exit on memory errors, even in simulate mode. break; } // rule execution will re-use the existing cache, so save the current cache. - const f_array_length_t cache_line_action = cache->line_action; - const f_array_length_t cache_line_item = cache->line_item; + const f_array_length_t cache_line_action = thread->cache_action->line_action; + const f_array_length_t cache_line_item = thread->cache_action->line_item; - const f_string_length_t cache_name_action_used = cache->name_action.used; - const f_string_length_t cache_name_item_used = cache->name_item.used; - const f_string_length_t cache_name_file_used = cache->name_file.used; + const f_string_length_t cache_name_action_used = thread->cache_action->name_action.used; + const f_string_length_t cache_name_item_used = thread->cache_action->name_item.used; + const f_string_length_t cache_name_file_used = thread->cache_action->name_file.used; char cache_name_action[cache_name_action_used]; char cache_name_item[cache_name_item_used]; char cache_name_file[cache_name_file_used]; - memcpy(cache_name_action, cache->name_action.string, cache->name_action.used); - memcpy(cache_name_item, cache->name_item.string, cache->name_item.used); - memcpy(cache_name_file, cache->name_file.string, cache->name_file.used); + memcpy(cache_name_action, thread->cache_action->name_action.string, thread->cache_action->name_action.used); + memcpy(cache_name_item, thread->cache_action->name_item.string, thread->cache_action->name_item.used); + memcpy(cache_name_file, thread->cache_action->name_file.string, thread->cache_action->name_file.used); - // @todo: this should pass or use the asynchronous state. - status = controller_rule_process(at, action, options, data, setting, cache); + // recursive rule processing is to always be synchronous. + status = controller_rule_process(at, action, options, thread); if (status == F_child || status == F_signal) break; // restore cache. - memcpy(cache->name_action.string, cache_name_action, cache_name_action_used); - memcpy(cache->name_item.string, cache_name_item, cache_name_item_used); - memcpy(cache->name_file.string, cache_name_file, cache_name_file_used); + memcpy(thread->cache_action->name_action.string, cache_name_action, cache_name_action_used); + memcpy(thread->cache_action->name_item.string, cache_name_item, cache_name_item_used); + memcpy(thread->cache_action->name_file.string, cache_name_file, cache_name_file_used); - cache->name_action.string[cache_name_action_used] = 0; - cache->name_item.string[cache_name_item_used] = 0; + thread->cache_action->name_action.string[cache_name_action_used] = 0; + thread->cache_action->name_item.string[cache_name_item_used] = 0; - cache->name_action.used = cache_name_action_used; - cache->name_item.used = cache_name_item_used; - cache->name_file.used = cache_name_file_used; + thread->cache_action->name_action.used = cache_name_action_used; + thread->cache_action->name_item.used = cache_name_item_used; + thread->cache_action->name_file.used = cache_name_file_used; - cache->line_action = cache_line_action; - cache->line_item = cache_line_item; + thread->cache_action->line_action = cache_line_action; + thread->cache_action->line_item = cache_line_item; if (F_status_is_error(status)) { if (i == 0 || i == 1 || F_status_set_fine(status) == F_memory_not) { - controller_rule_error_print_need_want_wish(data->error, strings[i], dynamics[i]->array[j].string, "failed during execution"); - controller_rule_error_print(data->error, *cache, F_true); + controller_rule_error_print_need_want_wish(thread->data->error, strings[i], dynamics[i]->array[j].string, "failed during execution"); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) { break; } } else { - if (data->warning.verbosity == f_console_verbosity_debug) { - controller_rule_error_print_need_want_wish(data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution"); - controller_rule_error_print(data->warning, *cache, F_true); + if (thread->data->warning.verbosity == f_console_verbosity_debug) { + controller_rule_error_print_need_want_wish(thread->data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution"); + controller_rule_error_print(thread->data->warning, *thread->cache_action, F_true); } } } } - else if (F_status_is_error(setting->rules.array[at].status)) { + else if (F_status_is_error(thread->setting->rules.array[at].status)) { if (i == 0 || i == 1) { - controller_rule_error_print_need_want_wish(data->error, strings[i], dynamics[i]->array[j].string, "is in a failed state"); + controller_rule_error_print_need_want_wish(thread->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(data->error, *cache, F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); if (!(options & controller_rule_option_simulate)) break; } else { - if (data->warning.verbosity == f_console_verbosity_debug) { - controller_rule_error_print_need_want_wish(data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state"); - controller_rule_error_print(data->warning, *cache, F_true); + if (thread->data->warning.verbosity == f_console_verbosity_debug) { + controller_rule_error_print_need_want_wish(thread->data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state"); + controller_rule_error_print(thread->data->warning, *thread->cache_action, F_true); } } } @@ -1533,6 +1543,10 @@ extern "C" { } // for } + if (!(options & controller_rule_option_wait) && F_status_is_error_not(status)) { + controller_rule_wait_all(thread); + } + if (!(options & controller_rule_option_validate) && F_status_is_error_not(status)) { // find at least one of the requested action when the rule is required. @@ -1554,15 +1568,15 @@ extern "C" { if (missing) { - if (data->error.verbosity != f_console_verbosity_quiet) { - fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data->error.to.stream, "%s%sThe rule '", 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, rule->name.used ? rule->name.string : f_string_empty_s, data->error.notable.after->string); - fprintf(data->error.to.stream, "%s' has no '", data->error.context.before->string); - fprintf(data->error.to.stream, "%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, controller_rule_action_type_name(action).string, data->error.notable.after->string); - fprintf(data->error.to.stream, "%s' action to execute.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fprintf(thread->data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(thread->data->error.to.stream, "%s%sThe rule '", thread->data->error.context.before->string, thread->data->error.prefix ? thread->data->error.prefix : f_string_empty_s); + fprintf(thread->data->error.to.stream, "%s%s%s%s", thread->data->error.context.after->string, thread->data->error.notable.before->string, rule->name.used ? rule->name.string : f_string_empty_s, thread->data->error.notable.after->string); + fprintf(thread->data->error.to.stream, "%s' has no '", thread->data->error.context.before->string); + fprintf(thread->data->error.to.stream, "%s%s%s%s", thread->data->error.context.after->string, thread->data->error.notable.before->string, controller_rule_action_type_name(action).string, thread->data->error.notable.after->string); + fprintf(thread->data->error.to.stream, "%s' action to execute.%s%c", thread->data->error.context.before->string, thread->data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data->error, *cache, F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); } status = F_status_set_error(F_parameter); @@ -1570,10 +1584,10 @@ extern "C" { } if (F_status_is_error_not(status)) { - status = controller_rule_execute(*cache, index, action, options & controller_rule_option_simulate, data, setting); + status = controller_rule_execute(index, action, options & controller_rule_option_simulate, thread); if (F_status_is_error(status)) { - controller_rule_error_print(data->error, *cache, F_true); + controller_rule_error_print(thread->data->error, *thread->cache_action, F_true); } if (status == F_child) { @@ -1583,7 +1597,7 @@ extern "C" { } // remove this rule off the stack. - cache->stack.used--; + thread->stack->used--; if (F_status_is_error(status)) { return status; @@ -1593,14 +1607,68 @@ extern "C" { } #endif // _di_controller_rule_process_ +#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_t *thread) { + + f_thread_mutex_lock(&thread->mutex->asynchronous); + + f_status_t status = controller_asynchronouss_increase(&thread->asynchronouss); + + if (F_status_is_error(status)) { + f_thread_mutex_unlock(&thread->mutex->asynchronous); + return status; + } + + controller_asynchronous_t *asynchronous = &thread->asynchronouss.array[thread->asynchronouss.used++]; + + controller_macro_asynchronous_t_clear((*asynchronous)); + + asynchronous->index = index; + asynchronous->state = controller_asynchronous_state_active; + asynchronous->action = action; + asynchronous->options = options; + asynchronous->thread = (void *) thread; + asynchronous->cache.line_action = thread->cache_action->line_action; + asynchronous->cache.line_item = thread->cache_action->line_item; + + status = f_string_dynamic_append(thread->cache_action->name_action, &asynchronous->cache.name_action); + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_append(thread->cache_action->name_file, &asynchronous->cache.name_file); + } + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_append(thread->cache_action->name_item, &asynchronous->cache.name_item); + } + + if (F_status_is_error_not(status)) { + status = f_thread_create(0, &asynchronous->id, controller_thread_asynchronous, (void *) asynchronous); + } + + if (F_status_is_error(status)) { + controller_macro_asynchronous_t_delete_simple((*asynchronous)); + + thread->asynchronouss.used--; + } + + f_thread_mutex_unlock(&thread->mutex->asynchronous); + + if (F_status_is_error(status)) { + return status; + } + + return F_none; + } +#endif // _di_controller_rule_process_asynchronous_ + #ifndef _di_controller_rule_read_ - f_status_t controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_cache_t *cache, controller_rule_t *rule) { + f_status_t controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_thread_t *thread, controller_cache_t *cache, controller_rule_t *rule) { f_status_t status = F_none; bool for_item = F_true; rule->status = F_known_not; - rule->process = 0; + rule->asynchronous = 0; // @todo: timeouts may be passed from entry, consider to or not to initialize in a more consistent manner. //rule->timeout_kill = 2; @@ -1652,8 +1720,8 @@ extern "C" { rule->items.used = 0; - cache->line_item = 0; - cache->line_action = 0; + cache->action.line_item = 0; + cache->action.line_action = 0; cache->range_action.start = 1; cache->range_action.stop = 0; @@ -1672,9 +1740,9 @@ extern "C" { cache->content_items.used = 0; cache->object_items.used = 0; - cache->name_action.used = 0; - cache->name_file.used = 0; - cache->name_item.used = 0; + cache->action.name_action.used = 0; + cache->action.name_file.used = 0; + cache->action.name_item.used = 0; status = f_string_dynamic_append_nulless(rule_id, &rule->id); @@ -1725,8 +1793,8 @@ extern "C" { for (; i < cache->object_items.used; ++i) { - cache->line_item = 0; - cache->line_action = 0; + cache->action.line_item = 0; + cache->action.line_action = 0; cache->range_action.start = 1; cache->range_action.stop = 0; @@ -1746,48 +1814,48 @@ extern "C" { cache->buffer_item.used = 0; cache->buffer_path.used = 0; - cache->name_action.used = 0; - cache->name_item.used = 0; + cache->action.name_action.used = 0; + cache->action.name_item.used = 0; for_item = F_true; - status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->line_item); + status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->action.line_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } - rule->items.array[rule->items.used].line = ++cache->line_item; + rule->items.array[rule->items.used].line = ++cache->action.line_item; - status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_items.array[i], &cache->name_item); + status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_items.array[i], &cache->action.name_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); break; } - if (fl_string_dynamic_compare_string(controller_string_setting_s, cache->name_item, controller_string_setting_length) == F_equal_to) { + if (fl_string_dynamic_compare_string(controller_string_setting_s, cache->action.name_item, controller_string_setting_length) == F_equal_to) { rule->items.array[rule->items.used].type = 0; } - else if (fl_string_dynamic_compare_string(controller_string_command_s, cache->name_item, controller_string_command_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_command_s, cache->action.name_item, controller_string_command_length) == F_equal_to) { rule->items.array[rule->items.used].type = controller_rule_item_type_command; } - else if (fl_string_dynamic_compare_string(controller_string_script_s, cache->name_item, controller_string_script_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_script_s, cache->action.name_item, controller_string_script_length) == F_equal_to) { rule->items.array[rule->items.used].type = controller_rule_item_type_script; } - else if (fl_string_dynamic_compare_string(controller_string_service_s, cache->name_item, controller_string_service_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_service_s, cache->action.name_item, controller_string_service_length) == F_equal_to) { rule->items.array[rule->items.used].type = controller_rule_item_type_service; } else { if (data.warning.verbosity == f_console_verbosity_debug) { fprintf(data.warning.to.stream, "%s%sUnknown rule item '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s); fprintf(data.warning.to.stream, "%s%s", data.warning.context.after->string, data.warning.notable.before->string); - f_print_dynamic(data.warning.to.stream, cache->name_item); + f_print_dynamic(data.warning.to.stream, cache->action.name_item); fprintf(data.warning.to.stream, "%s", data.warning.notable.after->string); fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.warning, *cache, F_true); + controller_rule_error_print(data.warning, cache->action, F_true); } continue; @@ -1829,7 +1897,7 @@ extern "C" { } if (F_status_is_error(status)) { - controller_rule_error_print(data.error, *cache, for_item); + controller_rule_error_print(data.error, cache->action, for_item); rule->status = controller_status_simplify(F_status_set_fine(status)); return F_false; @@ -1851,7 +1919,7 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fll_fss_extended_read", F_true); - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); return status; } @@ -1866,29 +1934,29 @@ extern "C" { uint8_t type = 0; // save the current name item and line number to restore on return. - const f_array_length_t line_item = cache->line_item; - const f_array_length_t length_name_item = cache->name_item.used; + const f_array_length_t line_item = cache->action.line_item; + const f_array_length_t length_name_item = cache->action.name_item.used; char name_item[length_name_item]; name_item[length_name_item] = 0; - memcpy(name_item, cache->name_item.string, length_name_item); + memcpy(name_item, cache->action.name_item.string, length_name_item); for (; i < cache->content_actions.used; ++i, type = 0) { // name_action is used to store all setting values for a single setting. - cache->name_action.used = 0; + cache->action.name_action.used = 0; // name_item is used to store the setting name. - cache->name_item.used = 0; + cache->action.name_item.used = 0; - status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->object_actions.array[i], &cache->name_item); + status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->object_actions.array[i], &cache->action.name_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); } else { - status = f_string_dynamic_terminate_after(&cache->name_item); + status = f_string_dynamic_terminate_after(&cache->action.name_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); @@ -1906,64 +1974,64 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } - if (fl_string_dynamic_compare_string(controller_string_affinity_s, cache->name_item, controller_string_affinity_length) == F_equal_to) { + if (fl_string_dynamic_compare_string(controller_string_affinity_s, cache->action.name_item, controller_string_affinity_length) == F_equal_to) { type = controller_rule_setting_type_affinity; } - else if (fl_string_dynamic_compare_string(controller_string_capability_s, cache->name_item, controller_string_capability_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_capability_s, cache->action.name_item, controller_string_capability_length) == F_equal_to) { type = controller_rule_setting_type_capability; } - else if (fl_string_dynamic_compare_string(controller_string_control_group_s, cache->name_item, controller_string_control_group_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_control_group_s, cache->action.name_item, controller_string_control_group_length) == F_equal_to) { type = controller_rule_setting_type_control_group; } - else if (fl_string_dynamic_compare_string(controller_string_define_s, cache->name_item, controller_string_define_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_define_s, cache->action.name_item, controller_string_define_length) == F_equal_to) { type = controller_rule_setting_type_define; } - else if (fl_string_dynamic_compare_string(controller_string_environment_s, cache->name_item, controller_string_environment_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_environment_s, cache->action.name_item, controller_string_environment_length) == F_equal_to) { type = controller_rule_setting_type_environment; } - else if (fl_string_dynamic_compare_string(controller_string_group_s, cache->name_item, controller_string_group_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_group_s, cache->action.name_item, controller_string_group_length) == F_equal_to) { type = controller_rule_setting_type_group; } - else if (fl_string_dynamic_compare_string(controller_string_limit_s, cache->name_item, controller_string_limit_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_limit_s, cache->action.name_item, controller_string_limit_length) == F_equal_to) { type = controller_rule_setting_type_limit; } - else if (fl_string_dynamic_compare_string(controller_string_name_s, cache->name_item, controller_string_name_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_name_s, cache->action.name_item, controller_string_name_length) == F_equal_to) { type = controller_rule_setting_type_name; } - else if (fl_string_dynamic_compare_string(controller_string_need_s, cache->name_item, controller_string_need_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_need_s, cache->action.name_item, controller_string_need_length) == F_equal_to) { type = controller_rule_setting_type_need; } - else if (fl_string_dynamic_compare_string(controller_string_nice_s, cache->name_item, controller_string_nice_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_nice_s, cache->action.name_item, controller_string_nice_length) == F_equal_to) { type = controller_rule_setting_type_nice; } - else if (fl_string_dynamic_compare_string(controller_string_parameter_s, cache->name_item, controller_string_parameter_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_parameter_s, cache->action.name_item, controller_string_parameter_length) == F_equal_to) { type = controller_rule_setting_type_parameter; } - else if (fl_string_dynamic_compare_string(controller_string_path_s, cache->name_item, controller_string_path_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_path_s, cache->action.name_item, controller_string_path_length) == F_equal_to) { type = controller_rule_setting_type_path; } - else if (fl_string_dynamic_compare_string(controller_string_scheduler_s, cache->name_item, controller_string_scheduler_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_scheduler_s, cache->action.name_item, controller_string_scheduler_length) == F_equal_to) { type = controller_rule_setting_type_scheduler; } - else if (fl_string_dynamic_compare_string(controller_string_script_s, cache->name_item, controller_string_script_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_script_s, cache->action.name_item, controller_string_script_length) == F_equal_to) { type = controller_rule_setting_type_script; } - else if (fl_string_dynamic_compare_string(controller_string_user_s, cache->name_item, controller_string_user_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_user_s, cache->action.name_item, controller_string_user_length) == F_equal_to) { type = controller_rule_setting_type_user; } - else if (fl_string_dynamic_compare_string(controller_string_want_s, cache->name_item, controller_string_want_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_want_s, cache->action.name_item, controller_string_want_length) == F_equal_to) { type = controller_rule_setting_type_want; } - else if (fl_string_dynamic_compare_string(controller_string_wish_s, cache->name_item, controller_string_wish_length) == F_equal_to) { + else if (fl_string_dynamic_compare_string(controller_string_wish_s, cache->action.name_item, controller_string_wish_length) == F_equal_to) { type = controller_rule_setting_type_wish; } else { @@ -1971,17 +2039,17 @@ extern "C" { fprintf(data.warning.to.stream, "%c", f_string_eol_s[0]); fprintf(data.warning.to.stream, "%s%sUnknown rule setting '", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s); fprintf(data.warning.to.stream, "%s%s", data.warning.context.after->string, data.warning.notable.before->string); - f_print_dynamic(data.warning.to.stream, cache->name_item); + f_print_dynamic(data.warning.to.stream, cache->action.name_item); fprintf(data.warning.to.stream, "%s", data.warning.notable.after->string); fprintf(data.warning.to.stream, "%s'.%s%c", data.warning.context.before->string, data.warning.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.warning, *cache, F_false); + controller_rule_error_print(data.warning, cache->action, F_false); } continue; @@ -1993,12 +2061,12 @@ extern "C" { fprintf(data.warning.to.stream, "%s%sEmpty rule setting.%s%c", data.warning.context.before->string, data.warning.prefix ? data.warning.prefix : f_string_empty_s, data.warning.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.warning, *cache, F_false); + controller_rule_error_print(data.warning, cache->action, F_false); } continue; @@ -2007,13 +2075,13 @@ extern "C" { range2.start = cache->content_actions.array[i].array[0].start; range2.stop = cache->content_actions.array[i].array[cache->content_actions.array[i].used - 1].stop; - status = f_string_dynamic_partial_append_nulless(cache->buffer_item, range2, &cache->name_action); + status = f_string_dynamic_partial_append_nulless(cache->buffer_item, range2, &cache->action.name_action); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); } else { - status = f_string_dynamic_terminate_after(&cache->name_action); + status = f_string_dynamic_terminate_after(&cache->action.name_action); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); @@ -2023,12 +2091,12 @@ extern "C" { if (F_status_is_error(status)) { // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); if (F_status_set_fine(status) == F_memory_not) { status_return = status; @@ -2050,15 +2118,15 @@ extern "C" { if (data.error.verbosity != f_console_verbosity_quiet) { // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); fprintf(data.error.to.stream, "%s%sRule setting requires one or more Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2121,12 +2189,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } status = F_status_set_error(F_valid_not); @@ -2161,15 +2229,15 @@ extern "C" { if (data.error.verbosity != f_console_verbosity_quiet) { // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2201,12 +2269,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -2228,12 +2296,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -2261,12 +2329,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -2283,12 +2351,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires two or more Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2313,12 +2381,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%s'.%s%c", data.error.notable.after->string, data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2378,12 +2446,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -2401,12 +2469,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires three Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2469,17 +2537,17 @@ extern "C" { fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); fprintf(data.error.to.stream, "%s%sUnknown resource limit type '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); - f_print_dynamic(data.error.to.stream, cache->name_action); + f_print_dynamic(data.error.to.stream, cache->action.name_action); fprintf(data.error.to.stream, "%s", data.error.notable.after->string); fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_true); + controller_rule_error_print(data.error, cache->action, F_true); } if (F_status_is_error_not(status_return)) { @@ -2498,12 +2566,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } status = F_status_set_error(F_valid_not); @@ -2531,12 +2599,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -2567,12 +2635,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } status = F_status_set_error(F_valid_not); @@ -2627,12 +2695,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2659,12 +2727,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -2683,12 +2751,12 @@ extern "C" { fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2708,12 +2776,12 @@ extern "C" { setting_value->used = 0; // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } } @@ -2745,12 +2813,12 @@ extern "C" { setting_value->used = 0; // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } } @@ -2767,12 +2835,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires either one or two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2815,12 +2883,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%s'.%s%c", data.error.notable.after->string, data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2864,12 +2932,12 @@ extern "C" { fprintf(data.error.to.stream, " allowed for the designated scheduler.%s%c", data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2905,12 +2973,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -2921,20 +2989,20 @@ extern "C" { } if (type == controller_rule_setting_type_capability) { - cache->buffer_other.used = 0; + cache->action.generic.used = 0; - status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->buffer_other); + status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->action.generic); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); if (F_status_set_fine(status) == F_memory_not) { status_return = status; @@ -2946,18 +3014,18 @@ extern "C" { } } - status = f_string_dynamic_terminate_after(&cache->buffer_other); + status = f_string_dynamic_terminate_after(&cache->action.generic); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); if (F_status_set_fine(status) == F_memory_not) { status_return = status; @@ -2969,7 +3037,7 @@ extern "C" { } } - status = f_capability_from_text(cache->buffer_other.string, &rule->capability); + status = f_capability_from_text(cache->action.generic.string, &rule->capability); if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) { @@ -2977,12 +3045,12 @@ extern "C" { fll_error_print(data.error, F_status_set_fine(status), "f_capability_from_text", F_true); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); status_return = status; break; @@ -2993,12 +3061,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting failed to process the capabilities.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -3030,12 +3098,12 @@ extern "C" { fprintf(data.error.to.stream, "%s are allowed.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -3099,12 +3167,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); if (F_status_is_error_not(status_return)) { status_return = F_status_set_error(status); @@ -3126,12 +3194,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires one or more Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -3162,12 +3230,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -3211,12 +3279,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); if (F_status_is_error_not(status_return)) { status_return = F_status_set_error(status); @@ -3256,12 +3324,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -3293,12 +3361,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -3314,12 +3382,12 @@ extern "C" { fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -3339,12 +3407,12 @@ extern "C" { setting_values->array[setting_values->used].used = 0; // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -3361,12 +3429,12 @@ extern "C" { fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]); // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); } if (F_status_is_error_not(status_return)) { @@ -3401,12 +3469,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -3425,12 +3493,12 @@ extern "C" { } // get the current line number within the settings item. - cache->line_item = line_item; - f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->line_item); + cache->action.line_item = line_item; + f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item); - cache->line_action = ++cache->line_item; + cache->action.line_action = ++cache->action.line_item; - controller_rule_error_print(data.error, *cache, F_false); + controller_rule_error_print(data.error, cache->action, F_false); continue; } @@ -3479,19 +3547,24 @@ extern "C" { } // for // resore the current name item and line number, which there should already be enough allocated space for. - memcpy(cache->name_item.string, name_item, length_name_item); + memcpy(cache->action.name_item.string, name_item, length_name_item); - cache->name_item.string[length_name_item] = 0; - cache->name_item.used = length_name_item; + cache->action.name_item.string[length_name_item] = 0; + cache->action.name_item.used = length_name_item; - cache->line_item = line_item; + cache->action.line_item = line_item; return status_return; } #endif // _di_controller_rule_setting_read_ #ifndef _di_controller_rule_simulate_ - void controller_rule_simulate(const controller_data_t data, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_cache_t *cache, controller_setting_t *setting) { + void controller_rule_simulate(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_t *thread) { + + controller_data_t *data = thread->data; + controller_setting_t *setting = thread->setting; + + f_thread_mutex_lock(&thread->mutex->print); switch (action) { case controller_rule_action_type_kill: @@ -3503,15 +3576,17 @@ extern "C" { default: - if (data.error.verbosity != f_console_verbosity_quiet) { - fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); - fprintf(data.error.to.stream, "%s%sUnsupported action type '", 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, controller_rule_action_type_name(action).string, data.error.notable.after->string); - fprintf(data.error.to.stream, "%s' while attempting to simulate rule execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + if (data->error.verbosity != f_console_verbosity_quiet) { + fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data->error.to.stream, "%s%sUnsupported action type '", 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, controller_rule_action_type_name(action).string, data->error.notable.after->string); + fprintf(data->error.to.stream, "%s' while attempting to simulate rule execution.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(data.error, *cache, F_true); + controller_rule_error_print(data->error, *thread->cache_action, F_true); } + f_thread_mutex_unlock(&thread->mutex->print); + return; } @@ -3536,64 +3611,64 @@ extern "C" { } // for if (missing) { - fprintf(data.output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, "Rule '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, rule->name.used ? rule->name.string : f_string_empty_s, data.context.set.title.after->string); - fprintf(data.output.stream, "' has no '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, controller_rule_action_type_name(action).string, data.context.set.important.after->string); - fprintf(data.output.stream, "' action to execute and would '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, options & controller_rule_option_require ? controller_string_fail_s : controller_string_succeed_s, data.context.set.important.after->string); - fprintf(data.output.stream, "' because it is '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, options & controller_rule_option_require ? controller_string_required_s : controller_string_optional_s, data.context.set.important.after->string); - fprintf(data.output.stream, "'.%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "Rule '"); + fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, rule->name.used ? rule->name.string : f_string_empty_s, data->context.set.title.after->string); + fprintf(data->output.stream, "' has no '"); + fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, controller_rule_action_type_name(action).string, data->context.set.important.after->string); + fprintf(data->output.stream, "' action to execute and would '"); + fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, options & controller_rule_option_require ? controller_string_fail_s : controller_string_succeed_s, data->context.set.important.after->string); + fprintf(data->output.stream, "' because it is '"); + fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, options & controller_rule_option_require ? controller_string_required_s : controller_string_optional_s, data->context.set.important.after->string); + fprintf(data->output.stream, "'.%c", f_string_eol_s[0]); } } - fprintf(data.output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, "Rule %s%s%s {%c", data.context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data.context.set.title.after->string, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_name_s, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_how_s, data.context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous_s, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_wait_s, data.context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no_s, f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "Rule %s%s%s {%c", data->context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data->context.set.title.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_name_s, data->context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_how_s, data->context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous_s, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_wait_s, data->context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no_s, f_string_eol_s[0]); if (f_capability_supported()) { - fprintf(data.output.stream, " %s%s%s ", data.context.set.important.before->string, controller_string_capability_s, data.context.set.important.after->string); + fprintf(data->output.stream, " %s%s%s ", data->context.set.important.before->string, controller_string_capability_s, data->context.set.important.after->string); if (rule->capability) { - cache->buffer_other.used = 0; + thread->cache_action->generic.used = 0; - if (F_status_is_error_not(f_capability_to_text(rule->capability, &cache->buffer_other))) { - fprintf(data.output.stream, "%s", cache->buffer_other.string); + if (F_status_is_error_not(f_capability_to_text(rule->capability, &thread->cache_action->generic))) { + fprintf(data->output.stream, "%s", thread->cache_action->generic.string); } } - fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); } else { - fprintf(data.output.stream, " %s%s%s ", data.context.set.important.before->string, controller_string_capability_s, data.context.set.important.after->string, f_string_eol_s[0]); - fprintf(data.output.stream, "%s(unsupported)%s%c", data.context.set.warning.before->string, data.context.set.warning.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s ", data->context.set.important.before->string, controller_string_capability_s, data->context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, "%s(unsupported)%s%c", data->context.set.warning.before->string, data->context.set.warning.after->string, f_string_eol_s[0]); } - fprintf(data.output.stream, " %s%s%s", data.context.set.important.before->string, controller_string_control_group_s, data.context.set.important.after->string); + fprintf(data->output.stream, " %s%s%s", data->context.set.important.before->string, controller_string_control_group_s, data->context.set.important.after->string); if (rule->has & controller_rule_has_control_group) { - fprintf(data.output.stream, " %s", rule->control_group.as_new ? controller_string_new_s : controller_string_existing_s); + fprintf(data->output.stream, " %s", rule->control_group.as_new ? controller_string_new_s : controller_string_existing_s); for (i = 0; i < rule->control_group.groups.used; ++i) { if (rule->control_group.groups.array[i].used) { - fprintf(data.output.stream, f_string_space_s); - f_print_dynamic(data.output.stream, rule->control_group.groups.array[i]); + fprintf(data->output.stream, f_string_space_s); + f_print_dynamic(data->output.stream, rule->control_group.groups.array[i]); } } // for } - fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s", data.context.set.important.before->string, controller_string_nice_s, data.context.set.important.after->string); + fprintf(data->output.stream, " %s%s%s", data->context.set.important.before->string, controller_string_nice_s, data->context.set.important.after->string); if (rule->has & controller_rule_has_nice) { - fprintf(data.output.stream, " %i", rule->nice); + fprintf(data->output.stream, " %i", rule->nice); } - fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s", data.context.set.important.before->string, controller_string_scheduler_s, data.context.set.important.after->string); + fprintf(data->output.stream, " %s%s%s", data->context.set.important.before->string, controller_string_scheduler_s, data->context.set.important.after->string); if (rule->has & controller_rule_has_scheduler) { f_string_t policy = ""; @@ -3616,112 +3691,112 @@ extern "C" { policy = controller_string_round_robin_s; } - fprintf(data.output.stream, " %s %i", policy, rule->scheduler.priority); + fprintf(data->output.stream, " %s %i", policy, rule->scheduler.priority); } - fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_script_s, data.context.set.important.after->string, rule->script.used ? rule->script.string : f_string_empty_s, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_script_s, data->context.set.important.after->string, rule->script.used ? rule->script.string : f_string_empty_s, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s", data.context.set.important.before->string, controller_string_user_s, data.context.set.important.after->string); + fprintf(data->output.stream, " %s%s%s", data->context.set.important.before->string, controller_string_user_s, data->context.set.important.after->string); if (rule->has & controller_rule_has_user) { - fprintf(data.output.stream, " %i", rule->user); + fprintf(data->output.stream, " %i", rule->user); } - fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_affinity_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_affinity_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->affinity.used; ++i) { - fprintf(data.output.stream, " %i%c", rule->affinity.array[i], f_string_eol_s[0]); + fprintf(data->output.stream, " %i%c", rule->affinity.array[i], f_string_eol_s[0]); } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_define_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_define_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->define.used; ++i) { if (rule->define.array[i].name.used && rule->define.array[i].value.used) { - fprintf(data.output.stream, " %s %s=%s %s%c", rule->define.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->define.array[i].value.string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s %s=%s %s%c", rule->define.array[i].name.string, data->context.set.important.before->string, data->context.set.important.after->string, rule->define.array[i].value.string, f_string_eol_s[0]); } } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_environment_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_environment_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->environment.used; ++i) { if (rule->environment.array[i].used) { - fprintf(data.output.stream, " %s%c", rule->environment.array[i].string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%c", rule->environment.array[i].string, f_string_eol_s[0]); } } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_group_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_group_s, data->context.set.important.after->string, f_string_eol_s[0]); if (rule->has & controller_rule_has_group) { - fprintf(data.output.stream, " %i%c", rule->group, f_string_eol_s[0]); + fprintf(data->output.stream, " %i%c", rule->group, f_string_eol_s[0]); for (i = 0; i < rule->groups.used; ++i) { - fprintf(data.output.stream, " %i%c", rule->groups.array[i], f_string_eol_s[0]); + fprintf(data->output.stream, " %i%c", rule->groups.array[i], f_string_eol_s[0]); } // for } - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_limit_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_limit_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->limits.used; ++i) { - fprintf(data.output.stream, " %s %s=%s %llu %llu%c", controller_rule_setting_limit_type_name(rule->limits.array[i].type).string, data.context.set.important.before->string, data.context.set.important.after->string, rule->limits.array[i].value.rlim_cur, rule->limits.array[i].value.rlim_max, f_string_eol_s[0]); + fprintf(data->output.stream, " %s %s=%s %llu %llu%c", controller_rule_setting_limit_type_name(rule->limits.array[i].type).string, data->context.set.important.before->string, data->context.set.important.after->string, rule->limits.array[i].value.rlim_cur, rule->limits.array[i].value.rlim_max, f_string_eol_s[0]); } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_need_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_need_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->need.used; ++i) { if (rule->need.array[i].used) { - fprintf(data.output.stream, " %s%c", rule->need.array[i].string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%c", rule->need.array[i].string, f_string_eol_s[0]); } } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_parameter_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->parameter.used; ++i) { if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) { - fprintf(data.output.stream, " %s %s=%s %s%c", rule->parameter.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s %s=%s %s%c", rule->parameter.array[i].name.string, data->context.set.important.before->string, data->context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]); } } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_want_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_want_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->want.used; ++i) { if (rule->want.array[i].used) { - fprintf(data.output.stream, " %s%c", rule->want.array[i].string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%c", rule->want.array[i].string, f_string_eol_s[0]); } } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_wish_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_wish_s, data->context.set.important.after->string, f_string_eol_s[0]); for (i = 0; i < rule->wish.used; ++i) { if (rule->wish.array[i].used) { - fprintf(data.output.stream, " %s%c", rule->wish.array[i].string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%c", rule->wish.array[i].string, f_string_eol_s[0]); } } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); if (rule->items.used) { controller_rule_action_t *action = 0; @@ -3735,85 +3810,121 @@ extern "C" { item = &rule->items.array[i]; - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_item_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_item_s, data->context.set.important.after->string, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_type_s, data.context.set.important.after->string, controller_rule_item_type_name(item->type).string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_type_s, data->context.set.important.after->string, controller_rule_item_type_name(item->type).string, f_string_eol_s[0]); for (j = 0; j < item->actions.used; ++j) { action = &item->actions.array[j]; - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_action_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_action_s, data->context.set.important.after->string, f_string_eol_s[0]); - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_type_s, data.context.set.important.after->string, controller_rule_action_type_name(action->type).string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_type_s, data->context.set.important.after->string, controller_rule_action_type_name(action->type).string, f_string_eol_s[0]); if (item->type == controller_rule_item_type_script) { - fprintf(data.output.stream, " %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter_s, data.context.set.important.after->string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_parameter_s, data->context.set.important.after->string, f_string_eol_s[0]); parameter = &action->parameters.array[0]; if (parameter->used) { - fprintf(data.output.stream, " "); + fprintf(data->output.stream, " "); for (k = 0; k < parameter->used; ++k) { - fprintf(data.output.stream, "%c", parameter->string[k]); + fprintf(data->output.stream, "%c", parameter->string[k]); if (parameter->string[k] == f_fss_eol && k + 1 < parameter->used) { - fprintf(data.output.stream, " "); + fprintf(data->output.stream, " "); } } // for - fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data->output.stream, "%c", f_string_eol_s[0]); } - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); } else { for (k = 0; k < action->parameters.used; ++k) { - fprintf(data.output.stream, " %s%s%s %s%c", data.context.set.important.before->string, controller_string_parameter_s, data.context.set.important.after->string, action->parameters.array[k].string, f_string_eol_s[0]); + fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_parameter_s, data->context.set.important.after->string, action->parameters.array[k].string, f_string_eol_s[0]); } // for } - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); } // for - fprintf(data.output.stream, " }%c", f_string_eol_s[0]); + fprintf(data->output.stream, " }%c", f_string_eol_s[0]); } // for } - fprintf(data.output.stream, "}%c", f_string_eol_s[0]); + fprintf(data->output.stream, "}%c", f_string_eol_s[0]); setting->rules.array[index].status = F_complete; + + f_thread_mutex_unlock(&thread->mutex->print); } #endif // _di_controller_rule_simulate_ -#ifndef _di_controller_rules_increase_ - f_status_t controller_rules_increase(controller_rules_t *rules) { +#ifndef _di_controller_rule_wait_all_ + void controller_rule_wait_all(controller_thread_t *thread) { - if (rules->used + 1 > rules->size) { - f_array_length_t size = rules->used + controller_default_allocation_step; + f_array_length_t i = 0; - if (size > f_string_length_t_size) { - if (rules->used + 1 > f_array_length_t_size) { - return F_status_set_error(F_array_too_large); - } + for (; i < thread->asynchronouss.used; ++i) { - size = f_array_length_t_size; + if (!thread->asynchronouss.array[i].state) continue; + + if (thread->asynchronouss.array[i].state != controller_asynchronous_state_joined) { + f_thread_join(thread->asynchronouss.array[i].id, 0); } - const f_status_t status = f_memory_resize(rules->size, size, sizeof(controller_rule_t), (void **) & rules->array); + f_thread_mutex_lock(&thread->mutex->asynchronous); - if (F_status_is_error_not(status)) { - rules->size = size; + if (thread->asynchronouss.array[i].state) { + thread->asynchronouss.array[i].state = 0; + + controller_macro_cache_action_t_clear(thread->asynchronouss.array[i].cache); } - return status; + if (i == thread->asynchronouss.used - 1) { + thread->asynchronouss.used = 0; + } + + f_thread_mutex_unlock(&thread->mutex->asynchronous); + } // for + } +#endif // _di_controller_rule_wait_all_ + +#ifndef _di_controller_rule_wait_for_ + void controller_rule_wait_for(const f_array_length_t index, controller_thread_t *thread) { + + if (index >= thread->setting->rules.used) { + return; } - return F_none; + controller_rule_t *rule = &thread->setting->rules.array[index]; + + if (!rule->asynchronous) { + return; + } + + controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) rule->asynchronous; + + if (asynchronous->state != controller_asynchronous_state_joined) { + f_thread_join(asynchronous->id, 0); + } + + f_thread_mutex_lock(&thread->mutex->asynchronous); + + if (asynchronous->state) { + asynchronous->state = 0; + + controller_macro_cache_action_t_clear(asynchronous->cache); + } + + f_thread_mutex_unlock(&thread->mutex->asynchronous); } -#endif // _di_controller_rules_increase_ +#endif // _di_controller_rule_wait_for_ #ifdef __cplusplus } // extern "C" diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 68d47d5..470744e 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -149,7 +149,7 @@ extern "C" { * @see controller_rule_setting_read() */ #ifndef _di_controller_rule_error_print_ - extern void controller_rule_error_print(const fll_error_print_t output, const controller_cache_t cache, const bool item) f_gcc_attribute_visibility_internal; + extern void controller_rule_error_print(const fll_error_print_t output, const controller_cache_action_t cache, const bool item) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_error_print_ /** @@ -205,8 +205,6 @@ extern "C" { /** * Perform an execution of the given rule. * - * @param cache - * A structure for containing and caching relevant data. * @param index * The position in the setting.rules array representing the rule to execute. * @param type @@ -223,10 +221,8 @@ extern "C" { * @param simulate * If TRUE, then run a simulated action (outputing result and executing an empty script). * If FALSE, perform the real execution. - * @param data - * The program data. - * @param setting - * The controller settings data. + * @param thread + * The thread data. * * @return * F_none on success. @@ -238,7 +234,7 @@ extern "C" { * On failure, the individual status for the rule is set to an appropriate error status. */ #ifndef _di_controller_rule_execute_ - extern f_status_t controller_rule_execute(const controller_cache_t cache, const f_array_length_t index, const uint8_t type, const bool simulate, controller_data_t *data, controller_setting_t *setting) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_execute(const f_array_length_t index, const uint8_t type, const bool simulate, controller_thread_t *thread) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_ /** @@ -496,7 +492,7 @@ extern "C" { #endif // _di_controller_rule_path_ /** - * Process and execute the given rule by the rule id. + * Synchronously process and execute the given rule by the rule id. * * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings. * All dependent rules must be already loaded, this function will not load any rules. @@ -519,14 +515,8 @@ extern "C" { * If no bits set, then operate normally in a synchronous manner. * If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule). * If bit controller_rule_option_asynchronous, then run asynchronously. - * @param data - * The program data. - * @param setting - * The controller settings data. - * @param cache - * A structure for containing and caching relevant data. - * This utilizes cache.stack for recursive executions, no function called by this may therefore safely use cache.stack for any other purpose. - * This utilizes line_action, line_item, name_action, and name_item from cache, but they are backed up before starting and then restored after finishing. + * @param thread + * The thread data. * * @return * F_none on success. @@ -534,10 +524,49 @@ 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_data_t *data, controller_setting_t *setting, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_process(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_t *thread) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_process_ /** + * Asynchronously process and execute the given rule by the rule id. + * + * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings. + * All dependent rules must be already loaded, this function will not load any rules. + * + * 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 index + * Position in the rules array representing the rule to execute + * @param action + * The action to perform based on the action type codes. + * + * Only subset of the action type codes are supported: + * - controller_rule_action_type_kill + * - controller_rule_action_type_reload + * - controller_rule_action_type_restart + * - controller_rule_action_type_start + * - controller_rule_action_type_stop + * @param options + * A number using bits to represent specific boolean options. + * If no bits set, then operate normally in a synchronous manner. + * If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule). + * If bit controller_rule_option_asynchronous, then run asynchronously. + * @param thread + * The thread data. + * + * @return + * F_none on success. + * F_signal on (exit) signal received. + * + * Errors (with error bit) from: controller_asynchronouss_increase(). + * Errors (with error bit) from: f_string_dynamic_append(). + * Errors (with error bit) from: f_thread_create(). + */ +#ifndef _di_controller_rule_process_asynchronous_ + extern f_status_t controller_rule_process_asynchronous(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_process_asynchronous_ + +/** * Read the rule file, extracting all valid items. * * @param data @@ -548,6 +577,8 @@ extern "C" { * 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. * "/etc/controller/rules/example/my.rule" would have a rule id of "example/my". + * @param thread + * The thread data. * @param cache * A structure for containing and caching relevant data. * @param rule @@ -570,7 +601,7 @@ extern "C" { * @see fll_fss_basic_list_read(). */ #ifndef _di_controller_rule_read_ - extern f_status_t controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_read(const controller_data_t data, const controller_setting_t setting, const f_string_static_t rule_id, controller_thread_t *thread, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_read_ /** @@ -619,12 +650,8 @@ extern "C" { * * This automatically sets the rule's status to F_complete. * - * @param data - * The program data. * @param index * The position in the setting.rules array representing the rule to simulate. - * @param cache - * A structure for containing and caching relevant data. * @param action * The action to perform based on the action type codes. * @@ -639,30 +666,34 @@ extern "C" { * If no bits set, then operate normally in a synchronous manner. * If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule). * If bit controller_rule_option_asynchronous, then run asynchronously. - * @param setting - * The controller settings data. + * @param thread + * The thread data. */ #ifndef _di_controller_rule_simulate_ - extern void controller_rule_simulate(const controller_data_t data, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_cache_t *cache, controller_setting_t *setting) f_gcc_attribute_visibility_internal; + extern void controller_rule_simulate(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_t *thread) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_simulate_ /** - * Increase the size of the rules array, but only if necessary. - * - * @param rules - * The rules to resize. - * - * @return - * F_none on success. - * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length. + * Wait until all currently running asynchronous execution threads are complete. * - * Errors (with error bit) from: f_memory_resize(). + * @param thread + * The thread data. + */ +#ifndef _di_controller_rule_wait_all_ + extern void controller_rule_wait_all(controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_wait_all_ + +/** + * Wait until the specific rule is done running, if running asynchronously. * - * @see f_memory_resize() + * @param index + * The index of the rule to wait for. + * @param thread + * The thread data. */ -#ifndef _di_controller_rules_increase_ - extern f_status_t controller_rules_increase(controller_rules_t *rules) f_gcc_attribute_visibility_internal; -#endif // _di_controller_rule_increase_ +#ifndef _di_controller_rule_wait_for_ + extern void controller_rule_wait_for(const f_array_length_t index, controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_wait_for_ #ifdef __cplusplus } // extern "C" diff --git a/level_3/controller/c/private-thread.c b/level_3/controller/c/private-thread.c new file mode 100644 index 0000000..0973ae5 --- /dev/null +++ b/level_3/controller/c/private-thread.c @@ -0,0 +1,300 @@ +#include "controller.h" +#include "private-common.h" +#include "private-controller.h" +#include "private-entry.h" +#include "private-rule.h" +#include "private-thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_thread_asynchronous_ + void * controller_thread_asynchronous(void *arguments) { + + controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) arguments; + controller_thread_t thread = controller_thread_t_initialize; + + { + controller_thread_t *thread_main = (controller_thread_t *) asynchronous->thread; + + f_thread_mutex_lock(&thread_main->setting->rules.array[asynchronous->index].lock); + + thread.cache_main = thread_main->cache_main; + thread.cache_action = &asynchronous->cache; + thread.data = thread_main->data; + thread.mutex = thread_main->mutex; + thread.setting = thread_main->setting; + thread.stack = &asynchronous->stack; + } + + controller_rule_process(asynchronous->index, asynchronous->action, asynchronous->options, &thread); + + f_thread_mutex_unlock(&thread.setting->rules.array[asynchronous->index].lock); + + return 0; + } +#endif // _di_controller_thread_asynchronous_ + +#ifndef _di_controller_thread_asynchronous_cancel_ + void controller_thread_asynchronous_cancel(controller_thread_t *thread) { + + f_thread_mutex_lock(&thread->mutex->asynchronous); + + for (f_array_length_t i = 0; i < thread->asynchronouss.used; ++i) { + + if (!thread->asynchronouss.array[i].state) continue; + + f_thread_cancel(thread->asynchronouss.array[i].id); + f_thread_join(thread->asynchronouss.array[i].id, 0); + + thread->asynchronouss.array[i].state = 0; + + controller_macro_cache_action_t_clear(thread->asynchronouss.array[i].cache); + } // for + + thread->asynchronouss.used = 0; + + f_thread_mutex_unlock(&thread->mutex->asynchronous); + } +#endif // _di_controller_thread_asynchronous_cancel_ + +#ifndef _di_controller_thread_cache_ + void * controller_thread_cache(void *arguments) { + + controller_thread_t *thread = (controller_thread_t *) arguments; + f_array_length_t i = 0; + + for (;;) { + + // @todo depend on a posix mutex condition that will designate when to sleep and perform actions. + // when the condition is on/off, then the program will either sleep until condition is toggled or sleep a given interval. + // when sleeping a given interval, then after each interval expiration, perform process cleanups until there are no asynchronous processes to cleanup. + // once all asynchronous processes are cleaned up, toggle the condition again and wait indefinitely. + sleep(controller_thread_cache_cleanup_interval_long); + + if (f_thread_mutex_lock_try(&thread->mutex->cache) == F_none) { + controller_macro_cache_t_delete_simple((*thread->cache_main)); + controller_macro_cache_action_t_delete_simple((*thread->cache_action)); + + if (f_thread_mutex_lock_try(&thread->mutex->asynchronous) == F_none) { + + for (i = 0; i < thread->asynchronouss.size; ++i) { + + if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) { + f_thread_join(thread->asynchronouss.array[i].id, 0); + thread->asynchronouss.array[i].state = controller_asynchronous_state_joined; + } + + if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) { + controller_macro_cache_action_t_clear(thread->asynchronouss.array[i].cache); + thread->asynchronouss.array[i].state = 0; + } + } // for + + for (i = thread->asynchronouss.size; i; --i) { + if (thread->asynchronouss.array[i - 1].state) break; + + controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]) + } // for + + thread->asynchronouss.used = i; + + if (thread->asynchronouss.used < thread->asynchronouss.size) { + controller_asynchronouss_resize(thread->asynchronouss.used, &thread->asynchronouss); + } + + f_thread_mutex_unlock(&thread->mutex->asynchronous); + } + + f_thread_mutex_unlock(&thread->mutex->cache); + } + } // for + + return 0; + } +#endif // _di_controller_thread_cache_ + +#ifndef _di_controller_thread_control_ + void * controller_thread_control(void *arguments) { + + controller_thread_t *thread = (controller_thread_t *) arguments; + + // @todo + + return 0; + } +#endif // _di_controller_thread_control_ + +#ifndef _di_controller_thread_main_ + f_status_t controller_thread_main(const f_string_static_t entry_name, controller_cache_t *cache, controller_thread_t *thread) { + + f_thread_id_t thread_cache = 0; + f_thread_id_t thread_control = 0; + f_thread_id_t thread_rule = 0; + f_thread_id_t thread_signal = 0; + + f_status_t status = f_thread_create(0, &thread_signal, &controller_thread_signal, (void *) thread); + + if (F_status_is_error_not(status)) { + status = f_thread_create(0, &thread_cache, &controller_thread_cache, (void *) thread); + } + + if (F_status_is_error(status)) { + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(thread->data->error, F_status_set_fine(status), "f_thread_create", F_true); + } + } + else { + if (thread->data->parameters[controller_parameter_daemon].result == f_console_result_found) { + thread->setting->ready = controller_setting_ready_done; + + if (f_file_exists(thread->setting->path_pid.string) == F_true) { + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fprintf(thread->data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(thread->data->error.to.stream, "%s%sThe pid file '", thread->data->error.context.before->string, thread->data->error.prefix ? thread->data->error.prefix : f_string_empty_s); + fprintf(thread->data->error.to.stream, "%s%s%s%s", thread->data->error.context.after->string, thread->data->error.notable.before->string, thread->setting->path_pid.string, thread->data->error.notable.after->string); + fprintf(thread->data->error.to.stream, "%s' must not already exist.%s%c", thread->data->error.context.before->string, thread->data->error.context.after->string, f_string_eol_s[0]); + } + + thread->setting->ready = controller_setting_ready_abort; + status = F_status_set_error(F_available_not); + } + } + else { + f_thread_mutex_lock(&thread->mutex->cache); + + status = controller_entry_read(*thread->data, *thread->setting, entry_name, cache, &thread->setting->entry); + + if (F_status_is_error(status)) { + thread->setting->ready = controller_setting_ready_fail; + } + else if (status != F_signal && status != F_child) { + status = controller_preprocess_entry(cache, thread); + } + + if (F_status_is_error_not(status) && status != F_signal && status != F_child) { + if (thread->data->parameters[controller_parameter_validate].result == f_console_result_none || thread->data->parameters[controller_parameter_test].result == f_console_result_found) { + + if (f_file_exists(thread->setting->path_pid.string) == F_true) { + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fprintf(thread->data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(thread->data->error.to.stream, "%s%sThe pid file '", thread->data->error.context.before->string, thread->data->error.prefix ? thread->data->error.prefix : f_string_empty_s); + fprintf(thread->data->error.to.stream, "%s%s%s%s", thread->data->error.context.after->string, thread->data->error.notable.before->string, thread->setting->path_pid.string, thread->data->error.notable.after->string); + fprintf(thread->data->error.to.stream, "%s' must not already exist.%s%c", thread->data->error.context.before->string, thread->data->error.context.after->string, f_string_eol_s[0]); + } + + thread->setting->ready = controller_setting_ready_fail; + status = F_status_set_error(F_available_not); + } + else { + status = controller_process_entry(cache, thread); + + if (F_status_is_error(status)) { + thread->setting->ready = controller_setting_ready_fail; + } + else if (status == F_signal || status == F_child) { + thread->setting->ready = controller_setting_ready_abort; + } + else { + thread->setting->ready = controller_setting_ready_done; + } + } + } + } + + f_thread_mutex_unlock(&thread->mutex->cache); + } + } + + if (status != F_signal && thread->setting->signal) { + status = F_signal; + } + + // only make the rule and control threads available once any/all pre-processing and is completed. + if (F_status_is_error_not(status) && status != F_signal && status != F_child) { + + controller_rule_wait_all(thread); + + status = f_thread_create(0, &thread_rule, &controller_thread_rule, (void *) thread); + + if (F_status_is_error_not(status)) { + status = f_thread_create(0, &thread_control, &controller_thread_control, (void *) thread); + } + + if (F_status_is_error(status)) { + if (thread->data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(thread->data->error, F_status_set_fine(status), "f_thread_create", F_true); + } + } + } + + if (F_status_is_error_not(status) && status != F_signal && status != F_child) { + + // wait until signal thread exits, which happens on any termination signal. + f_thread_join(thread_signal, 0); + } + else { + f_thread_cancel(thread_signal); + f_thread_join(thread_signal, 0); + } + + controller_thread_asynchronous_cancel(thread); + + f_thread_cancel(thread_cache); + f_thread_cancel(thread_control); + f_thread_cancel(thread_rule); + + f_thread_join(thread_cache, 0); + f_thread_join(thread_control, 0); + f_thread_join(thread_rule, 0); + + if (F_status_is_error(status)) { + return F_status_set_error(F_failure); + } + + if (status == F_signal) { + return F_signal; + } + + return F_none; + } +#endif // _di_controller_thread_main_ + +#ifndef _di_controller_thread_rule_ + void * controller_thread_rule(void *arguments) { + + controller_thread_t *thread = (controller_thread_t *) arguments; + + // @todo + // f_thread_mutex_lock(&thread->mutex->rule); + // f_thread_mutex_unlock(&thread->mutex->rule); + + return 0; + } +#endif // _di_controller_thread_rule_ + +#ifndef _di_controller_thread_signal_ + void * controller_thread_signal(void *arguments) { + + controller_thread_t *thread = (controller_thread_t *) arguments; + + for (int signal = 0; ; ) { + + sigwait(&thread->data->signal.set, &signal); + + if (thread->data->parameters[controller_parameter_interruptable].result == f_console_result_found) { + if (signal == F_signal_interrupt || signal == F_signal_abort || signal == F_signal_quit || signal == F_signal_termination) { + thread->setting->signal = signal; + break; + } + } + } // for + + return 0; + } +#endif // _di_controller_thread_signal_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_3/controller/c/private-thread.h b/level_3/controller/c/private-thread.h new file mode 100644 index 0000000..2e06299 --- /dev/null +++ b/level_3/controller/c/private-thread.h @@ -0,0 +1,121 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.5 + * Licenses: lgplv2.1 + */ +#ifndef _PRIVATE_thread_h +#define _PRIVATE_thread_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Asynchronously execute a process. + * + * @param arguments + * The thread arguments. + * Must be of type controller_asynchronous_t. + * + * @return + * 0, always. + */ +#ifndef _di_controller_thread_asynchronous_ + extern void * controller_thread_asynchronous(void *arguments) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_asynchronous_ + +/** + * Cancel all asynchronous threads. + * + * @param thread + * The thread data. + */ +#ifndef _di_controller_thread_asynchronous_cancel_ + void controller_thread_asynchronous_cancel(controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_asynchronous_cancel_ + +/** + * Thread for periodically clearing cache if cache is not busy. + * + * @param arguments + * The thread arguments. + * Must be of type controller_thread_t. + * + * @return + * 0, always. + */ +#ifndef _di_controller_thread_cache_ + extern void * controller_thread_cache(void *arguments) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_cache_ + +/** + * Thread for handling control requests and responses. + * + * @param arguments + * The thread arguments. + * Must be of type controller_thread_t. + * + * @return + * 0, always. + */ +#ifndef _di_controller_thread_control_ + extern void * controller_thread_control(void *arguments) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_control_ + +/** + * Start all threads, wait on threads, and handle requests. + * + * @param entry_name + * The entry name string. + * @param cache + * The main/global cache to use. + * @param thread + * The thread data. + * + * @return + * F_none on success. + * F_child on child process exiting. + * F_signal on signal received. + * F_failure (with error bit) on any failure. + */ +#ifndef _di_controller_thread_main_ + extern f_status_t controller_thread_main(const f_string_static_t entry_name, controller_cache_t *cache, controller_thread_t *thread) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_main_ + +/** + * Thread for handling loading of rules into memory. + * + * @param arguments + * The thread arguments. + * Must be of type controller_thread_t. + * + * @return + * 0, always. + */ +#ifndef _di_controller_thread_rule_ + extern void * controller_thread_rule(void *arguments) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_rule_ + +/** + * Thread for handling signals/interrupts. + * + * Currently this only handles signals to exist, but may be updated to handle interrupt and hangup signals. + * + * @param arguments + * The thread arguments. + * Must be of type controller_thread_t. + * + * @return + * 0, always. + */ +#ifndef _di_controller_thread_signal_ + extern void * controller_thread_signal(void *arguments) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_signal_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_thread_h diff --git a/level_3/controller/data/build/settings b/level_3/controller/data/build/settings index ce9f015..4824893 100644 --- a/level_3/controller/data/build/settings +++ b/level_3/controller/data/build/settings @@ -22,7 +22,7 @@ build_libraries -lc -lcap build_libraries-individual -lfll_control_group -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfl_color -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_string -lf_thread -lf_type_array -lf_utf build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll -build_sources_library controller.c private-control.c private-controller.c private-entry.c private-rule.c +build_sources_library controller.c private-common.c private-control.c private-controller.c private-entry.c private-rule.c private-thread.c build_sources_program main.c build_sources_headers controller.h build_sources_script diff --git a/level_3/fake/c/main.c b/level_3/fake/c/main.c index 3436e4c..36b02bb 100644 --- a/level_3/fake/c/main.c +++ b/level_3/fake/c/main.c @@ -25,14 +25,17 @@ int main(const unsigned long argc, const f_string_t *argv) { f_signal_set_add(F_signal_interrupt, &data.signal.set); f_signal_set_add(F_signal_quit, &data.signal.set); f_signal_set_add(F_signal_termination, &data.signal.set); - f_signal_mask(SIG_BLOCK, &data.signal.set, 0); - status = f_signal_open(&data.signal); + status = f_signal_mask(SIG_BLOCK, &data.signal.set, 0); - // if there is an error opening a signal descriptor, then do not handle signals. - if (F_status_is_error(status)) { - f_signal_mask(SIG_UNBLOCK, &data.signal.set, 0); - f_signal_close(&data.signal); + if (F_status_is_error_not(status)) { + status = f_signal_open(&data.signal); + + // if there is an error opening a signal descriptor, then do not handle signals. + if (F_status_is_error(status)) { + f_signal_mask(SIG_UNBLOCK, &data.signal.set, 0); + f_signal_close(&data.signal); + } } // @fixme: bad design in POSIX where there is no get umask without setting it. -- 1.8.3.1