From d8b895cd1bde9168d713c3dea822edaf13c5f92f Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Tue, 30 Mar 2021 23:54:28 -0500 Subject: [PATCH] Progress: controller program. --- level_3/controller/c/private-common.c | 4 - level_3/controller/c/private-common.h | 15 +- level_3/controller/c/private-controller.c | 77 ++++---- level_3/controller/c/private-controller.h | 1 + level_3/controller/c/private-rule.c | 304 +++++++++++++++--------------- level_3/controller/c/private-rule.h | 46 ++--- level_3/controller/c/private-thread.c | 95 +++++----- 7 files changed, 278 insertions(+), 264 deletions(-) diff --git a/level_3/controller/c/private-common.c b/level_3/controller/c/private-common.c index 319f911..335e2c2 100644 --- a/level_3/controller/c/private-common.c +++ b/level_3/controller/c/private-common.c @@ -100,9 +100,6 @@ extern "C" { f_status_t status = f_thread_mutex_create(0, &lock->print); if (F_status_is_error(status)) return status; - status = f_thread_lock_create(0, &lock->entry); - if (F_status_is_error(status)) return status; - status = f_thread_lock_create(0, &lock->process); if (F_status_is_error(status)) return status; @@ -118,7 +115,6 @@ extern "C" { f_thread_mutex_delete(&lock->print); - f_thread_lock_delete(&lock->entry); f_thread_lock_delete(&lock->process); f_thread_lock_delete(&lock->rule); } diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index ebab445..a4a4fc3 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -448,7 +448,6 @@ extern "C" { typedef struct { f_thread_mutex_t print; - f_thread_lock_t entry; f_thread_lock_t process; f_thread_lock_t rule; } controller_lock_t; @@ -457,7 +456,6 @@ extern "C" { f_thread_mutex_t_initialize, \ f_thread_lock_t_initialize, \ f_thread_lock_t_initialize, \ - f_thread_lock_t_initialize, \ } #endif // _di_controller_mutex_t_ @@ -593,6 +591,7 @@ extern "C" { * timeout_kill: The timeout to wait relating to using a kill signal. * timeout_start: The timeout to wait relating to starting a process. * timeout_stop: The timeout to wait relating to stopping a process. + * status: A status associated with the loading of the rule (not the execution of the rule). * has: Bitwise set of "has" codes representing what the Rule has. * nice: The niceness value if the Rule "has" nice. * user: The User ID if the Rule "has" a user. @@ -651,6 +650,8 @@ extern "C" { #define controller_rule_has_user 0x10 typedef struct { + f_status_t status; + f_number_unsigned_t timeout_kill; f_number_unsigned_t timeout_start; f_number_unsigned_t timeout_stop; @@ -686,6 +687,7 @@ extern "C" { } controller_rule_t; #define controller_rule_t_initialize { \ + F_known_not, \ 0, \ 0, \ 0, \ @@ -1047,8 +1049,6 @@ extern "C" { * * This is essentially data shared globally between threads, about threads. * - * As a special case, index 0 of processs is reserved for use the main thread and is not used by any Rule Processes. - * * The "enabled" and "signal" utilize the lock: lock.process. * * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE. @@ -1060,6 +1060,9 @@ extern "C" { * processs: All Rule Process thread data. */ #ifndef _di_controller_thread_t_ + #define controller_thread_cleanup_interval_long 3600 // 1 hour in seconds. + #define controller_thread_cleanup_interval_short 180 // 3 minutes in seconds. + typedef struct { bool enabled; int signal; @@ -1092,10 +1095,6 @@ extern "C" { * thread: All thread related data. */ #ifndef _di_controller_main_t_ - // @todo relocate these under a different ifdef block. - #define controller_thread_cache_cleanup_interval_long 3600 // 1 hour in seconds. - #define controller_thread_cache_cleanup_interval_short 180 // 3 minutes in seconds. - typedef struct { controller_data_t *data; controller_setting_t *setting; diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 8938ca3..cd1e7a3 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -260,7 +260,7 @@ extern "C" { for (f_array_length_t i = 0; i < processs.used; ++i) { if (fl_string_dynamic_compare(alias, processs.array[i].alias_rule) == F_equal_to) { - *at = i; + if (at) *at = i; return F_true; } } // for @@ -696,8 +696,6 @@ extern "C" { f_thread_mutex_unlock(&main.thread->lock.print); } - f_thread_lock_read(&main.thread->lock.entry); - for (;;) { entry_actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions; @@ -719,8 +717,6 @@ extern "C" { if (F_status_is_error(status)) { controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); - f_thread_unlock(&main.thread->lock.entry); - return status; } @@ -771,8 +767,6 @@ extern "C" { f_thread_mutex_unlock(&main.thread->lock.print); } - f_thread_unlock(&main.thread->lock.entry); - return F_status_is_error(F_require); } else if (main.data->warning.verbosity == f_console_verbosity_debug) { @@ -859,11 +853,7 @@ extern "C" { else { controller_perform_ready(main, cache); - if (F_status_is_error(status)) { - f_thread_unlock(&main.thread->lock.entry); - - return status; - } + if (F_status_is_error(status)) return status; } main.setting->ready = controller_setting_ready_yes; @@ -897,8 +887,6 @@ extern "C" { f_thread_mutex_unlock(&main.thread->lock.print); } - f_thread_unlock(&main.thread->lock.entry); - return F_status_is_error(F_critical); } @@ -907,8 +895,6 @@ extern "C" { if (F_status_is_error(status)) { controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main.thread); - f_thread_unlock(&main.thread->lock.entry); - return status; } @@ -932,8 +918,6 @@ extern "C" { if (F_status_is_error(status)) { controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); - f_thread_unlock(&main.thread->lock.entry); - return status; } @@ -962,8 +946,6 @@ extern "C" { if (F_status_is_error(status)) { controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, main.thread); - f_thread_unlock(&main.thread->lock.entry); - return status; } @@ -979,7 +961,9 @@ extern "C" { f_thread_lock_read(&main.thread->lock.rule); - at = controller_rule_find_loaded(alias_rule, main); + status = controller_rule_find(alias_rule, main.setting->rules, &at); + + f_thread_unlock(&main.thread->lock.rule); if (simulate) { f_thread_mutex_lock(&main.thread->lock.print); @@ -993,9 +977,7 @@ extern "C" { } // the rule is not yet loaded, ensure that it is loaded. - if (at == main.setting->rules.used) { - - f_thread_unlock(&main.thread->lock.rule); + if (status != F_true) { // rule execution will re-use the existing cache, so save the current cache. const f_array_length_t cache_line_action = cache->action.line_action; @@ -1054,9 +1036,44 @@ extern "C" { } f_thread_unlock(&main.thread->lock.rule); - } - else { - f_thread_unlock(&main.thread->lock.rule); + + // ensure that a process exists for the added rule. + if (F_status_is_error_not(status)) { + f_thread_lock_read(&main.thread->lock.process); + + if (controller_find_process(alias_rule, main.thread->processs, 0) == F_false) { + + f_thread_unlock(&main.thread->lock.process); + f_thread_lock_write(&main.thread->lock.process); + + status = controller_processs_increase(&main.thread->processs); + + if (F_status_is_error(status)) { + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, main.thread); + } + else { + controller_process_t *process = &main.thread->processs.array[main.thread->processs.used]; + + status = f_string_dynamic_append(alias_rule, &process->alias_rule); + + if (F_status_is_error(status)) { + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, main.thread); + } + else { + status = f_string_dynamic_terminate_after(&process->alias_rule); + + if (F_status_is_error(status)) { + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, main.thread); + } + else { + process->id = main.thread->processs.used++; + } + } + } + } + + f_thread_unlock(&main.thread->lock.process); + } } if (F_status_is_error_not(status) && entry_action->type == controller_entry_action_type_rule) { @@ -1078,7 +1095,7 @@ extern "C" { rule_options |= controller_rule_option_asynchronous; } - status = controller_rule_process_begin(entry_action->code & controller_entry_rule_code_asynchronous, alias_rule, controller_rule_action_type_start, rule_options, stack, main, cache); + status = controller_rule_process_begin(entry_action->code & controller_entry_rule_code_asynchronous, alias_rule, controller_rule_action_type_start, rule_options, stack, main, *cache); if (!simulate || F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal) { break; @@ -1142,8 +1159,6 @@ extern "C" { f_thread_mutex_unlock(&main.thread->lock.print); } - f_thread_unlock(&main.thread->lock.entry); - return F_status_is_error(F_critical); } else { @@ -1206,8 +1221,6 @@ extern "C" { } } // for - f_thread_unlock(&main.thread->lock.entry); - if (status == F_child || status == F_signal) { return status; } diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index 7e59ddd..fda8df9 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -170,6 +170,7 @@ extern "C" { * The array of processes to. * @param at * The location within processs the id was found. + * (optional) Set to NULL to disable. * * @return * F_none if not given a valid id to search. diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 317db16..56ee6ae 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-entry.h" #include "private-thread.h" #ifdef __cplusplus @@ -40,7 +41,7 @@ extern "C" { for (f_array_length_t i = 0; i < rules.used; ++i) { if (fl_string_dynamic_compare(alias, rules.array[i].alias) == F_equal_to) { - *at = i; + if (at) *at = i; return F_true; } } // for @@ -517,7 +518,15 @@ extern "C" { } status = f_capability_copy(source.capability, &destination->capability); - if (F_status_is_error(status)) return status; + + if (F_status_is_error(status)) { + + // F_parameter is returned when source.capability is not used or when destination->capability is 0. + // check to see why the error happens, such that source.capability not being used is not an error. + if (F_status_set_fine(status) != F_parameter || !&destination->capability) { + return status; + } + } status = f_control_group_copy(source.control_group, &destination->control_group); if (F_status_is_error(status)) return status; @@ -697,8 +706,20 @@ extern "C" { } #endif // _di_controller_rule_error_print_need_want_wish_ +#ifndef _di_controller_rule_error_print_rule_not_loaded_ + void controller_rule_error_print_rule_not_loaded(const fll_error_print_t output, const f_string_t alias) { + + if (output.verbosity != f_console_verbosity_quiet) { + fprintf(output.to.stream, "%c", f_string_eol_s[0]); + fprintf(output.to.stream, "%s%sThe rule '", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s); + fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, alias, output.notable.after->string); + fprintf(output.to.stream, "%s' is no longer loaded.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]); + } + } +#endif // _di_controller_rule_error_print_rule_not_loaded_ + #ifndef _di_controller_rule_execute_ - f_status_t controller_rule_execute(const uint8_t type, const uint8_t options, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) { + f_status_t controller_rule_execute(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) { f_status_t status = F_none; f_status_t success = F_false; @@ -707,7 +728,7 @@ extern "C" { f_array_length_t j = 0; f_array_length_t k = 0; - // child processes should receive all signals, without blocking. + // child processes should receive all signals and handle the signals as they see fit. f_signal_how_t signals = f_signal_how_t_initialize; f_signal_set_empty(&signals.block); f_signal_set_fill(&signals.block_not); @@ -718,101 +739,101 @@ extern "C" { controller_execute_set_t execute_set = controller_macro_execute_set_t_initialize(0, &environment, &signals, 0, fl_execute_as_t_initialize); - // when using pointers in threads and calling the exec functions, invalid reads and writes may occure. - // make local copies and have the pointers reference these to avoid invalid reads and writes. + // @todo now that "rule' is a (local) copy, this workaround might no longer be necessary. + // when using pointers in threads and calling the exec functions, invalid reads and writes may occur. + // this problem might be happening due to a compiler optimization/decision, so make local copies and have the pointers reference these to avoid invalid reads and writes. int local_nice; uid_t local_id_user; gid_t local_id_group; - // @todo now that "rule' is a (local) copy, this workaround might no longer be necessary. f_int32s_t local_affinity; f_control_group_t local_control_group; f_int32s_t local_id_groups; f_limit_sets_t local_limits; f_execute_scheduler_t local_scheduler; - if (rule->affinity.used) { - local_affinity = rule->affinity; + if (rule.affinity.used) { + local_affinity = rule.affinity; execute_set.as.affinity = &local_affinity; } - if (rule->capability) { - execute_set.as.capability = rule->capability; + if (rule.capability) { + execute_set.as.capability = rule.capability; } - if (rule->has & controller_rule_has_control_group) { - local_control_group = rule->control_group; + if (rule.has & controller_rule_has_control_group) { + local_control_group = rule.control_group; execute_set.as.control_group = &local_control_group; // make sure all required cgroup directories exist. - if (rule->status == F_known_not) { - status = fll_control_group_prepare(rule->control_group); + if (process->status == F_known_not) { + status = fll_control_group_prepare(rule.control_group); if (F_status_is_error(status)) { controller_error_print(main.data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, main.thread); - rule->status = F_status_set_error(F_failure); + process->status = F_status_set_error(F_failure); return status; } } } - if (rule->has & controller_rule_has_group) { - local_id_group = rule->group; + if (rule.has & controller_rule_has_group) { + local_id_group = rule.group; execute_set.as.id_group = &local_id_group; - if (rule->groups.used) { - local_id_groups = rule->groups; + if (rule.groups.used) { + local_id_groups = rule.groups; execute_set.as.id_groups = &local_id_groups; } } - if (rule->limits.used) { - local_limits = rule->limits; + if (rule.limits.used) { + local_limits = rule.limits; execute_set.as.limits = &local_limits; } - if (rule->has & controller_rule_has_scheduler) { - local_scheduler = rule->scheduler; + if (rule.has & controller_rule_has_scheduler) { + local_scheduler = rule.scheduler; execute_set.as.scheduler = &local_scheduler; } - if (rule->has & controller_rule_has_nice) { - local_nice = rule->nice; + if (rule.has & controller_rule_has_nice) { + local_nice = rule.nice; execute_set.as.nice = &local_nice; } - if (rule->has & controller_rule_has_user) { - local_id_user = rule->user; + if (rule.has & controller_rule_has_user) { + local_id_user = rule.user; execute_set.as.id_user = &local_id_user; } - status = fl_environment_load_names(rule->environment, &environment); + status = fl_environment_load_names(rule.environment, &environment); if (F_status_is_error(status)) { controller_error_print(main.data->error, F_status_set_fine(status), "fl_environment_load_names", F_true, main.thread); - rule->status = F_status_set_error(F_failure); + process->status = F_status_set_error(F_failure); return status; } - for (i = 0; i < rule->items.used; ++i) { + for (i = 0; i < rule.items.used; ++i) { if (main.thread->signal) { status = F_signal; break; } - if (rule->items.array[i].type == controller_rule_item_type_setting) continue; + if (rule.items.array[i].type == controller_rule_item_type_setting) continue; - for (j = 0; j < rule->items.array[i].actions.used; ++j) { + for (j = 0; j < rule.items.array[i].actions.used; ++j) { if (main.thread->signal) { status = F_signal; break; } - if (rule->items.array[i].actions.array[j].type != type) continue; + if (rule.items.array[i].actions.array[j].type != action) continue; execute_set.parameter.data = 0; execute_set.parameter.option = fl_execute_parameter_option_threadsafe; @@ -821,56 +842,56 @@ extern "C" { execute_set.parameter.option |= fl_execute_parameter_option_return; } - if (rule->items.array[i].type == controller_rule_item_type_command) { + if (rule.items.array[i].type == controller_rule_item_type_command) { - if (strchr(rule->items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) { + if (strchr(rule.items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) { execute_set.parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_foreground(rule->items.array[i].type, rule->items.array[i].actions.array[j], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, main, rule); + status = controller_rule_execute_foreground(rule, rule.items.array[i].type, rule.items.array[i].actions.array[j], 0, rule.items.array[i].actions.array[j].parameters, options, main, &execute_set, process); if (status == F_child) break; if (F_status_is_error(status)) { - rule->items.array[i].actions.array[j].status = F_status_set_error(F_failure); + rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure); if (!(options & controller_rule_option_simulate)) break; } success = F_true; } - else if (rule->items.array[i].type == controller_rule_item_type_script) { + else if (rule.items.array[i].type == controller_rule_item_type_script) { - execute_set.parameter.data = &rule->items.array[i].actions.array[j].parameters.array[0]; + execute_set.parameter.data = &rule.items.array[i].actions.array[j].parameters.array[0]; - if (rule->script.used && strchr(rule->script.string, f_path_separator_s[0])) { + if (rule.script.used && strchr(rule.script.string, f_path_separator_s[0])) { execute_set.parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_foreground(rule->items.array[i].type, rule->items.array[i].actions.array[j], rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, options, &execute_set, main, rule); + status = controller_rule_execute_foreground(rule, rule.items.array[i].type, rule.items.array[i].actions.array[j], rule.script.used ? rule.script.string : controller_default_program_script, arguments_none, options, main, &execute_set, process); if (status == F_child) break; if (F_status_is_error(status)) { - rule->items.array[i].actions.array[j].status = F_status_set_error(F_failure); + rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure); if (!(options & controller_rule_option_simulate)) break; } success = F_true; } - else if (rule->items.array[i].type == controller_rule_item_type_service) { + else if (rule.items.array[i].type == controller_rule_item_type_service) { - if (strchr(rule->items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) { + if (strchr(rule.items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) { execute_set.parameter.option |= fl_execute_parameter_option_path; } - status = controller_rule_execute_pid_with(rule->items.array[i].type, rule->items.array[i].actions.array[j], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, main, rule); + status = controller_rule_execute_pid_with(rule, rule.items.array[i].type, rule.items.array[i].actions.array[j], 0, rule.items.array[i].actions.array[j].parameters, options, main, &execute_set, process); if (status == F_child) break; if (F_status_is_error(status)) { - rule->items.array[i].actions.array[j].status = F_status_set_error(F_failure); + rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure); if (!(options & controller_rule_option_simulate)) break; } @@ -885,12 +906,12 @@ extern "C" { fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]); fprintf(main.data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s, main.data->warning.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(main.data->warning, cache->action, F_true); + controller_rule_error_print(main.data->warning, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } - rule->items.array[i].actions.array[j].status = F_ignore; + rule.items.array[i].actions.array[j].status = F_ignore; if (success != F_true) { success = F_ignore; @@ -912,21 +933,21 @@ extern "C" { } if (F_status_is_error(status) || success == F_false) { - rule->status = F_status_set_error(F_failure); + process->status = F_status_set_error(F_failure); } else if (success == F_ignore || success == F_busy) { - rule->status = success; + process->status = success; } else { - rule->status = F_none; + process->status = F_none; } - return rule->status; + return process->status; } #endif // _di_controller_rule_execute_ #ifndef _di_controller_rule_execute_foreground_ - f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) { + f_status_t controller_rule_execute_foreground(const controller_rule_t rule, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) { f_status_t status = F_none; int result = 0; @@ -946,7 +967,7 @@ extern "C" { } // for fprintf(main.data->output.stream, "%s' from '", main.data->context.reset.string); - fprintf(main.data->output.stream, "%s%s%s", main.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, main.data->context.reset.string); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.notable.string, rule.name.used ? rule.name.string : f_string_empty_s, main.data->context.reset.string); fprintf(main.data->output.stream, "%s'.%c", main.data->context.reset.string, f_string_eol_s[0]); f_thread_mutex_unlock(&main.thread->lock.print); @@ -968,14 +989,14 @@ extern "C" { if (status == F_parent) { result = 0; - // assign the child process id to the asynchronous thread to allow for the cancel process to send appropriate termination signals to the child process. - main.thread->asynchronouss.array[main.id].child = id_process; + // assign the child process id to allow for the cancel process to send appropriate termination signals to the child process. + process->child = id_process; // have the parent wait for the child process to finish. waitpid(id_process, &result, WUNTRACED | WCONTINUED); // remove the pid now that waidpid() has returned. - main.thread->asynchronouss.array[main.id].child = 0; + process->child = 0; // this must explicitly check for 0 (as opposed to checking (!result)). if (!WIFEXITED(result)) { @@ -1027,7 +1048,7 @@ extern "C" { #endif // _di_controller_rule_execute_foreground_ #ifndef _di_controller_rule_execute_pid_with_ - f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) { + f_status_t controller_rule_execute_pid_with(const controller_rule_t rule, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) { f_status_t status = F_none; int result = 0; @@ -1056,7 +1077,7 @@ extern "C" { } // for fprintf(main.data->output.stream, "%s' from '", main.data->context.reset.string); - fprintf(main.data->output.stream, "%s%s%s", main.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, main.data->context.reset.string); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.notable.string, rule.name.used ? rule.name.string : f_string_empty_s, main.data->context.reset.string); fprintf(main.data->output.stream, "%s'.%c", main.data->context.reset.string, f_string_eol_s[0]); f_thread_mutex_unlock(&main.thread->lock.print); @@ -1078,14 +1099,14 @@ extern "C" { if (status == F_parent) { result = 0; - // assign the child process id to the asynchronous thread to allow for the cancel process to send appropriate termination signals to the child process. - main.thread->asynchronouss.array[main.id].child = id_process; + // assign the child process id to allow for the cancel process to send appropriate termination signals to the child process. + process->child = id_process; // have the parent wait for the child process to finish. waitpid(id_process, &result, WUNTRACED | WCONTINUED); // remove the pid now that waidpid() has returned. - main.thread->asynchronouss.array[main.id].child = 0; + process->child = 0; // this must explicitly check for 0 (as opposed to checking (!result)). if (!WIFEXITED(result)) { @@ -1549,7 +1570,7 @@ extern "C" { #endif // _di_controller_rule_path_ #ifndef _di_controller_rule_process_ - f_status_t controller_rule_process(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) { + f_status_t controller_rule_process(const uint8_t action, const uint8_t options, const controller_main_t main, controller_rule_t rule, controller_process_t *process) { switch (action) { case controller_rule_action_type_freeze: @@ -1573,7 +1594,7 @@ extern "C" { fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_rule_action_type_name(action), main.data->error.notable.after->string); fprintf(main.data->error.to.stream, "%s' while attempting to execute rule.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -1583,64 +1604,64 @@ extern "C" { f_status_t status = F_none; - cache->action.name_action.used = 0; - cache->action.name_item.used = 0; - cache->action.name_file.used = 0; + process->cache.action.name_action.used = 0; + process->cache.action.name_item.used = 0; + process->cache.action.name_file.used = 0; - status = f_string_append(controller_string_rules_s, controller_string_rules_length, &cache->action.name_file); + status = f_string_append(controller_string_rules_s, controller_string_rules_length, &process->cache.action.name_file); if (F_status_is_error_not(status)) { - status = f_string_append(f_path_separator_s, f_path_separator_length, &cache->action.name_file); + status = f_string_append(f_path_separator_s, f_path_separator_length, &process->cache.action.name_file); } if (F_status_is_error(status)) { f_thread_mutex_lock(&main.thread->lock.print); fll_error_print(main.data->error, F_status_set_fine(status), "f_string_append", F_true); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); return status; } - status = f_string_dynamic_append(rule.alias, &cache->action.name_file); + status = f_string_dynamic_append(rule.alias, &process->cache.action.name_file); if (F_status_is_error(status)) { f_thread_mutex_lock(&main.thread->lock.print); fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); return status; } - status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &cache->action.name_file); + status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &process->cache.action.name_file); if (F_status_is_error_not(status)) { - status = f_string_append(controller_string_rule_s, controller_string_rule_length, &cache->action.name_file); + status = f_string_append(controller_string_rule_s, controller_string_rule_length, &process->cache.action.name_file); } if (F_status_is_error(status)) { f_thread_mutex_lock(&main.thread->lock.print); fll_error_print(main.data->error, F_status_set_fine(status), "f_string_append", F_true); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); return status; } - status = f_string_dynamic_terminate_after(&cache->action.name_file); + status = f_string_dynamic_terminate_after(&process->cache.action.name_file); if (F_status_is_error(status)) { f_thread_mutex_lock(&main.thread->lock.print); fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); @@ -1648,7 +1669,7 @@ extern "C" { } if ((options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) { - controller_rule_simulate(rule, controller_rule_action_type_start, options, main, cache); + controller_rule_simulate(rule, controller_rule_action_type_start, options, main, &process->cache); } f_array_length_t i = 0; @@ -1663,9 +1684,9 @@ extern "C" { controller_process_t *process_other = 0; f_string_dynamics_t * const dynamics[] = { - &rule->need, - &rule->want, - &rule->wish, + &rule.need, + &rule.want, + &rule.wish, }; const f_string_t strings[] = { @@ -1682,7 +1703,7 @@ extern "C" { f_thread_lock_read(&main.thread->lock.rule); - status = controller_find_process(dynamics[i]->array[j], *main.thread->processs, &id_process); + status = controller_find_process(dynamics[i]->array[j], main.thread->processs, &id_process); if (status == F_true) { status = controller_rule_find(dynamics[i]->array[j], main.setting->rules, &id_rule); @@ -1695,7 +1716,7 @@ extern "C" { f_thread_mutex_lock(&main.thread->lock.print); controller_rule_error_print_need_want_wish(main.data->error, strings[i], dynamics[i]->array[j].string, "was not found"); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); @@ -1712,7 +1733,7 @@ extern "C" { f_thread_mutex_lock(&main.thread->lock.print); controller_rule_error_print_need_want_wish(main.data->warning, strings[i], dynamics[i]->array[j].string, "was not found"); - controller_rule_error_print(main.data->warning, cache->action, F_true); + controller_rule_error_print(main.data->warning, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -1722,7 +1743,7 @@ extern "C" { if (status == F_true && id_rule < main.setting->rules.used) { f_thread_lock_read(&main.thread->lock.process); - process_other = &main.thread->processs->array[id_process]; + process_other = &main.thread->processs.array[id_process]; f_thread_lock_read(&process_other->active); f_thread_lock_read(&process_other->lock); @@ -1753,9 +1774,9 @@ extern "C" { rule_other = &main.setting->rules.array[id_rule]; // attempt to (synchronously) execute the rule when the status is unknown (the rule has not yet been run). - if (rule_other->status == F_known_not) { + if (process_other->status == F_known_not) { - status = controller_rule_process_begin(F_false, rule_other->alias, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, process->stack, main, cache); + status = controller_rule_process_begin(F_false, rule_other->alias, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, process->stack, main, process->cache); if (status == F_child || status == F_signal) { f_thread_unlock(&process_other->active); @@ -1769,7 +1790,7 @@ extern "C" { f_thread_mutex_lock(&main.thread->lock.print); controller_rule_error_print_need_want_wish(main.data->error, strings[i], rule_other->alias.string, "failed during execution"); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); @@ -1785,7 +1806,7 @@ extern "C" { f_thread_mutex_lock(&main.thread->lock.print); controller_rule_error_print_need_want_wish(main.data->warning, strings[i], rule_other->alias.string, "failed during execution"); - controller_rule_error_print(main.data->warning, cache->action, F_true); + controller_rule_error_print(main.data->warning, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -1795,14 +1816,14 @@ extern "C" { f_thread_unlock(&process_other->active); - if (F_status_is_error(rule_other->status)) { + if (F_status_is_error(process_other->status)) { if (i == 0 || i == 1) { f_thread_mutex_lock(&main.thread->lock.print); controller_rule_error_print_need_want_wish(main.data->error, strings[i], rule_other->alias.string, "is in a failed state"); status = F_status_set_error(F_found_not); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); @@ -1816,7 +1837,7 @@ extern "C" { f_thread_mutex_lock(&main.thread->lock.print); controller_rule_error_print_need_want_wish(main.data->warning, strings[i], rule_other->alias.string, "is in a failed state"); - controller_rule_error_print(main.data->warning, cache->action, F_true); + controller_rule_error_print(main.data->warning, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -1879,7 +1900,7 @@ extern "C" { fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_rule_action_type_name(action).string, main.data->error.notable.after->string); fprintf(main.data->error.to.stream, "%s' action to execute.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -1889,7 +1910,6 @@ extern "C" { } if (F_status_is_error_not(status)) { - // @todo make sure to update this function. status = controller_rule_execute(rule, action, options, main, process); if (status == F_child) { @@ -1901,7 +1921,7 @@ extern "C" { } if (F_status_is_error(status)) { - controller_rule_error_print_locked(main.data->error, cache->action, F_true, thread); + controller_rule_error_print_locked(main.data->error, process->cache.action, F_true, main.thread); } } } @@ -1915,13 +1935,9 @@ extern "C" { #endif // _di_controller_rule_process_ #ifndef _di_controller_rule_process_begin_ - f_status_t controller_rule_process_begin(const bool asynchronous, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const f_array_lengths_t stack, const controller_main_t main, controller_cache_t *cache) { - - f_thread_lock_read(&main.thread->lock.process); + f_status_t controller_rule_process_begin(const bool asynchronous, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const f_array_lengths_t stack, const controller_main_t main, const controller_cache_t cache) { if (!main.thread->enabled) { - f_thread_mutex_unlock(&main.thread->lock.process); - return F_signal; } @@ -1930,9 +1946,9 @@ extern "C" { controller_process_t *process = 0; { - f_array_length_t id_process = 0; + f_array_length_t at = 0; - if (controller_find_process(alias_rule, *main.thread->processs, &id_process) != F_true) { + if (controller_find_process(alias_rule, main.thread->processs, &at) != F_true) { status = F_status_set_error(F_found_not); } @@ -1941,14 +1957,10 @@ extern "C" { if (F_status_is_error(status)) { if (main.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_main->thread->lock.print); - - fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(main.data->output.stream, "The entry item rule '"); - fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, alias_rule.string, main.data->context.set.title.after->string); - fprintf(main.data->output.stream, "' is no longer loaded.%c", f_string_eol_s[0]); + f_thread_mutex_lock(&main.thread->lock.print); - controller_entry_error_print_cache(main.data->error, cache->action); + controller_rule_error_print_rule_not_loaded(main.data->error, alias_rule.string); + controller_rule_error_print(main.data->error, cache.action, F_false); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -1956,9 +1968,9 @@ extern "C" { return status; } - f_thread_lock_write(&main.thread->processs->array[id_process].lock); + f_thread_lock_write(&main.thread->processs.array[at].lock); - process = &main.thread->processs->array[id_process]; + process = &main.thread->processs.array[at]; // if the process is already running, then there is nothing to do. if (process->state == controller_process_state_active || process->state == controller_process_state_busy) { @@ -1971,16 +1983,13 @@ extern "C" { // the thread is done, so detach/close the thread. if (process->state == controller_process_state_done) { - f_thread_detach(process->id_thread); + f_thread_cancel(process->id_thread); + f_thread_join(process->id_thread, 0); } - process->id = id_process; + process->id = at; } - process->main.data = main.data; - process->main.setting = main.setting; - process->main.thread = main.thread; - process->state = controller_process_state_active; process->action = action; process->options = options; @@ -2000,15 +2009,18 @@ extern "C" { process->cache.buffer_file.used = 0; process->cache.buffer_item.used = 0; process->cache.buffer_path.used = 0; - process->cache.action.used = 0; - process->cache.line_action = process_data.thread->cache_action->line_action; - process->cache.line_item = process_data.thread->cache_action->line_item; + process->cache.action.line_action = cache.action.line_action; + process->cache.action.line_item = cache.action.line_item; + process->cache.action.name_action.used = 0; + process->cache.action.name_file.used = 0; + process->cache.action.name_item.used = 0; + process->cache.action.generic.used = 0; process->stack.used = 0; - process->main_data = (void *) &main->data; - process->main_setting = (void *) &main->setting; - process->main_thread = (void *) &main->thread; + process->main_data = (void *) main.data; + process->main_setting = (void *) main.setting; + process->main_thread = (void *) main.thread; if (F_status_is_error_not(status) && stack.used) { if (process->stack.used < stack.used) { @@ -2016,7 +2028,7 @@ extern "C" { } if (F_status_is_error(status)) { - controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_type_array_lengths_resize", F_true, process_data.thread); + controller_entry_error_print(main.data->error, cache.action, F_status_set_fine(status), "f_type_array_lengths_resize", F_true, main.thread); } else { for (f_array_length_t i = 0; i < stack.used; ++i) { @@ -2026,17 +2038,17 @@ extern "C" { } if (F_status_is_error_not(status)) { - status = f_string_dynamic_append(process_data.thread->cache_action.name_action, &process->cache.action.name_action); + status = f_string_dynamic_append(cache.action.name_action, &process->cache.action.name_action); if (F_status_is_error_not(status)) { - status = f_string_dynamic_append(process_data.thread->cache_action.name_file, &process->cache.action.name_file); + status = f_string_dynamic_append(cache.action.name_file, &process->cache.action.name_file); } if (F_status_is_error_not(status)) { - status = f_string_dynamic_append(process_data.thread->cache_action.name_item, &process->cache.action.name_item); + status = f_string_dynamic_append(cache.action.name_item, &process->cache.action.name_item); } else { - controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, process_data.thread); + controller_entry_error_print(main.data->error, cache.action, F_status_set_fine(status), "f_string_dynamic_append", F_true, main.thread); } } @@ -2047,7 +2059,7 @@ extern "C" { status = f_thread_create(0, &process->id_thread, controller_thread_process, (void *) &process); if (F_status_is_error(status)) { - controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_thread_create", F_true, process_data.thread); + controller_entry_error_print(main.data->error, cache.action, F_status_set_fine(status), "f_thread_create", F_true, main.thread); } } else { @@ -2070,18 +2082,14 @@ extern "C" { f_thread_lock_read(&process->lock); - controller_main_t main = controller_macro_main_t_initialize((controller_data_t *) process->main_data, (controller_setting_t *) process->main_setting(controller_thread_t *) process->main_thread); - - f_thread_lock_read(&main.thread->lock.process); + controller_main_t main = controller_macro_main_t_initialize((controller_data_t *) process->main_data, (controller_setting_t *) process->main_setting, (controller_thread_t *) process->main_thread); if (!main.thread->enabled) { f_thread_unlock(&process->lock); - f_thread_unlock(&main.thread->lock.process); return F_signal; } - f_thread_unlock(&main.thread->lock.process); f_thread_lock_read(&process->active); f_thread_mutex_lock(&process->running); @@ -2098,7 +2106,7 @@ extern "C" { f_thread_unlock(&main.thread->lock.rule); if (F_status_is_error(status)) { - controller_entry_error_print(main.data->error, process->cache->action, F_status_set_fine(status), "controller_rule_copy", F_true, main.thread); + controller_entry_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "controller_rule_copy", F_true, main.thread); } else { for (f_array_length_t i = 0; i < process->stack.used; ++i) { @@ -2112,7 +2120,7 @@ extern "C" { fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, process->alias_rule.string, main.data->error.notable.after->string); fprintf(main.data->error.to.stream, "%s' is already on the execution dependency stack, this recursion is prohibited.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_rule_error_print(main.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, process->cache.action, F_true); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -2131,7 +2139,7 @@ extern "C" { status = f_type_array_lengths_increase(&process->stack); if (F_status_is_error(status)) { - controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_type_array_lengths_increase", F_true, process_data.thread); + controller_entry_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "f_type_array_lengths_increase", F_true, main.thread); } else { process->stack.array[process->stack.used++] = id_rule; @@ -2143,12 +2151,14 @@ extern "C" { } if (F_status_is_error_not(status)) { - status = controller_rule_process(rule, controller_rule_action_type_start, rule_options, main, process); + const uint8_t rule_options = asynchronous ? controller_rule_option_asynchronous : 0; + + status = controller_rule_process(controller_rule_action_type_start, rule_options, main, rule, process); if (F_status_is_error(status)) { f_thread_mutex_lock(&main.thread->lock.print); - controller_entry_error_print_cache(main.data->error, process->cache->action); + controller_entry_error_print_cache(main.data->error, process->cache.action); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -2162,12 +2172,8 @@ extern "C" { if (main.data->error.verbosity != f_console_verbosity_quiet) { f_thread_mutex_lock(&main.thread->lock.print); - fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(main.data->output.stream, "The entry item rule '"); - fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, process->alias_rule.string, main.data->context.set.title.after->string); - fprintf(main.data->output.stream, "' is no longer loaded.%c", f_string_eol_s[0]); - - controller_entry_error_print_cache(main.data->error, process->cache->action); + controller_rule_error_print_rule_not_loaded(main.data->error, process->alias_rule.string); + controller_rule_error_print(main.data->error, process->cache.action, F_false); f_thread_mutex_unlock(&main.thread->lock.print); } @@ -2177,10 +2183,10 @@ extern "C" { f_thread_lock_write(&process->lock); if (asynchronous) { - process->state = controller_asynchronous_state_done; + process->state = controller_process_state_done; } else { - process->state = controller_asynchronous_state_idle; + process->state = controller_process_state_idle; } --process->stack.used; @@ -4379,8 +4385,6 @@ extern "C" { fprintf(data->output.stream, "}%c", f_string_eol_s[0]); - main.setting->rules.array[index].status = F_complete; - f_thread_mutex_unlock(&main.thread->lock.print); } #endif // _di_controller_rule_simulate_ diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 49fd2d5..2aacd7a 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -35,6 +35,7 @@ extern "C" { * The rules to search through. * @param at * The index the rule was found at. + * (optional) Set to NULL to disable. * * @return * F_none on success, but the id.used is 0. @@ -280,7 +281,9 @@ extern "C" { /** * Perform an execution of the given rule. * - * @param type + * @param rule + * The rule being executed. + * @param action * The action to perform based on the action type codes. * * Only subset of the action type codes are supported: @@ -296,10 +299,8 @@ extern "C" { * 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). * @param main * The main data. - * @param cache - * A structure for containing and caching relevant data. - * @param rule - * The rule to process. + * @param process + * The process data for processing this rule. * * @return * F_none on success. @@ -311,12 +312,14 @@ 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 uint8_t type, const uint8_t options, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_execute(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_ /** * Perform an execution of the given rule in the foreground. * + * @param rule + * The rule being executed. * @param type * The item type code. * @param action @@ -335,12 +338,12 @@ extern "C" { * @param options * A number using bits to represent specific boolean options. * 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). - * @param execute_set - * The execute parameter and as settings. * @param main * The main data. - * @param rule - * The rule to process. + * @param execute_set + * The execute parameter and as settings. + * @param process + * The process data for processing this rule. * * @return * F_none on success. @@ -352,7 +355,7 @@ extern "C" { * @see fll_execute_program() */ #ifndef _di_controller_rule_execute_foreground_ - extern f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_execute_foreground(const controller_rule_t rule, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_foreground_ /** @@ -361,6 +364,8 @@ extern "C" { * When this is synchronous, this will wait for the PID file to be generated before continuing. * When this is asynchronous, this will continue on adding the rule id and action to the asynchronous list. * + * @param rule + * The rule being executed. * @param type * The item type code. * @param action @@ -379,13 +384,12 @@ extern "C" { * @param options * A number using bits to represent specific boolean options. * 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). - * @param execute_set - * The execute parameter and as settings. * @param main * The main data. - * @param asynchronous - * Holds the current asynchronous thread information if this is being run from within one. - * Set to NULL when this is not being called from within an asynchronous thread. + * @param execute_set + * The execute parameter and as settings. + * @param process + * The process data for processing this rule. * * @return * F_none on success. @@ -398,7 +402,7 @@ extern "C" { * @see fll_execute_program() */ #ifndef _di_controller_rule_execute_pid_with_ - extern f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_execute_pid_with(const controller_rule_t rule, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_pid_with_ /** @@ -550,8 +554,6 @@ extern "C" { * @fixme recursion is no longer happening is it? * This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array. * - * @param rule - * The rule information at the time the rule process started. * @param action * The action to perform based on the action type codes. * @@ -568,6 +570,8 @@ extern "C" { * If bit controller_rule_option_asynchronous, then run asynchronously. * @param main * The main data. + * @param rule + * The rule information at the time the rule process started. * @param process * The process data for processing this rule. * @@ -577,7 +581,7 @@ extern "C" { * F_signal on (exit) signal received. */ #ifndef _di_controller_rule_process_ - extern f_status_t controller_rule_process(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_process(const uint8_t action, const uint8_t options, const controller_main_t main, controller_rule_t rule, controller_process_t *process) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_process_ /** @@ -619,7 +623,7 @@ extern "C" { * @see f_thread_create() */ #ifndef _di_controller_rule_process_begin_ - extern f_status_t controller_rule_process_begin(const bool asynchronous, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const f_array_lengths_t stack, const controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_process_begin(const bool asynchronous, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const f_array_lengths_t stack, const controller_main_t main, const controller_cache_t cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_process_begin_ /** diff --git a/level_3/controller/c/private-thread.c b/level_3/controller/c/private-thread.c index 81675f3..652c7ec 100644 --- a/level_3/controller/c/private-thread.c +++ b/level_3/controller/c/private-thread.c @@ -14,19 +14,18 @@ extern "C" { const controller_main_t *main = (controller_main_t *) arguments; - const unsigned int interval = main->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cache_cleanup_interval_short : controller_thread_cache_cleanup_interval_long; + const unsigned int interval = main->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cleanup_interval_short : controller_thread_cleanup_interval_long; while (main->thread->enabled) { sleep(interval); - if (f_thread_lock_write_try(&main->thread->lock.process) == F_none) { + if (main->thread->enabled && f_thread_lock_write_try(&main->thread->lock.process) == F_none) { controller_process_t *process = 0; - // index 0 is reserved for "main thread". - f_array_length_t i = 1; + f_array_length_t i = 0; - for (; j < main->thread->processs.used; ++i) { + for (; i < main->thread->processs.used && main->thread->enabled; ++i) { process = &main->thread->processs.array[i]; @@ -60,41 +59,43 @@ extern "C" { f_thread_unlock(&process->lock); } // for - for (i = main->thread->processs.used - 1; main->thread->processs.used; --i, --main->thread->processs.used) { + if (main->thread->processs.used) { + for (i = main->thread->processs.used - 1; main->thread->processs.used && main->thread->enabled; --i) { - process = &main->thread->processs.array[i]; + process = &main->thread->processs.array[i]; - if (f_thread_lock_write_try(&process->active) != F_none) { - break; - } + if (f_thread_lock_write_try(&process->active) != F_none) { + break; + } - if (f_thread_lock_write_try(&process->lock) != F_none) { - f_thread_unlock(&process->active); + if (f_thread_lock_write_try(&process->lock) != F_none) { + f_thread_unlock(&process->active); - break; - } + break; + } - if (process->state == controller_process_state_active || process->state == controller_process_state_busy) { - f_thread_unlock(&process->active); - f_thread_unlock(&process->lock); + if (process->state == controller_process_state_active || process->state == controller_process_state_busy) { + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); - break; - } + break; + } - if (process->state == controller_process_state_done) { - f_thread_detach(process->id_thread); - process->state = controller_process_state_idle; - } + if (process->state == controller_process_state_done) { + f_thread_detach(process->id_thread); + process->state = controller_process_state_idle; + } - // deallocate dynamic portions of the structure that are only ever needed while the process is running. - controller_cache_delete_simple(&process->cache); - f_type_array_lengths_resize(0, &process->stack); + // deallocate dynamic portions of the structure that are only ever needed while the rule is being processed. + controller_cache_delete_simple(&process->cache); + f_type_array_lengths_resize(0, &process->stack); - --main->thread->processs.used; + --main->thread->processs.used; - f_thread_unlock(&process->active); - f_thread_unlock(&process->lock); - } // for + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); + } // for + } f_thread_unlock(&main->thread->lock.process); } @@ -141,13 +142,14 @@ extern "C" { if (F_status_is_error_not(status)) { status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &main); + } + if (F_status_is_error(status)) { if (data->error.verbosity != f_console_verbosity_quiet) { controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread); } } - - if (F_status_is_error_not(status)) { + else { if (data->parameters[controller_parameter_daemon].result == f_console_result_found) { setting->ready = controller_setting_ready_done; @@ -170,17 +172,15 @@ extern "C" { } } else { + controller_cache_t cache = controller_cache_t_initialize; - // index 0 is reserved for running the main thread cache. - thread.processs.used = 1; - - status = controller_entry_read(entry_name, main, &thread.processs.array[0].cache); + status = controller_entry_read(entry_name, main, &cache); if (F_status_is_error(status)) { setting->ready = controller_setting_ready_fail; } else if (status != F_signal && status != F_child) { - status = controller_preprocess_entry(main, &thread.processs.array[0].cache); + status = controller_preprocess_entry(main, &cache); } if (F_status_is_error_not(status) && status != F_signal && status != F_child) { @@ -204,7 +204,7 @@ extern "C" { status = F_status_set_error(F_available_not); } else { - status = controller_process_entry(main, &thread.processs.array[0].cache); + status = controller_process_entry(main, &cache); if (F_status_is_error(status)) { setting->ready = controller_setting_ready_fail; @@ -219,6 +219,8 @@ extern "C" { } } + controller_cache_delete_simple(&cache); + if (status == F_child) { controller_thread_delete_simple(&thread); @@ -227,7 +229,7 @@ extern "C" { } } - if (status != F_signal && setting->signal) { + if (status != F_signal && thread.signal) { status = F_signal; } @@ -257,7 +259,6 @@ extern "C" { return F_child; } - // @todo consider f_thread_detach() over f_thread_join() when exiting. if (F_status_is_error_not(status) && status != F_signal && (data->parameters[controller_parameter_validate].result == f_console_result_none || data->parameters[controller_parameter_test].result == f_console_result_found)) { // wait until signal thread exits, which happens on any termination signal. @@ -275,8 +276,8 @@ extern "C" { f_thread_cancel(thread.id_cleanup); f_thread_cancel(thread.id_control); - f_thread_detach(thread.id_cleanup); - f_thread_detach(thread.id_control); + f_thread_join(thread.id_cleanup, 0); + f_thread_join(thread.id_control, 0); controller_thread_delete_simple(&thread); @@ -322,8 +323,7 @@ extern "C" { //pid_t[main.thread->processs.used] pids; //memset(&pids, 0, sizeof(pid_t) * main.thread->processs.used); - // index 0 is reserved for running the main thread cache. - for (f_array_length_t i = 1; i < main.thread->processs.used; ++i) { + for (f_array_length_t i = 0; i < main.thread->processs.used; ++i) { process = &main.thread->processs.array[i]; @@ -338,12 +338,9 @@ extern "C" { f_signal_send(F_signal_quit, process->child); } - if (process->state == controller_process_state_active || process->state == controller_process_state_busy) { + if (process->state == controller_process_state_active || process->state == controller_process_state_busy || process->state == controller_process_state_done) { f_thread_cancel(process->id_thread); - f_thread_detach(process->id_thread); - } - else if (process->state == controller_process_state_done) { - f_thread_detach(process->id_thread); + f_thread_join(process->id_thread, 0); } f_thread_unlock(&process->lock); -- 1.8.3.1