From ba8b9bfbb3bd903f8dd922e28d0ece563413f5c8 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 13 Dec 2020 20:36:58 -0600 Subject: [PATCH] Progress: controller program. --- level_3/controller/c/private-common.h | 20 +++++++- level_3/controller/c/private-controller.c | 81 +++++++++++++++++++++++++------ level_3/controller/c/private-entry.c | 33 ++++++++----- level_3/controller/c/private-rule.c | 22 ++++++--- level_3/controller/c/private-rule.h | 12 ++--- 5 files changed, 125 insertions(+), 43 deletions(-) diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index 0508ca4..4d9059c 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -239,6 +239,10 @@ extern "C" { 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_number_unsigned_t timeout_kill; + f_number_unsigned_t timeout_start; + f_number_unsigned_t timeout_stop; + f_time_spec_t timestamp; f_string_dynamic_t id; @@ -262,6 +266,8 @@ extern "C" { F_known_not, \ 0, \ 0, \ + 0, \ + 0, \ f_time_spec_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ @@ -457,9 +463,16 @@ extern "C" { typedef struct { bool interruptable; - bool lock; // @todo: this is intend for mutex write locking of this setting for thread safety, remove this if another approach is used. + 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; + f_number_unsigned_t timeout_kill; + f_number_unsigned_t timeout_start; + f_number_unsigned_t timeout_stop; + + bool failsafe_enabled; + f_array_length_t failsafe_rule_id; + f_string_dynamic_t path_pid; f_string_dynamic_t path_setting; @@ -472,6 +485,11 @@ extern "C" { F_false, \ F_false, \ 0, \ + 3, \ + 3, \ + 3, \ + F_false, \ + 0, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ controller_entry_t_initialize, \ diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index ee07570..b1e3f52 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -539,6 +539,20 @@ extern "C" { return status; } + if (F_status_is_error(actions->array[cache->ats.array[at_j]].status)) { + 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, "' is in a %sfailed%s state, skipping execution.%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]); + } + else { + // @todo check to see if this rule is "required" and if so immediately fail, otherwise report a failure as a warning (normal verbosity, not debug verbosity). + } + + continue; + } + if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) { if (setting->ready == controller_setting_ready_wait) { @@ -625,10 +639,10 @@ extern "C" { } else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_consider || actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) { - status = controller_rules_increase_by(controller_default_allocation_step, &setting->rules); + status = controller_rules_increase(&setting->rules); if (F_status_is_error(status)) { - fll_error_print(data.error, F_status_set_fine(status), "controller_rules_increase_by", F_true); + fll_error_print(data.error, F_status_set_fine(status), "controller_rules_increase", F_true); controller_entry_error_print(data.error, *cache); return status; @@ -715,30 +729,69 @@ extern "C" { } } else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_timeout) { + if (simulate) { + f_string_t code = ""; + + if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) { + code = controller_string_kill; + } + else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_start) { + code = controller_string_start; + } + else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_stop) { + code = controller_string_stop; + } + fprintf(data.output.stream, "%c", f_string_eol_s[0]); fprintf(data.output.stream, "Processing entry item action '"); fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_timeout, data.context.set.title.after->string); fprintf(data.output.stream, "' setting '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, "@todo", data.context.set.important.after->string); + fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, code, data.context.set.important.after->string); fprintf(data.output.stream, "' to '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, "@todo", data.context.set.important.after->string); - fprintf(data.output.stream, "'.%c", f_string_eol_s[0]); + fprintf(data.output.stream, "%s%llu%s", data.context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, data.context.set.important.after->string); + fprintf(data.output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]); } - // @todo set the appropriate timeout value (set the entry actions timeouts which are later used as the initial defaults as the rule timeouts). + if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) { + setting->timeout_kill = actions->array[cache->ats.array[at_j]].number; + } + else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_start) { + setting->timeout_start = actions->array[cache->ats.array[at_j]].number; + } + else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_stop) { + setting->timeout_stop = actions->array[cache->ats.array[at_j]].number; + } } else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_failsafe) { - if (simulate) { - fprintf(data.output.stream, "%c", f_string_eol_s[0]); - fprintf(data.output.stream, "Processing entry item action '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_failsafe, data.context.set.title.after->string); - fprintf(data.output.stream, "' setting value to '"); - fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, "@todo", data.context.set.important.after->string); - fprintf(data.output.stream, "'.%c", f_string_eol_s[0]); + + if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= setting->entry.items.used) { + + // This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors. + if (data.error.verbosity != f_console_verbosity_quiet) { + fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); + fprintf(data.error.to.stream, "%s%sInvalid entry item index ", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); + fprintf(data.error.to.stream, "%s%s%llu%s", data.error.context.after->string, data.error.notable.before->string, actions->array[cache->ats.array[at_j]].number, data.error.notable.after->string); + 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); + + return F_status_is_error(F_critical); } + else { + setting->failsafe_enabled = F_true; + setting->failsafe_rule_id = actions->array[cache->ats.array[at_j]].number; - // @todo set the failsafe rule to this rule id (find the rule and then assign by the rule id and then assign by the array index). + if (simulate) { + fprintf(data.output.stream, "%c", f_string_eol_s[0]); + fprintf(data.output.stream, "Processing entry item action '"); + fprintf(data.output.stream, "%s%s%s", data.context.set.title.before->string, controller_string_failsafe, data.context.set.title.after->string); + fprintf(data.output.stream, "' setting value to '"); + fprintf(data.output.stream, "%s%s%s", data.context.set.important.before->string, setting->entry.items.array[setting->failsafe_rule_id].name.string, data.context.set.important.after->string); + fprintf(data.output.stream, "'.%c", f_string_eol_s[0]); + } + } } } // for diff --git a/level_3/controller/c/private-entry.c b/level_3/controller/c/private-entry.c index 5ef7a96..6b677b6 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -396,13 +396,13 @@ extern "C" { for (j = 2; j < action->parameters.used; ++j) { if (fl_string_dynamic_compare_string(controller_string_asynchronous, action->parameters.array[j], controller_string_asynchronous_length) == F_equal_to) { - // do nothing. + action->code = controller_entry_rule_code_asynchronous; } else if (fl_string_dynamic_compare_string(controller_string_require, action->parameters.array[j], controller_string_require_length) == F_equal_to) { - // do nothing. + action->code = controller_entry_rule_code_require; } else if (fl_string_dynamic_compare_string(controller_string_wait, action->parameters.array[j], controller_string_wait_length) == F_equal_to) { - // do nothing. + action->code = controller_entry_rule_code_wait; } else { if (action->status == F_none) { @@ -428,7 +428,7 @@ extern "C" { } } // for } - else if (action->type == controller_entry_action_type_item) { + else if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) { if (fl_string_dynamic_compare_string(controller_string_main, action->parameters.array[0], controller_string_main_length) == F_equal_to) { action->status = F_status_set_error(F_supported_not); @@ -445,14 +445,15 @@ extern "C" { } } else if (action->type == controller_entry_action_type_timeout) { + if (fl_string_dynamic_compare_string(controller_string_kill, action->parameters.array[0], controller_string_kill_length) == F_equal_to) { - // do nothing + action->code = controller_entry_timeout_code_kill; } else if (fl_string_dynamic_compare_string(controller_string_start, action->parameters.array[0], controller_string_start_length) == F_equal_to) { - // do nothing + action->code = controller_entry_timeout_code_start; } else if (fl_string_dynamic_compare_string(controller_string_stop, action->parameters.array[0], controller_string_stop_length) == F_equal_to) { - // do nothing + action->code = controller_entry_timeout_code_stop; } else { action->status = F_status_set_error(F_supported_not); @@ -804,7 +805,7 @@ extern "C" { if (F_status_is_error(action->status)) continue; if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) { - missing &= 0x1; + missing |= 0x1; for (k = 0; k < entry->items.used; ++k) { @@ -818,7 +819,7 @@ extern "C" { } // for if (missing & 0x1) { - missing &= 0x2; + missing |= 0x2; cache->line_action = action->line; cache->line_item = entry->items.array[i].line; @@ -832,25 +833,33 @@ 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, "The requested entry item '"); + fprintf(data.error.to.stream, "%s%sThe required entry item '", 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, 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); } - entry->status = controller_status_simplify(F_found_not); + action->number = 0; + action->status = controller_status_simplify(F_found_not); + + // @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; } + else { + action->number = k; + } } } // for } // for // the error is already fully printed and the entry status is already assigned, so immediately exit. if (missing & 0x2) { - return entry->status; + // @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). + //return entry->status; } } } diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 4c19ed3..459c07a 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -1876,18 +1876,24 @@ extern "C" { } #endif // _di_controller_rule_simulate_ -#ifndef _di_controller_rules_increase_by_ - f_return_status controller_rules_increase_by(const f_array_length_t amount, controller_rules_t *rules) { +#ifndef _di_controller_rules_increase_ + f_return_status controller_rules_increase(controller_rules_t *rules) { - if (rules->used + amount > rules->size) { - if (rules->used + amount > f_array_length_t_size) { - return F_status_set_error(F_array_too_large); + 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((void **) & rules->array, sizeof(controller_rule_t), rules->size, rules->used + amount); + const f_status_t status = f_memory_resize((void **) & rules->array, sizeof(controller_rule_t), rules->size, size); if (F_status_is_error_not(status)) { - rules->size = rules->used + amount; + rules->size = size; } return status; @@ -1895,7 +1901,7 @@ extern "C" { return F_none; } -#endif // _di_controller_rule_increase_by_ +#endif // _di_controller_rules_increase_ #ifdef __cplusplus } // extern "C" diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 42eba62..6c7545b 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -462,12 +462,8 @@ extern "C" { #endif // _di_controller_rule_simulate_ /** - * Increase the size of the rules array by the specified amount, but only if necessary. + * Increase the size of the rules array, but only if necessary. * - * This only increases size if the current used plus amount is greater than the currently allocated size. - * - * @param amount - * A positive number representing how much to increase the size by. * @param rules * The rules to resize. * @@ -479,9 +475,9 @@ extern "C" { * * @see f_memory_resize() */ -#ifndef _di_controller_rules_increase_by_ - extern f_return_status controller_rules_increase_by(const f_array_length_t amount, controller_rules_t *rules) f_gcc_attribute_visibility_internal; -#endif // _di_controller_rule_increase_by_ +#ifndef _di_controller_rules_increase_ + extern f_return_status controller_rules_increase(controller_rules_t *rules) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_increase_ #ifdef __cplusplus } // extern "C" -- 1.8.3.1