From fe54476f40f4cc7f76c247f395230668dbacfcba Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 28 Mar 2021 20:34:45 -0500 Subject: [PATCH] Progress: controller program. --- level_3/controller/c/private-common.c | 134 ++-- level_3/controller/c/private-common.h | 671 ++++++----------- level_3/controller/c/private-controller.c | 601 ++++++++------- level_3/controller/c/private-controller.h | 30 +- level_3/controller/c/private-entry.c | 296 ++++---- level_3/controller/c/private-entry.h | 14 +- level_3/controller/c/private-rule.c | 1145 +++++++++++++++-------------- level_3/controller/c/private-rule.h | 187 +++-- level_3/controller/c/private-thread.c | 354 +++++---- level_3/controller/c/private-thread.h | 52 +- 10 files changed, 1659 insertions(+), 1825 deletions(-) diff --git a/level_3/controller/c/private-common.c b/level_3/controller/c/private-common.c index 4a5e6ae..319f911 100644 --- a/level_3/controller/c/private-common.c +++ b/level_3/controller/c/private-common.c @@ -5,59 +5,6 @@ extern "C" { #endif -#ifndef _di_controller_asynchronous_delete_simple_ - void controller_asynchronous_delete_simple(controller_asynchronous_t *asynchronous) { - - f_macro_array_lengths_t_delete_simple(asynchronous->stack) - - controller_cache_delete_simple(&asynchronous->cache); - } -#endif // _di_controller_asynchronous_delete_simple_ - -#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_default_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_asynchronous_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_cache_action_delete_simple_ void controller_cache_action_delete_simple(controller_cache_action_t *cache) { @@ -147,16 +94,49 @@ extern "C" { } #endif // _di_controller_error_print_ +#ifndef _di_controller_lock_create_ + f_status_t controller_lock_create(controller_lock_t *lock) { + + 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; + + status = f_thread_lock_create(0, &lock->rule); + if (F_status_is_error(status)) return status; + + return F_none; + } +#endif // _di_controller_lock_create_ + +#ifndef _di_controller_lock_delete_simple_ + void controller_lock_delete_simple(controller_lock_t *lock) { + + f_thread_mutex_delete(&lock->print); + + f_thread_lock_delete(&lock->entry); + f_thread_lock_delete(&lock->process); + f_thread_lock_delete(&lock->rule); + } +#endif // _di_controller_lock_delete_simple_ + #ifndef _di_controller_process_delete_simple_ void controller_process_delete_simple(controller_process_t *process) { - f_string_dynamic_resize(0, &process->id_rule); + f_string_dynamic_resize(0, &process->alias_rule); f_thread_lock_delete(&process->lock); f_thread_lock_delete(&process->active); + f_thread_mutex_delete(&process->running); + f_thread_condition_delete(&process->wait); + + controller_cache_delete_simple(&process->cache); - f_thread_lock_attribute_delete(&process->lock_attribute); - f_thread_lock_attribute_delete(&process->active_attribute); + f_macro_array_lengths_t_delete_simple(process->stack) } #endif // _di_controller_process_delete_simple_ @@ -200,6 +180,32 @@ extern "C" { status = f_memory_resize(processs->size, length, sizeof(controller_process_t), (void **) & processs->array); if (F_status_is_error_not(status)) { + + // the lock must be initialized, but only once, so initialize immediately upon allocation. + while (processs->size < length) { + + status = f_thread_lock_create(0, &processs->array[processs->size].lock); + + if (F_status_is_error_not(status)) { + status = f_thread_lock_create(0, &processs->array[processs->size].active); + } + + if (F_status_is_error_not(status)) { + status = f_thread_mutex_create(0, &processs->array[processs->size].running); + } + + if (F_status_is_error_not(status)) { + status = f_thread_condition_create(0, &processs->array[processs->size].wait); + } + + ++processs->size; + + if (F_status_is_error(status)) { + processs->size = length; + return status; + } + } // while + processs->size = length; if (processs->used > processs->size) { @@ -235,7 +241,7 @@ extern "C" { #ifndef _di_controller_rule_delete_simple_ void controller_rule_delete_simple(controller_rule_t *rule) { - f_string_dynamic_resize(0, &rule->id); + f_string_dynamic_resize(0, &rule->alias); f_string_dynamic_resize(0, &rule->name); f_string_dynamic_resize(0, &rule->path); f_string_dynamic_resize(0, &rule->script); @@ -346,18 +352,8 @@ extern "C" { #ifndef _di_controller_thread_delete_simple_ void controller_thread_delete_simple(controller_thread_t *thread) { - f_thread_mutex_delete(&thread->lock.print); - - f_thread_lock_delete(&thread->lock.asynchronous); - f_thread_lock_attribute_delete(&thread->lock.asynchronous_attribute); - - f_thread_lock_delete(&thread->lock.process); - f_thread_lock_attribute_delete(&thread->lock.process_attribute); - - f_thread_lock_delete(&thread->lock.rule); - f_thread_lock_attribute_delete(&thread->lock.rule_attribute); - - controller_asynchronouss_resize(0, &thread->asynchronouss); + controller_lock_delete_simple(&thread->lock); + controller_processs_resize(0, &thread->processs); } #endif // _di_controller_thread_delete_simple_ diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index ac709f1..ebab445 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -306,6 +306,109 @@ extern "C" { #endif // _di_controller_resource_limit_t_ /** + * Action related cache. + * + * line_action: The line in some file representing an Action. + * line_item: The line in some file representing an Item. + * name_action: A NULL terminated name of some Action. + * name_file: A NULL terminated name of some File. + * name_item: A NULL terminated name of some Item. + * generic: A NULL terminated string for general use. + */ +#ifndef _di_controller_cache_action_t_ + typedef struct { + f_array_length_t line_action; + f_array_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; \ + f_macro_string_dynamic_t_clear(cache.name_action) \ + f_macro_string_dynamic_t_clear(cache.name_file) \ + f_macro_string_dynamic_t_clear(cache.name_item) \ + f_macro_string_dynamic_t_clear(cache.generic) +#endif // _di_controller_cache_action_t_ + +/** + * A cache intended for re-using memory while loading and processing rules whenever possible. + * + * timestamp: The timestamp. + * range_action: The Range for some Action. + * ats: Locations. + * stack: Locations within a items history used as a history stack for circular recursion prevention. + * comments: Comments associated with a buffer string. + * delimits: Delimits associated with a buffer string. + * content_action: The specific Content for some Action. + * content_actions: Content for some Action. + * content_items: Content for some Item. + * object_actions: Objects for some Action. + * object_items: Objects for some Item. + * buffer_file: A generic file related buffer. + * buffer_item: A generic item related buffer. + * buffer_path: A generic path related buffer. + * action: A cache for some Action, often used by error printing for reporting where an error happened. + */ +#ifndef _di_controller_cache_t_ + typedef struct { + f_time_spec_t timestamp; + + f_string_range_t range_action; + + f_array_lengths_t ats; + f_array_lengths_t stack; + + f_fss_comments_t comments; + f_fss_delimits_t delimits; + + f_fss_content_t content_action; + f_fss_contents_t content_actions; + f_fss_contents_t content_items; + f_fss_objects_t object_actions; + f_fss_objects_t object_items; + + f_string_dynamic_t buffer_file; + f_string_dynamic_t buffer_item; + f_string_dynamic_t buffer_path; + + controller_cache_action_t action; + } controller_cache_t; + + #define controller_cache_t_initialize { \ + f_time_spec_t_initialize, \ + f_string_range_t_initialize, \ + f_array_lengths_t_initialize, \ + f_array_lengths_t_initialize, \ + f_fss_comments_t_initialize, \ + f_fss_delimits_t_initialize, \ + f_fss_content_t_initialize, \ + f_fss_contents_t_initialize, \ + f_fss_contents_t_initialize, \ + f_fss_objects_t_initialize, \ + f_fss_objects_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + controller_cache_action_t_initialize, \ + } +#endif // _di_controller_cache_t_ + +/** * A structure for passing execution arguments to the execute functions. * * parameter: All parameters sent to the program on execution. @@ -324,53 +427,37 @@ extern "C" { #define controller_macro_execute_set_t_initialize(option, environment, signals, data, as) { \ fl_macro_execute_parameter_t_initialize(option, environment, signals, data), \ - as \ + as, \ } - - #define controller_macro_execute_set_t_clear(set) \ - fl_macro_execute_parameter_t_clear(set.parameter) \ - fl_macro_execute_as_t_clear(set.as) #endif // _di_controller_execute_set_t_ /** * A structure for sharing mutexes globally between different threads. * - * The asynchronous lock is intended to lock any activity on the asynchronouss structure and related. * The print lock is intended to lock any activity printing to stdout/stderr. + * The entry lock is intended to lock any activity on the entrys structure. * The process lock is intended to lock any activity on the processs structure. * The rule lock is intended to lock any activity on the rules structure. * - * print: The print mutex lock. - * asynchronous: The asynchronous r/w lock. - * asynchronous_attribute: The asynchronous r/w lock attribute. - * process: The process r/w lock. - * process_attribute: The process r/w lock attribute. - * rule: The rule r/w lock. - * rule_attribute: The rule r/w lock attribute. - * + * print: The print mutex lock. + * entry: The entry r/w lock. + * process: The process r/w lock. + * rule: The rule r/w lock. */ #ifndef _di_controller_lock_t_ typedef struct { f_thread_mutex_t print; - f_thread_lock_t asynchronous; - f_thread_lock_attribute_t asynchronous_attribute; - + f_thread_lock_t entry; f_thread_lock_t process; - f_thread_lock_attribute_t process_attribute; - f_thread_lock_t rule; - f_thread_lock_attribute_t rule_attribute; } controller_lock_t; #define controller_lock_t_initialize { \ f_thread_mutex_t_initialize, \ f_thread_lock_t_initialize, \ - f_thread_lock_attribute_t_initialize, \ f_thread_lock_t_initialize, \ - f_thread_lock_attribute_t_initialize, \ f_thread_lock_t_initialize, \ - f_thread_lock_attribute_t_initialize \ } #endif // _di_controller_mutex_t_ @@ -424,12 +511,6 @@ extern "C" { F_known_not, \ f_string_dynamics_t_initialize, \ } - - #define controller_macro_rule_action_t_clear(rule) \ - type = 0; \ - line = 0; \ - status = F_known_not; \ - f_macro_string_dynamics_t_clear(rule.parameters) #endif // _di_controller_rule_action_t_ /** @@ -452,11 +533,6 @@ extern "C" { 0, \ 0, \ } - - #define controller_macro_rule_actions_t_clear(actions) \ - actions.array = 0; \ - actions.size = 0; \ - actions.used = 0; #endif // _di_controller_rule_actions_t_ /** @@ -487,11 +563,6 @@ extern "C" { 0, \ controller_rule_actions_t_initialize, \ } - - #define controller_macro_rule_item_t_clear(item) \ - item.type = 0; \ - item.line = 0; \ - controller_macro_rule_actions_t_clear(item.actions); #endif // _di_controller_rule_item_t_ /** @@ -514,11 +585,6 @@ extern "C" { 0, \ 0, \ } - - #define controller_macro_rule_items_t_clear(items) \ - items.array = 0; \ - items.size = 0; \ - items.used = 0; #endif // _di_controller_rule_items_t_ /** @@ -596,7 +662,7 @@ extern "C" { f_time_spec_t timestamp; - f_string_dynamic_t id; + f_string_dynamic_t alias; f_string_dynamic_t name; f_string_dynamic_t path; f_string_dynamic_t script; @@ -646,33 +712,6 @@ extern "C" { f_execute_scheduler_t_initialize, \ controller_rule_items_initialize, \ } - - #define controller_macro_rule_t_clear(rule) \ - rule.timeout_kill = 0; \ - rule.timeout_start = 0; \ - rule.timeout_stop = 0; \ - rule.has = 0; \ - rule.nice = 0; \ - rule.user = 0; \ - rule.group = 0; \ - f_macro_time_spec_t_clear(rule.timestamp) \ - f_macro_string_dynamic_t_clear(rule.id) \ - f_macro_string_dynamic_t_clear(rule.name) \ - f_macro_string_dynamic_t_clear(rule.path) \ - f_macro_string_dynamic_t_clear(rule.script) \ - f_macro_string_maps_t_clear(rule.define) \ - f_macro_string_maps_t_clear(rule.parameter) \ - f_macro_string_dynamics_t_clear(rule.environment) \ - f_macro_string_dynamics_t_clear(rule.need) \ - f_macro_string_dynamics_t_clear(rule.want) \ - f_macro_string_dynamics_t_clear(rule.wish) \ - f_macro_int32s_t_clear(rule.affinity) \ - f_macro_capability_t_clear(rule.capability) \ - f_macro_control_group_t_clear(rule.control_group) \ - f_macro_int32s_t_clear(rule.groups) \ - f_macro_limit_sets_t_clear(rule.limits) \ - f_macro_execute_scheduler_t_clear(rule.scheduler) \ - controller_macro_rule_items_t_clear(rule.items) #endif // _di_controller_rule_t_ /** @@ -695,11 +734,6 @@ extern "C" { 0, \ 0, \ } - - #define controller_macro_rules_t_clear(rules) \ - rules.array = 0; \ - rules.size = 0; \ - rules.used = 0; #endif // _di_controller_rules_t_ /** @@ -707,32 +741,80 @@ extern "C" { * * This refers to "process" as in the processing of a single rule for the given Rule ID and does not refer to "process" as in a CPU Process. * - * id_rule: The Rule ID, such as "network/ntpdate". - * status: The last execution status of the Rule. - * lock: A read/write lock on the structure. - * active: A read/write lock representing that something is currently using this (read locks = in use, write lock = see if in use and possibly prepare for delete). - * lock_attribute: The lock attribute for "lock". - * active_attribute: The lock attribute for "active". + * Process States: + * - idle: No process is running for this rule. + * - busy: A process is actively using this, and is running synchronously. + * - active: A process is actively using this, and is running asynchronously. + * - done: A process has finished running on this and there is a thread that needs to be cleaned up. + * + * id: The ID of this process relative to the processes array. + * alias_rule: The Rule alias, such as "network/ntpdate". + * status: The last execution status of the Rule. + * state: The state of the process. + * action: The action being performed. + * options: Configuration options for this asynchronous thread. + * child: The process id of a child process, if one is running (when forking to execute a child process). + * id_thread: The thread id, a valid ID when state is "active", and an invalid ID when the state is "busy". + * lock: A read/write lock on the structure. + * active: A read/write lock representing that something is currently using this (read locks = in use, write lock = begin deleting). + * running: A mutex lock for working with "wait" to designate that the process is being executed and to trigger anything waiting when done. + * wait: A thread condition to tell a process waiting process that the rule has is done being processed. + * cache: The cache used in this process. + * stack: A stack used to represent dependencies to avoid circular rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A). + * main_data: Used for passing the controller_data_t data to the process thread (to populate controller_main_t). + * main_setting: Used for passing the controller_setting_t data to the process thread (to populate controller_main_t). + * main_thread: Used for passing the controller_thread_t data to the process thread (to populate controller_main_t). */ #ifndef _di_controller_process_t_ + enum { + controller_process_state_idle = 1, + controller_process_state_busy, + controller_process_state_active, + controller_process_state_done, + }; + typedef struct { - f_string_dynamic_t id_rule; + f_array_length_t id; + f_string_dynamic_t alias_rule; f_status_t status; + uint8_t state; + uint8_t action; + uint8_t options; + pid_t child; + + f_thread_id_t id_thread; f_thread_lock_t lock; f_thread_lock_t active; - f_thread_lock_attribute_t lock_attribute; - f_thread_lock_attribute_t active_attribute; + f_thread_mutex_t running; + f_thread_condition_t wait; + + controller_cache_t cache; + f_array_lengths_t stack; + + void *main_data; + void *main_setting; + void *main_thread; } controller_process_t; #define controller_process_t_initialize { \ + 0, \ f_string_dynamic_t_initialize \ F_known_not, \ + 0, \ + 0, \ + 0, \ + 0, \ + f_thread_id_t_initialize, \ f_thread_lock_t_initialize, \ f_thread_lock_t_initialize, \ - f_thread_lock_attribute_t_initialize, \ - f_thread_lock_attribute_t_initialize, \ + f_thread_condition_t_initialize, \ + controller_cache_t_initialize, \ + f_array_lengths_t_initialize, \ + 0, \ + 0, \ + 0, \ } #endif // _di_controller_process_t_ @@ -756,11 +838,6 @@ extern "C" { 0, \ 0, \ } - - #define controller_macro_processs_t_clear(process) \ - process.array = 0; \ - process.size = 0; \ - process.used = 0; #endif // _di_controller_processs_t_ /** @@ -811,14 +888,6 @@ extern "C" { F_known_not, \ f_string_dynamics_t_initialize, \ } - - #define controller_macro_entry_action_t_clear(action) \ - action.type = 0; \ - action.code = 0; \ - action.line = 0; \ - action.number = 0; \ - action.status = F_known_not; \ - f_macro_string_dynamics_t_clear(action.parameters) #endif // _di_controller_entry_action_t_ /** @@ -841,11 +910,6 @@ extern "C" { 0, \ 0, \ } - - #define controller_macro_entry_actions_t_clear(actions) \ - actions.array = 0; \ - actions.size = 0; \ - actions.used = 0; #endif // _di_controller_entry_actions_t_ /** @@ -869,11 +933,6 @@ extern "C" { f_string_dynamic_t_initialize, \ controller_entry_actions_t_initialize, \ } - - #define controller_macro_entry_item_t_clear(item) \ - item.line = 0; \ - f_macro_string_dynamic_t_clear(item.name) \ - controller_macro_entry_actions_t_clear(item.actions) #endif // _di_controller_entry_item_t_ /** @@ -920,10 +979,6 @@ extern "C" { F_known_not, \ controller_entry_items_t_initialize, \ } - - #define controller_macro_entry_t_clear(entry) \ - entry.status = F_known_not; \ - controller_macro_entry_items_t_clear(entry.items) #endif // _di_controller_entry_t_ /** @@ -985,216 +1040,24 @@ extern "C" { controller_entry_t_initialize, \ controller_rules_t_initialize, \ } - - #define controller_macro_setting_t_clear(setting) \ - setting.interruptable = F_false; \ - setting.ready = 0; \ - setting.timeout_kill = 3; \ - setting.timeout_start = 3; \ - setting.timeout_stop = 3; \ - setting.failsafe_enabled = F_false; \ - setting.failsafe_rule_id = 0; \ - f_macro_string_dynamic_t_clear(entry.path_control) \ - f_macro_string_dynamic_t_clear(entry.path_pid) \ - f_macro_string_dynamic_t_clear(entry.path_setting) \ - controller_macro_entry_t_clear(entry.entry) \ - controller_macro_rules_t_clear(entry.setting) #endif // _di_controller_setting_t /** - * Action related cache. - * - * line_action: The line in some file representing an Action. - * line_item: The line in some file representing an Item. - * name_action: A NULL terminated name of some Action. - * name_file: A NULL terminated name of some File. - * name_item: A NULL terminated name of some Item. - * generic: A NULL terminated string for general use. - */ -#ifndef _di_controller_cache_action_t_ - typedef struct { - f_array_length_t line_action; - f_array_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; \ - f_macro_string_dynamic_t_clear(cache.name_action) \ - f_macro_string_dynamic_t_clear(cache.name_file) \ - f_macro_string_dynamic_t_clear(cache.name_item) \ - f_macro_string_dynamic_t_clear(cache.generic) -#endif // _di_controller_cache_action_t_ - -/** - * A cache intended for re-using memory while loading and processing rules whenever possible. - * - * timestamp: The timestamp. - * range_action: The Range for some Action. - * ats: Locations. - * stack: Locations within a items history used as a history stack for circular recursion prevention. - * comments: Comments associated with a buffer string. - * delimits: Delimits associated with a buffer string. - * content_action: The specific Content for some Action. - * content_actions: Content for some Action. - * content_items: Content for some Item. - * object_actions: Objects for some Action. - * object_items: Objects for some Item. - * buffer_file: A generic file related buffer. - * buffer_item: A generic item related buffer. - * buffer_path: A generic path related buffer. - * action: A cache for some Action, often used by error printing for reporting where an error happened. - */ -#ifndef _di_controller_cache_t_ - typedef struct { - f_time_spec_t timestamp; - - f_string_range_t range_action; - - f_array_lengths_t ats; - f_array_lengths_t stack; - - f_fss_comments_t comments; - f_fss_delimits_t delimits; - - f_fss_content_t content_action; - f_fss_contents_t content_actions; - f_fss_contents_t content_items; - f_fss_objects_t object_actions; - f_fss_objects_t object_items; - - f_string_dynamic_t buffer_file; - f_string_dynamic_t buffer_item; - f_string_dynamic_t buffer_path; - - controller_cache_action_t action; - } controller_cache_t; - - #define controller_cache_t_initialize { \ - f_time_spec_t_initialize, \ - f_string_range_t_initialize, \ - f_array_lengths_t_initialize, \ - f_array_lengths_t_initialize, \ - f_fss_comments_t_initialize, \ - f_fss_delimits_t_initialize, \ - f_fss_content_t_initialize, \ - f_fss_contents_t_initialize, \ - f_fss_contents_t_initialize, \ - f_fss_objects_t_initialize, \ - f_fss_objects_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - controller_cache_action_t_initialize, \ - } -#endif // _di_controller_cache_t_ - -/** - * Stores data passed to a thread on thread creation, specifically for rule processing. - * - * The thread has different states: - * - active: The thread is running. - * - done: The thread has finished executed but has not been cleaned up. - * - joined: The thread has been cleaned up, this is safe to delete. - * - * id: The thread id, which is controlled by pthread functions. - * id_process: The id representing the rule process this asynchronous thread operates for. - * state: The state of the asynchronous. - * action: The action being performed. - * options: Configuration options for this asynchronous thread. - * child: The process id of a child process, if one is running (when forking to execute a child process). - * stack: The execution stack representing all other rule processes (by process id) that called this (to prevent infinite recursion). // @todo is this needed here anymore? - * cache: A per asynchronous thread cache. - */ -#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 id_process; - - uint8_t state; - uint8_t action; - uint8_t options; - pid_t child; - - f_array_lengths_t stack; - controller_cache_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_t_initialize \ - } -#endif // _di_controller_asynchronous_t_ - -/** - * The asynchronous execution data. - * - * array: An array of asynchronous execution data. - * size: Total amount of allocated space. - * used: Total number of allocated spaces used. - */ -#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_clear(asynchronouss) \ - asynchronouss.array = 0; \ - asynchronouss.size = 0; \ - asynchronouss.used = 0; -#endif // _di_controller_asynchronouss_t_ - -/** * A structure for managing threads. * * This is essentially data shared globally between threads, about threads. * - * As a special case, index 0 of asynchronouss is reserved for use the main thread and is not used by any Rule Processes. + * As a special case, index 0 of processs is reserved for use the main thread and is not used by any Rule Processes. * - * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE. - * signal: The code of any signal received. - * id_cleanup: The thread ID representing the cleanup Process. - * id_control: The thread ID representing the cleanup Process. - * id_rule: The thread ID representing the cleanup Process. - * id_signal: The thread ID representing the cleanup Process. - * lock: A r/w lock for operating on this structure. - * asynchronouss: All Rule Process thread data. + * 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. + * signal: The code of any signal received. + * id_cleanup: The thread ID representing the Cleanup Process. + * id_control: The thread ID representing the Control Process. + * id_signal: The thread ID representing the Signal Process. + * lock: A r/w lock for operating on this structure. + * processs: All Rule Process thread data. */ #ifndef _di_controller_thread_t_ typedef struct { @@ -1203,11 +1066,10 @@ extern "C" { f_thread_id_t id_cleanup; f_thread_id_t id_control; - f_thread_id_t id_rule; f_thread_id_t id_signal; controller_lock_t lock; - controller_asynchronouss_t asynchronouss; + controller_processs_t processs; } controller_thread_t; #define controller_thread_t_initialize { \ @@ -1216,134 +1078,38 @@ extern "C" { f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ - f_thread_id_t_initialize, \ controller_lock_t_initialize, \ - controller_asynchronouss_t_initialize \ + controller_processs_t_initialize, \ } - - #define controller_macro_thread_t_initialize(lock, asynchronouss) { \ - F_true, \ - 0, \ - f_thread_id_t_initialize, \ - f_thread_id_t_initialize, \ - f_thread_id_t_initialize, \ - f_thread_id_t_initialize. \ - lock, \ - asynchronouss \ - } - - #define controller_macro_thread_t_clear(thread) \ - thread.enabled = F_true; \ - thread.signal = 0; \ - f_macro_thread_id_t_clear(thread.id_cleanup); \ - f_macro_thread_id_t_clear(thread.id_control); \ - f_macro_thread_id_t_clear(thread.id_rule); \ - f_macro_thread_id_t_clear(thread.id_signal); \ - controller_macro_asynchronouss_t_clear(thread.asynchronouss) #endif // _di_controller_data_common_t_ /** - * A wrapper used for passing all data to each individual asynchronous thread. + * A wrapper used for passing a common set of all data, particularly for sharing between threads. * - * id_process: The index in the processs array representing the current process. - * data: All standard program data. - * setting: All loaded settings. - * processs: All Rule Process data. - * thread: All thread related data. + * data: All standard program data. + * setting: All loaded settings. + * processs: All Rule Process data. + * thread: All thread related data. */ -#ifndef _di_controller_thread_data_t_ +#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. - - // @fixme these aren't used? consider removing or updating. - #define controller_thread_asynchronous_allocation_step 16 // Total number of asynchronous threads increase by. - #define controller_thread_asynchronous_max 65535 // Total number of asynchronous threads allowed at any one time. + #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 { - f_array_length_t id_process; - controller_data_t *data; controller_setting_t *setting; - controller_processs_t *processs; controller_thread_t *thread; - } controller_thread_data_t; + } controller_main_t; - #define controller_thread_data_t_initialize { 0, 0, 0, 0, 0 } + #define controller_main_t_initialize { 0, 0, 0 } - #define controller_macro_thread_data_t_initialize(id_process, data, setting, processs, thread) { \ - id_process, \ + #define controller_macro_main_t_initialize(data, setting, thread) { \ data, \ setting, \ - processs, \ - thread \ + thread, \ } - - #define controller_macro_thread_data_t_clear(thread_data) \ - thread_data.id_process = 0; \ - thread_data.data = 0; \ - thread_data.setting = 0; \ - thread_data.processs = 0; \ - thread_data.thread = 0; -#endif // _di_controller_thread_data_t_ - -/** - * Fully deallocate all memory for the given asynchronous without caring about return status. - * - * @param asynchronous - * The asynchronous to deallocate. - * - * @see f_macro_array_lengths_t_delete_simple() - * - * @see controller_cache_delete_simple() - * @see controller_rule_delete_simple() - */ -#ifndef _di_controller_asynchronous_delete_simple_ - extern void controller_asynchronous_delete_simple(controller_asynchronous_t *asynchronous) f_gcc_attribute_visibility_internal; -#endif // _di_controller_asynchronous_delete_simple_ - -/** - * Increase the size of the asynchronous 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_default_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. - * - * @see controller_asynchronouss_resize() - */ -#ifndef _di_controller_asynchronouss_increase_ - extern f_status_t controller_asynchronouss_increase(controller_asynchronouss_t *asynchronouss) f_gcc_attribute_visibility_internal; -#endif // _di_controller_asynchronouss_increase_ - -/** - * Resize the string asynchronous 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. - * - * @see f_memory_resize() - */ -#ifndef _di_controller_asynchronouss_resize_ - extern f_status_t controller_asynchronouss_resize(const f_array_length_t length, controller_asynchronouss_t *asynchronouss) f_gcc_attribute_visibility_internal; -#endif // _di_controller_asynchronouss_resize_ +#endif // _di_controller_main_t_ /** * Fully deallocate all memory for the given cache without caring about return status. @@ -1448,8 +1214,43 @@ extern "C" { #endif // _di_controller_error_print_ /** + * Perform the initial, required, allocation for the lock. + * + * @param lock + * The lock to allocate. + * + * @return + * F_none on success. + * + * Errors (with error bit) from f_thread_lock_delete(). + * Errors (with error bit) from f_thread_mutex_delete(). + * + * @see f_thread_lock_delete() + * @see f_thread_mutex_delete() + */ +#ifndef _di_controller_lock_create_ + extern f_status_t controller_lock_create(controller_lock_t *lock) f_gcc_attribute_visibility_internal; +#endif // _di_controller_lock_create_ + +/** + * Fully deallocate all memory for the given lock without caring about return status. + * + * @param lock + * The lock to deallocate. + * + * @see f_thread_lock_delete() + * @see f_thread_mutex_delete() + */ +#ifndef _di_controller_lock_delete_simple_ + extern void controller_lock_delete_simple(controller_lock_t *lock) f_gcc_attribute_visibility_internal; +#endif // _di_controller_lock_delete_simple_ + +/** * Fully deallocate all memory for the given process without caring about return status. * + * This does not close/cancel the id_thread. + * Be sure to properly close and/or detach the thread. + * * @param process * The process to deallocate. * @@ -1464,6 +1265,9 @@ extern "C" { /** * Fully deallocate all memory for the given processs without caring about return status. * + * This does not close/cancel the id_thread for any process. + * Be sure to properly close and/or detach the thread for each process. + * * @param processs * The process array to deallocate. * @@ -1507,10 +1311,15 @@ extern "C" { * @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. + * Errors (with error bit) from: controller_process_delete_simple(). + * Errors (with error bit) from: f_memory_resize(). + * Errors (with error bit) from: f_thread_condition_create(). + * Errors (with error bit) from: f_thread_lock_create(). * + * @see controller_process_delete_simple() * @see f_memory_resize() + * @see f_thread_condition_create() + * @see f_thread_lock_create() */ #ifndef _di_controller_processs_resize_ extern f_status_t controller_processs_resize(const f_array_length_t length, controller_processs_t *processs) f_gcc_attribute_visibility_internal; diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index 24e82ca..8938ca3 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -41,7 +41,7 @@ extern "C" { #endif // _di_controller_string_dynamic_partial_append_terminated_ #ifndef _di_controller_file_load_ - f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_thread_data_t thread_data, controller_cache_t *cache) { + f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_main_t main, controller_cache_t *cache) { f_status_t status = F_none; f_file_t file = f_file_t_initialize; @@ -69,12 +69,12 @@ extern "C" { } if (F_status_is_error(status)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_append", F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } return status; @@ -83,25 +83,25 @@ extern "C" { status = f_string_dynamic_terminate_after(&cache->action.name_file); if (F_status_is_error(status)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } return status; } - const f_array_length_t path_length = thread_data.setting->path_setting.used ? thread_data.setting->path_setting.used + f_path_separator_length + cache->action.name_file.used : cache->action.name_file.used; + const f_array_length_t path_length = main.setting->path_setting.used ? main.setting->path_setting.used + f_path_separator_length + cache->action.name_file.used : cache->action.name_file.used; char path[path_length + 1]; - if (thread_data.setting->path_setting.used) { - memcpy(path, thread_data.setting->path_setting.string, thread_data.setting->path_setting.used); - memcpy(path + thread_data.setting->path_setting.used + f_path_separator_length, cache->action.name_file.string, cache->action.name_file.used); + if (main.setting->path_setting.used) { + memcpy(path, main.setting->path_setting.string, main.setting->path_setting.used); + memcpy(path + main.setting->path_setting.used + f_path_separator_length, cache->action.name_file.string, cache->action.name_file.used); - path[thread_data.setting->path_setting.used] = f_path_separator_s[0]; + path[main.setting->path_setting.used] = f_path_separator_s[0]; } path[path_length] = 0; @@ -109,24 +109,24 @@ extern "C" { status = f_file_stream_open(path, 0, &file); if (F_status_is_error(status)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file); + fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } else { status = f_file_stream_read(file, 1, &cache->buffer_file); if (F_status_is_error(status)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file); + fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } } @@ -139,12 +139,12 @@ extern "C" { status = f_file_stat(path, F_true, &stat_file); if (F_status_is_error(status)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file); + fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } else { @@ -252,14 +252,14 @@ extern "C" { #endif // _di_controller_file_pid_delete_ #ifndef _di_controller_find_process_ - f_status_t controller_find_process(const f_string_static_t id, const controller_processs_t processs, f_array_length_t *at) { + f_status_t controller_find_process(const f_string_static_t alias, const controller_processs_t processs, f_array_length_t *at) { - if (!id.used) return F_none; + if (!alias.used) return F_none; if (!processs.used) return F_false; for (f_array_length_t i = 0; i < processs.used; ++i) { - if (fl_string_dynamic_compare(id, processs.array[i].id_rule) == F_equal_to) { + if (fl_string_dynamic_compare(alias, processs.array[i].alias_rule) == F_equal_to) { *at = i; return F_true; } @@ -354,40 +354,40 @@ extern "C" { #endif // _di_controller_get_id_group_ #ifndef _di_controller_perform_ready_ - f_status_t controller_perform_ready(controller_thread_data_t thread_data, controller_cache_t *cache) { + f_status_t controller_perform_ready(controller_main_t main, controller_cache_t *cache) { f_status_t status = F_none; // only create pid file when not in validate mode. - if (thread_data.data->parameters[controller_parameter_validate].result == f_console_result_none) { + if (main.data->parameters[controller_parameter_validate].result == f_console_result_none) { - status = controller_file_pid_create(*thread_data.data, thread_data.setting->path_pid); + status = controller_file_pid_create(*main.data, main.setting->path_pid); // report pid file error but because this could be an "init" program, consider the pid file as optional and continue on. if (F_status_is_error(status)) { // always return immediately on memory errors. if (F_status_set_fine(status) == F_memory_not) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file); + fll_error_file_print(main.data->error, F_status_set_fine(status), "controller_file_pid_create", F_true, main.setting->path_pid.string, "create", fll_error_file_type_file); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } return status; } - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_file_print(thread_data.data->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file); + fll_error_file_print(main.data->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, main.setting->path_pid.string, "create", fll_error_file_type_file); - controller_entry_error_print_cache(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(main.data->warning, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } status = F_none; @@ -399,7 +399,7 @@ extern "C" { #endif // _di_controller_perform_ready_ #ifndef _di_controller_preprocess_entry_ - f_status_t controller_preprocess_entry(controller_thread_data_t thread_data, controller_cache_t *cache) { + f_status_t controller_preprocess_entry(controller_main_t main, controller_cache_t *cache) { f_status_t status = F_none; f_status_t status2 = F_none; @@ -413,7 +413,7 @@ extern "C" { uint8_t error_has = F_false; - thread_data.setting->ready = controller_setting_ready_no; + main.setting->ready = controller_setting_ready_no; cache->ats.used = 0; @@ -425,7 +425,7 @@ extern "C" { f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); + 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); return status; } @@ -434,24 +434,24 @@ extern "C" { cache->ats.array[1] = 0; cache->ats.used = 2; - cache->action.line_item = thread_data.setting->entry.items.array[0].line; + cache->action.line_item = main.setting->entry.items.array[0].line; cache->action.name_item.used = 0; - status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[0].name, &cache->action.name_item); + status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[0].name, &cache->action.name_item); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); return status; } for (;;) { - actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions; + actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions; for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) { - if (thread_data.thread->signal) { + if (main.thread->signal) { return F_signal; } @@ -461,30 +461,30 @@ extern "C" { status2 = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->action.name_action); if (F_status_is_error(status2)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, main.thread); return status2; } if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) { - if (thread_data.setting->ready == controller_setting_ready_wait) { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.setting->ready == controller_setting_ready_wait) { + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->warning.to.stream, "%s%sMultiple '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); - fprintf(thread_data.data->warning.to.stream, "%s%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, controller_string_ready_s, thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%s%sMultiple '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s); + fprintf(main.data->warning.to.stream, "%s%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, controller_string_ready_s, main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(main.data->warning, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } // the pre-process currently only looks for "ready", so once found, pre-process is complete. - thread_data.setting->ready = controller_setting_ready_wait; + main.setting->ready = controller_setting_ready_wait; } else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) { error_has = F_false; @@ -494,25 +494,25 @@ extern "C" { } // walk though each items and check to see if the item actually exists (skipping main). - for (i = 1; i < thread_data.setting->entry.items.used; ++i) { + for (i = 1; i < main.setting->entry.items.used; ++i) { - if (fl_string_dynamic_compare(thread_data.setting->entry.items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) { + if (fl_string_dynamic_compare(main.setting->entry.items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) { // check to see if "i" is already in the stack (to prevent recursion) (skipping main). for (j = 2; j < cache->ats.used; j += 2) { if (cache->ats.array[j] == i) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item named '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.setting->entry.items.array[i].name.string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item named '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.setting->entry.items.array[i].name.string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } if (F_status_is_error_not(status)) { @@ -529,7 +529,7 @@ extern "C" { f_macro_array_lengths_t_increase_by(status2, cache->ats, controller_default_allocation_step) if (F_status_is_error(status2)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true, main.thread); return status2; } @@ -549,12 +549,12 @@ extern "C" { cache->action.line_action = 0; cache->action.name_item.used = 0; - cache->action.line_item = thread_data.setting->entry.items.array[i].line; + cache->action.line_item = main.setting->entry.items.array[i].line; - status2 = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[i].name, &cache->action.name_item); + status2 = controller_string_dynamic_append_terminated(main.setting->entry.items.array[i].name, &cache->action.name_item); if (F_status_is_error(status2)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, main.thread); return status2; } @@ -563,19 +563,19 @@ extern "C" { } } // for - if (error_has || i >= thread_data.setting->entry.items.used) { - if (i >= thread_data.setting->entry.items.used) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (error_has || i >= main.setting->entry.items.used) { + if (i >= main.setting->entry.items.used) { + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item named '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].parameters.array[0].string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' does not exist.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item named '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].parameters.array[0].string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' does not exist.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } if (F_status_is_error_not(status)) { @@ -604,13 +604,13 @@ extern "C" { cache->ats.used -= 2; cache->ats.array[at_j]++; - cache->action.line_item = thread_data.setting->entry.items.array[cache->ats.array[at_i]].line; + cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line; cache->action.name_item.used = 0; - status2 = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); + status2 = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); if (F_status_is_error(status2)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, main.thread); return status2; } @@ -618,8 +618,8 @@ extern "C" { } // for // if ready was never found in the entry, then default to always ready. - if (thread_data.setting->ready == controller_setting_ready_no) { - thread_data.setting->ready = controller_setting_ready_yes; + if (main.setting->ready == controller_setting_ready_no) { + main.setting->ready = controller_setting_ready_yes; } return status; @@ -627,7 +627,7 @@ extern "C" { #endif // _di_controller_preprocess_entry_ #ifndef _di_controller_process_entry_ - f_status_t controller_process_entry(controller_thread_data_t thread_data, controller_cache_t *cache) { + f_status_t controller_process_entry(controller_main_t main, controller_cache_t *cache) { f_status_t status = F_none; f_array_length_t i = 0; @@ -643,7 +643,10 @@ extern "C" { controller_entry_actions_t *entry_actions = 0; controller_process_t *process = 0; - const bool simulate = thread_data.data->parameters[controller_parameter_test].result == f_console_result_found; + // an empty stack is used here because each rule here is the first rule run in the rule's scope. + const f_array_lengths_t stack = f_array_lengths_t_initialize; + + const bool simulate = main.data->parameters[controller_parameter_test].result == f_console_result_found; cache->ats.used = 0; cache->stack.used = 0; @@ -653,15 +656,15 @@ extern "C" { cache->action.name_action.used = 0; cache->action.name_item.used = 0; - if (thread_data.setting->ready == controller_setting_ready_yes) { - status = controller_perform_ready(thread_data, cache); + if (main.setting->ready == controller_setting_ready_yes) { + status = controller_perform_ready(main, cache); if (F_status_is_error(status)) return status; } f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); + 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); return status; } @@ -671,37 +674,37 @@ extern "C" { cache->ats.array[1] = 0; cache->ats.used = 2; - cache->action.line_item = thread_data.setting->entry.items.array[0].line; + cache->action.line_item = main.setting->entry.items.array[0].line; cache->action.name_item.used = 0; - status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[0].name, &cache->action.name_item); + status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[0].name, &cache->action.name_item); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); return status; } if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Processing entry item rule '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_main_s, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Processing entry item rule '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_main_s, main.data->context.set.title.after->string); + fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } - // @todo this function should maintain a read lock on "thread_data.thread->lock.rule", but it must immediately release the read lock before it can do a write lock (which is unfortunate). - // I would much rather gain the write lock and then release the read lock, but that is likely not possible. + f_thread_lock_read(&main.thread->lock.entry); + for (;;) { - entry_actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions; + entry_actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions; for (; cache->ats.array[at_j] < entry_actions->used; ++cache->ats.array[at_j]) { - if (thread_data.thread->signal) { + if (main.thread->signal) { status = F_signal; break; } @@ -714,7 +717,9 @@ extern "C" { status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(entry_action->type), &cache->action.name_action); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + 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; } @@ -724,111 +729,113 @@ extern "C" { if (entry_action->type == controller_entry_action_type_rule) { if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "The entry item action '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_action.string, thread_data.data->context.set.title.after->string); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "The entry item action '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string); if (entry_action->parameters.used) { - fprintf(thread_data.data->output.stream, f_string_space_s); - fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.before->string); - controller_entry_action_parameters_print(thread_data.data->output.stream, entry_actions->array[cache->ats.array[at_j]]); - fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.after->string); + fprintf(main.data->output.stream, f_string_space_s); + fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string); + controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]); + fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string); } - fprintf(thread_data.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } else if (entry_action->code & controller_entry_rule_code_require) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->action.name_action.string); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.name_action.string); if (entry_action->parameters.used) { - fprintf(thread_data.data->error.to.stream, f_string_space_s); - controller_entry_action_parameters_print(thread_data.data->error.to.stream, entry_actions->array[cache->ats.array[at_j]]); + fprintf(main.data->error.to.stream, f_string_space_s); + controller_entry_action_parameters_print(main.data->error.to.stream, entry_actions->array[cache->ats.array[at_j]]); } - fprintf(thread_data.data->error.to.stream, "%s%s' is ", thread_data.data->error.notable.after->string, thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%srequired%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s and is in a ", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%sfailed%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s state, skipping execution.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%s' is ", main.data->error.notable.after->string, main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%srequired%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s and is in a ", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%sfailed%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s state, skipping execution.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } + f_thread_unlock(&main.thread->lock.entry); + return F_status_is_error(F_require); } - else if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + else if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->warning.to.stream, "%s%sThe entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); - fprintf(thread_data.data->warning.to.stream, "%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, cache->action.name_action.string); + fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%s%sThe entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s); + fprintf(main.data->warning.to.stream, "%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, cache->action.name_action.string); if (entry_action->parameters.used) { - fprintf(thread_data.data->warning.to.stream, f_string_space_s); - controller_entry_action_parameters_print(thread_data.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]); + fprintf(main.data->warning.to.stream, f_string_space_s); + controller_entry_action_parameters_print(main.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]); } - fprintf(thread_data.data->warning.to.stream, "%s%s' is ", thread_data.data->warning.notable.after->string, thread_data.data->warning.context.before->string); - fprintf(thread_data.data->warning.to.stream, "%s%srequired%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s and is in a ", thread_data.data->warning.context.before->string); - fprintf(thread_data.data->warning.to.stream, "%s%sfailed%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s state, skipping execution.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%s%s' is ", main.data->warning.notable.after->string, main.data->warning.context.before->string); + fprintf(main.data->warning.to.stream, "%s%srequired%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s and is in a ", main.data->warning.context.before->string); + fprintf(main.data->warning.to.stream, "%s%sfailed%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s state, skipping execution.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(main.data->warning, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } else { if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "The entry item action '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_action.string, thread_data.data->context.set.title.after->string); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "The entry item action '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string); if (entry_action->parameters.used) { - fprintf(thread_data.data->output.stream, f_string_space_s); - fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.before->string); - controller_entry_action_parameters_print(thread_data.data->output.stream, entry_actions->array[cache->ats.array[at_j]]); - fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.after->string); + fprintf(main.data->output.stream, f_string_space_s); + fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string); + controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]); + fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string); } - fprintf(thread_data.data->output.stream, "' is in a %sfailed%s state, skipping.%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->output.stream, "' is in a %sfailed%s state, skipping.%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } - else if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + else if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->warning.to.stream, "%s%sThe entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); - fprintf(thread_data.data->warning.to.stream, "%s%s", thread_data.data->warning.notable.before->string, cache->action.name_action.string); + fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%s%sThe entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s); + fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.notable.before->string, cache->action.name_action.string); if (entry_action->parameters.used) { - fprintf(thread_data.data->warning.to.stream, f_string_space_s); - controller_entry_action_parameters_print(thread_data.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]); + fprintf(main.data->warning.to.stream, f_string_space_s); + controller_entry_action_parameters_print(main.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]); } - fprintf(thread_data.data->warning.to.stream, "%s' is in a ", thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s%sfailed%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s state, skipping.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%s' is in a ", main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s%sfailed%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s state, skipping.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(main.data->warning, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } @@ -837,61 +844,70 @@ extern "C" { if (entry_action->type == controller_entry_action_type_ready) { - if (thread_data.setting->ready == controller_setting_ready_wait) { + if (main.setting->ready == controller_setting_ready_wait) { if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Processing entry item action '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_ready_s, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Processing entry item action '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string); + fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } else { - controller_perform_ready(thread_data, cache); - if (F_status_is_error(status)) return status; + controller_perform_ready(main, cache); + + if (F_status_is_error(status)) { + f_thread_unlock(&main.thread->lock.entry); + + return status; + } } - thread_data.setting->ready = controller_setting_ready_yes; + main.setting->ready = controller_setting_ready_yes; } else if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Ignoring entry item action '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_ready_s, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Ignoring entry item action '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string); + fprintf(main.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } else if (entry_action->type == controller_entry_action_type_item) { - if (entry_action->number == 0 || entry_action->number >= thread_data.setting->entry.items.used) { + if (entry_action->number == 0 || entry_action->number >= main.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 (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sInvalid entry item index ", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, entry_action->number, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s detected.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sInvalid entry item index ", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, entry_action->number, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s detected.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } + f_thread_unlock(&main.thread->lock.entry); + return F_status_is_error(F_critical); } f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step) if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread); + 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; } @@ -909,25 +925,27 @@ extern "C" { cache->action.line_action = 0; cache->action.name_item.used = 0; - cache->action.line_item = thread_data.setting->entry.items.array[cache->ats.array[at_i]].line; + cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line; - status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); + status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + 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; } if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Processing entry item '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_item.string, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Processing entry item '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_item.string, main.data->context.set.title.after->string); + fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } // exit inner loop to force restarting and start processing the requested item. @@ -935,17 +953,23 @@ extern "C" { } else if (entry_action->type == controller_entry_action_type_consider || entry_action->type == controller_entry_action_type_rule) { - status = controller_rules_increase(&thread_data.setting->rules); + f_thread_lock_write(&main.thread->lock.rule); + + status = controller_rules_increase(&main.setting->rules); + + f_thread_unlock(&main.thread->lock.rule); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, thread_data.thread); + 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; } const f_array_length_t id_rule_length = entry_action->parameters.array[0].used + entry_action->parameters.array[1].used + 1; char id_rule_name[id_rule_length + 1]; - const f_string_static_t id_rule = f_macro_string_static_t_initialize(id_rule_name, id_rule_length); + const f_string_static_t alias_rule = f_macro_string_static_t_initialize(id_rule_name, id_rule_length); memcpy(id_rule_name, entry_action->parameters.array[0].string, entry_action->parameters.array[0].used); memcpy(id_rule_name + entry_action->parameters.array[0].used + 1, entry_action->parameters.array[1].string, entry_action->parameters.array[1].used); @@ -953,25 +977,25 @@ extern "C" { id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s[0]; id_rule_name[id_rule_length] = 0; - f_thread_lock_read(&thread_data.thread->lock.rule); + f_thread_lock_read(&main.thread->lock.rule); - at = controller_rule_find_loaded(id_rule, thread_data); + at = controller_rule_find_loaded(alias_rule, main); if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, id_rule.string, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering"); + 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, "'.%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } // the rule is not yet loaded, ensure that it is loaded. - if (at == thread_data.setting->rules.used) { + if (at == main.setting->rules.used) { - f_thread_unlock(&thread_data.thread->lock.rule); + f_thread_unlock(&main.thread->lock.rule); // rule execution will re-use the existing cache, so save the current cache. const f_array_length_t cache_line_action = cache->action.line_action; @@ -989,9 +1013,9 @@ extern "C" { memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used); memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used); - f_thread_lock_write(&thread_data.thread->lock.rule); + f_thread_lock_write(&main.thread->lock.rule); - status = controller_rule_read(id_rule, thread_data, cache, &thread_data.setting->rules.array[thread_data.setting->rules.used]); + status = controller_rule_read(alias_rule, main, cache, &main.setting->rules.array[main.setting->rules.used]); // restore cache. memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used); @@ -1011,45 +1035,31 @@ extern "C" { if (F_status_is_error(status)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } if (!simulate) { - f_thread_unlock(&thread_data.thread->lock.rule); + f_thread_unlock(&main.thread->lock.rule); break; } } else { - thread_data.setting->rules.used++; + main.setting->rules.used++; } - f_thread_unlock(&thread_data.thread->lock.rule); + f_thread_unlock(&main.thread->lock.rule); + } + else { + f_thread_unlock(&main.thread->lock.rule); } if (F_status_is_error_not(status) && entry_action->type == controller_entry_action_type_rule) { - - // rule execution will re-use the existing cache, so save the current cache. - const f_array_length_t cache_line_action = cache->action.line_action; - const f_array_length_t cache_line_item = cache->action.line_item; - - const f_array_length_t cache_name_action_used = cache->action.name_action.used; - const f_array_length_t cache_name_item_used = cache->action.name_item.used; - const f_array_length_t cache_name_file_used = 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->action.name_action.string, cache->action.name_action.used); - memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used); - memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used); - rule_options = 0; if (simulate) { @@ -1066,30 +1076,9 @@ extern "C" { if (entry_action->code & controller_entry_rule_code_asynchronous) { rule_options |= controller_rule_option_asynchronous; - - // @todo - //status = controller_rule_process_asynchronous(id_rule, controller_rule_action_type_start, rule_options, thread_data, cache); } - else { - // @todo - // status = controller_rule_process(id_rule, controller_rule_action_type_start, rule_options, thread_data, cache); - } - - // restore cache. - memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used); - memcpy(cache->action.name_item.string, cache_name_item, cache_name_item_used); - memcpy(cache->action.name_file.string, cache_name_file, cache_name_file_used); - cache->action.name_action.string[cache_name_action_used] = 0; - cache->action.name_item.string[cache_name_item_used] = 0; - cache->action.name_file.string[cache_name_file_used] = 0; - - cache->action.name_action.used = cache_name_action_used; - cache->action.name_item.used = cache_name_item_used; - cache->action.name_file.used = cache_name_file_used; - - cache->action.line_action = cache_line_action; - cache->action.line_item = cache_line_item; + 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; @@ -1111,71 +1100,73 @@ extern "C" { code = controller_string_stop_s; } - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Processing entry item action '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_timeout_s, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "' setting '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.important.before->string, code, thread_data.data->context.set.important.after->string); - fprintf(thread_data.data->output.stream, "' to '"); - fprintf(thread_data.data->output.stream, "%s%llu%s", thread_data.data->context.set.important.before->string, entry_action->number, thread_data.data->context.set.important.after->string); - fprintf(thread_data.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Processing entry item action '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_timeout_s, main.data->context.set.title.after->string); + fprintf(main.data->output.stream, "' setting '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, code, main.data->context.set.important.after->string); + fprintf(main.data->output.stream, "' to '"); + fprintf(main.data->output.stream, "%s%llu%s", main.data->context.set.important.before->string, entry_action->number, main.data->context.set.important.after->string); + fprintf(main.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } if (entry_action->code == controller_entry_timeout_code_kill) { - thread_data.setting->timeout_kill = entry_action->number; + main.setting->timeout_kill = entry_action->number; } else if (entry_action->code == controller_entry_timeout_code_start) { - thread_data.setting->timeout_start = entry_action->number; + main.setting->timeout_start = entry_action->number; } else if (entry_action->code == controller_entry_timeout_code_stop) { - thread_data.setting->timeout_stop = entry_action->number; + main.setting->timeout_stop = entry_action->number; } } else if (entry_action->type == controller_entry_action_type_failsafe) { - if (entry_action->number == 0 || entry_action->number >= thread_data.setting->entry.items.used) { + if (entry_action->number == 0 || entry_action->number >= main.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 (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sInvalid entry item index ", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, entry_action->number, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s detected.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sInvalid entry item index ", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, entry_action->number, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s detected.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } + f_thread_unlock(&main.thread->lock.entry); + return F_status_is_error(F_critical); } else { - thread_data.setting->failsafe_enabled = F_true; - thread_data.setting->failsafe_rule_id = entry_action->number; + main.setting->failsafe_enabled = F_true; + main.setting->failsafe_rule_id = entry_action->number; if (simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Processing entry item action '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_failsafe_s, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "' setting value to '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.important.before->string, thread_data.setting->entry.items.array[thread_data.setting->failsafe_rule_id].name.string, thread_data.data->context.set.important.after->string); - fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Processing entry item action '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_failsafe_s, main.data->context.set.title.after->string); + fprintf(main.data->output.stream, "' setting value to '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, main.setting->entry.items.array[main.setting->failsafe_rule_id].name.string, main.data->context.set.important.after->string); + fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } } } // for - if (thread_data.thread->signal) { + if (main.thread->signal) { status = F_signal; } @@ -1202,29 +1193,31 @@ extern "C" { cache->ats.used -= 2; cache->ats.array[at_j]++; - cache->action.line_item = thread_data.setting->entry.items.array[cache->ats.array[at_i]].line; + cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line; cache->action.name_item.used = 0; - status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); + status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); break; } } } // for + f_thread_unlock(&main.thread->lock.entry); + if (status == F_child || status == F_signal) { return status; } if (F_status_is_error_not(status) && simulate) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } return status; diff --git a/level_3/controller/c/private-controller.h b/level_3/controller/c/private-controller.h index f6f9a74..7e59ddd 100644 --- a/level_3/controller/c/private-controller.h +++ b/level_3/controller/c/private-controller.h @@ -90,8 +90,8 @@ extern "C" { * The length of the prefix path. * @param path_suffix_length * The length of the suffix path. - * @param thread_data - * The thread data. + * @param main + * The main data. * @param cache * The following within the cache is updated: * - name_file: The partial path of the file is inserted. @@ -114,7 +114,7 @@ extern "C" { * @see f_string_dynamic_terminate_after() */ #ifndef _di_controller_file_load_ - extern f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_file_load_ /** @@ -164,8 +164,8 @@ extern "C" { * * This does not do any locking or unlocking for the processs data, be sure to lock appropriately before and after calling this. * - * @param id - * The (rule) id to find. + * @param alias + * The Rule alias to find. * @param processs * The array of processes to. * @param at @@ -177,7 +177,7 @@ extern "C" { * F_true if there is a process found (address is stored in "at"). */ #ifndef _di_controller_find_process_ - f_status_t controller_find_process(const f_string_static_t id, const controller_processs_t processs, f_array_length_t *at) f_gcc_attribute_visibility_internal; + f_status_t controller_find_process(const f_string_static_t alias, const controller_processs_t processs, f_array_length_t *at) f_gcc_attribute_visibility_internal; #endif // _di_controller_find_process_ /** @@ -241,8 +241,8 @@ extern "C" { * * This does not do any locking or unlocking for the setting data, be sure to lock appropriately before and after calling this. * - * @param thread_data - * The thread data. + * @param main + * The main data. * @param cache * The cache. * @@ -254,14 +254,14 @@ extern "C" { * @see controller_file_pid_create() */ #ifndef _di_controller_perform_ready_ - extern f_status_t controller_perform_ready(controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_perform_ready(controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_perform_ready_ /** * Pre-process all items for the loaded entry. * - * @param thread_data - * The thread data. + * @param main + * The main data. * @param cache * The main/global cache to use. * @@ -282,14 +282,14 @@ extern "C" { * @see f_string_dynamic_terminate_after() */ #ifndef _di_controller_preprocess_entry_ - extern f_status_t controller_preprocess_entry(controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_preprocess_entry(controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_preprocess_entry_ /** * Process (execute) all items for the loaded entry. * - * @param thread_data - * The thread data. + * @param main + * The main data. * @param cache * The main/global cache to use. * @@ -306,7 +306,7 @@ extern "C" { * @see controller_string_dynamic_append_terminated() */ #ifndef _di_controller_process_entry_ - extern f_status_t controller_process_entry(controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_process_entry(controller_main_t main, controller_cache_t *cache) 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 7f42a22..e875493 100644 --- a/level_3/controller/c/private-entry.c +++ b/level_3/controller/c/private-entry.c @@ -91,7 +91,7 @@ extern "C" { #endif // _di_controller_entry_actions_increase_by_ #ifndef _di_controller_entry_actions_read_ - f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_thread_data_t thread_data, controller_cache_t *cache, controller_entry_actions_t *actions) { + f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_main_t main, controller_cache_t *cache, controller_entry_actions_t *actions) { f_status_t status = F_none; f_status_t status_action = F_none; @@ -119,7 +119,7 @@ extern "C" { } if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_extended_read", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "fll_fss_extended_read", F_true); return status; } @@ -127,7 +127,7 @@ extern "C" { status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true); return status; } @@ -137,7 +137,7 @@ extern "C" { status = controller_entry_actions_increase_by(cache->object_actions.used, actions); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_entry_actions_increase_by", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "controller_entry_actions_increase_by", F_true); return status; } @@ -167,7 +167,7 @@ extern "C" { 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(thread_data.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } @@ -176,7 +176,7 @@ extern "C" { 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(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); break; } @@ -199,14 +199,14 @@ extern "C" { actions->array[actions->used].type = controller_entry_action_type_timeout; } else { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - fprintf(thread_data.data->warning.to.stream, "%s%sUnknown entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); - fprintf(thread_data.data->warning.to.stream, "%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string); - f_print_dynamic(thread_data.data->warning.to.stream, cache->action.name_action); - fprintf(thread_data.data->warning.to.stream, "%s", thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); - - controller_entry_error_print_cache(thread_data.data->warning, cache->action); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + fprintf(main.data->warning.to.stream, "%s%sUnknown entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s); + fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string); + f_print_dynamic(main.data->warning.to.stream, cache->action.name_action); + fprintf(main.data->warning.to.stream, "%s", main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s'.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]); + + controller_entry_error_print_cache(main.data->warning, cache->action); } continue; @@ -237,15 +237,15 @@ extern "C" { if (cache->content_actions.array[i].used < at_least || cache->content_actions.array[i].used > at_most) { action->status = F_status_set_error(F_parameter); - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->action.name_action.string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' requires ", thread_data.data->error.context.before->string); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.name_action.string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' requires ", main.data->error.context.before->string); if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) { - fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->action.line_action, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s or more parameters.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.line_action, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s or more parameters.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } else { uint8_t parameters = 0; @@ -257,9 +257,9 @@ extern "C" { parameters = 2; } - fprintf(thread_data.data->error.to.stream, "exactly ", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%u%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, parameters, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s parameters.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "exactly ", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%u%s", main.data->error.context.after->string, main.data->error.notable.before->string, parameters, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s parameters.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } } } @@ -279,7 +279,7 @@ extern "C" { status = f_string_dynamics_increase_by(allocate, &action->parameters); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamics_increase_by", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamics_increase_by", F_true); action->status = status; @@ -297,7 +297,7 @@ extern "C" { status = f_string_dynamic_partial_append_nulless(cache->buffer_file, cache->content_actions.array[i].array[j], &action->parameters.array[j]); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); action->status = status; @@ -319,7 +319,7 @@ extern "C" { status = fll_path_canonical(action->parameters.array[0].string, &cache->buffer_path); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_path_canonical", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "fll_path_canonical", F_true); action->status = status; @@ -340,9 +340,9 @@ extern "C" { status_action = action->status; } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action must not have an empty string for a path (the first parameter).%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action must not have an empty string for a path (the first parameter).%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]); } } @@ -352,7 +352,7 @@ extern "C" { status = f_file_name_base(action->parameters.array[1].string, action->parameters.array[1].used, &cache->buffer_path); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_file_name_base", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_file_name_base", F_true); if (F_status_set_fine(status) == F_memory_not) { status_action = status; @@ -368,11 +368,11 @@ extern "C" { else { if (fl_string_dynamic_compare(action->parameters.array[1], cache->buffer_path) == F_equal_to_not) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { + if (main.data->error.verbosity != f_console_verbosity_quiet) { status = f_string_dynamic_terminate_after(&cache->buffer_path); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); action->status = status; @@ -383,12 +383,12 @@ extern "C" { break; } - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action second parameter '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[1].string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' must be a base path name, such as '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->buffer_path.string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action second parameter '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[1].string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' must be a base path name, such as '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->buffer_path.string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } action->status = F_status_set_error(F_parameter); @@ -406,9 +406,9 @@ extern "C" { status_action = action->status; } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action must not have an empty string for a rule name (the second parameter).%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action must not have an empty string for a rule name (the second parameter).%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]); } } @@ -432,17 +432,17 @@ extern "C" { } } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action third parameter (and beyond) must be one of '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_asynchronous_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s', '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_require_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s', or '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_wait_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' but instead has '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[j].string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action third parameter (and beyond) must be one of '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_asynchronous_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s', '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_require_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s', or '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_wait_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' but instead has '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[j].string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } } } // for @@ -455,11 +455,11 @@ extern "C" { status_action = action->status; } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action may not specify the reserved item '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_main_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action may not specify the reserved item '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_main_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } } } @@ -481,17 +481,17 @@ extern "C" { status_action = action->status; } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action must have one of '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_kill_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s', '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_start_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s', or '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_stop_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' but instead has '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[0].string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action must have one of '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_kill_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s', '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_start_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s', or '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_stop_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' but instead has '", main.data->error.context.before->string); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[0].string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } } @@ -511,17 +511,17 @@ extern "C" { } if (F_status_set_fine(status) == F_memory_not) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true); status_action = status; break; } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action parameter '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[1].string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' is not a valid supported number.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry item action parameter '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[1].string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' is not a valid supported number.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); } } } @@ -606,14 +606,14 @@ extern "C" { #endif // _di_controller_entry_items_increase_by_ #ifndef _di_controller_entry_read_ - f_status_t controller_entry_read(const f_string_static_t entry_name, controller_thread_data_t thread_data, controller_cache_t *cache) { + f_status_t controller_entry_read(const f_string_static_t entry_name, controller_main_t main, controller_cache_t *cache) { f_status_t status = F_none; // @fixme all printfs in this function and child functions now need to be using the print mutex. // @fixme this should lock the global rule mutex until all rules for the entry have been processed. - thread_data.setting->entry.status = F_known_not; - thread_data.setting->entry.items.used = 0; + main.setting->entry.status = F_known_not; + main.setting->entry.items.used = 0; cache->action.line_action = 0; cache->action.line_item = 0; @@ -650,7 +650,7 @@ extern "C" { cache->action.name_action.used = 0; cache->action.name_item.used = 0; - status = controller_file_load(controller_string_entries_s, entry_name, controller_string_entry_s, controller_string_entries_length, controller_string_entry_length, thread_data, cache); + status = controller_file_load(controller_string_entries_s, entry_name, controller_string_entry_s, controller_string_entries_length, controller_string_entry_length, main, cache); if (F_status_is_error_not(status)) { if (cache->buffer_file.used) { @@ -659,24 +659,24 @@ extern "C" { status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments); if (F_status_is_error(status)) { - controller_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true, thread_data.thread); + controller_error_print(main.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true, main.thread); } else { status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file); if (F_status_is_error(status)) { - controller_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, thread_data.thread); + controller_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, main.thread); } } } else { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe entry file is empty.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe entry file is empty.%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } status = F_status_set_error(F_data_not); @@ -684,10 +684,10 @@ extern "C" { } if (F_status_is_error_not(status) && cache->object_items.used) { - status = controller_entry_items_increase_by(cache->object_items.used, &thread_data.setting->entry.items); + status = controller_entry_items_increase_by(cache->object_items.used, &main.setting->entry.items); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true); } else { @@ -702,7 +702,7 @@ extern "C" { for (; i < cache->object_items.used; ++i) { - if (thread_data.thread->signal) { + if (main.thread->signal) { return F_signal; } @@ -729,43 +729,43 @@ extern "C" { cache->action.name_action.used = 0; cache->action.name_item.used = 0; - status = controller_entry_items_increase_by(controller_default_allocation_step, &thread_data.setting->entry.items); + status = controller_entry_items_increase_by(controller_default_allocation_step, &main.setting->entry.items); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true); break; } 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(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_partial_append_terminated", F_true); + fll_error_print(main.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->action.line_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } cache->action.line_item++; - for (j = (code & 0x1) ? 1 : 0; j < thread_data.setting->entry.items.used; ++j) { + for (j = (code & 0x1) ? 1 : 0; j < main.setting->entry.items.used; ++j) { - if (fl_string_dynamic_compare(thread_data.setting->entry.items.array[j].name, cache->action.name_item) == F_equal_to) { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (fl_string_dynamic_compare(main.setting->entry.items.array[j].name, cache->action.name_item) == F_equal_to) { + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->warning.to.stream, "%s%sIgnoring duplicate entry item '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); - fprintf(thread_data.data->warning.to.stream, "%s%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, cache->action.name_file.string, thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->warning.to.stream, "%s%sIgnoring duplicate entry item '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s); + fprintf(main.data->warning.to.stream, "%s%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, cache->action.name_file.string, main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s'.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->warning, cache->action); + controller_entry_error_print_cache(main.data->warning, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } code |= 0x2; @@ -782,39 +782,39 @@ extern "C" { at = 0; - if (!thread_data.setting->entry.items.used) { - thread_data.setting->entry.items.used = 1; + if (!main.setting->entry.items.used) { + main.setting->entry.items.used = 1; } } - else if (thread_data.setting->entry.items.used) { - at = thread_data.setting->entry.items.used++; + else if (main.setting->entry.items.used) { + at = main.setting->entry.items.used++; } else { // skip position 0, which is reserved for "main". - thread_data.setting->entry.items.array[0].name.used = 0; + main.setting->entry.items.array[0].name.used = 0; at = 1; - thread_data.setting->entry.items.used = 2; + main.setting->entry.items.used = 2; } - thread_data.setting->entry.items.array[at].line = cache->action.line_item; + main.setting->entry.items.array[at].line = cache->action.line_item; - status = controller_string_dynamic_append_terminated(cache->action.name_item, &thread_data.setting->entry.items.array[at].name); + status = controller_string_dynamic_append_terminated(cache->action.name_item, &main.setting->entry.items.array[at].name); if (F_status_is_error(status)) { - controller_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); break; } - status = controller_entry_actions_read(*range, thread_data, cache, &thread_data.setting->entry.items.array[at].actions); + status = controller_entry_actions_read(*range, main, cache, &main.setting->entry.items.array[at].actions); if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); if (F_status_set_fine(status) == F_memory_not) { break; @@ -827,15 +827,15 @@ extern "C" { cache->action.name_item.used = 0; if (!(code & 0x1)) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe required entry item '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_main_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' was not found.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe required entry item '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_main_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' was not found.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } status = F_status_set_error(F_found_not); @@ -849,15 +849,15 @@ extern "C" { // 0x1 = missing or not, 0x2 = one or more missing. uint8_t missing = 0; - for (i = 0; i < thread_data.setting->entry.items.used; ++i) { + for (i = 0; i < main.setting->entry.items.used; ++i) { - for (j = 0; j < thread_data.setting->entry.items.array[i].actions.used; ++j) { + for (j = 0; j < main.setting->entry.items.array[i].actions.used; ++j) { - if (thread_data.thread->signal) { + if (main.thread->signal) { return F_signal; } - action = &thread_data.setting->entry.items.array[i].actions.array[j]; + action = &main.setting->entry.items.array[i].actions.array[j]; // only process actions that don't already have an error. if (F_status_is_error(action->status)) continue; @@ -865,9 +865,9 @@ extern "C" { if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) { missing |= 0x1; - for (k = 0; k < thread_data.setting->entry.items.used; ++k) { + for (k = 0; k < main.setting->entry.items.used; ++k) { - if (fl_string_dynamic_compare(action->parameters.array[0], thread_data.setting->entry.items.array[k].name) == F_equal_to) { + if (fl_string_dynamic_compare(action->parameters.array[0], main.setting->entry.items.array[k].name) == F_equal_to) { if (missing & 0x1) { missing -= 0x1; } @@ -880,33 +880,33 @@ extern "C" { missing |= 0x2; cache->action.line_action = action->line; - cache->action.line_item = thread_data.setting->entry.items.array[i].line; + cache->action.line_item = main.setting->entry.items.array[i].line; - status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[i].name, &cache->action.name_item); + status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[i].name, &cache->action.name_item); if (F_status_is_error(status)) { - controller_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread); + controller_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread); break; } - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe required entry item '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[0].string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' does not exist.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe required entry item '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[0].string, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' does not exist.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]); - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } action->number = 0; action->status = controller_status_simplify(F_found_not); - // @fixme review how thread_data.setting->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). - //thread_data.setting->entry.status = controller_status_simplify(F_found_not); + // @fixme review how main.setting->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). + //main.setting->entry.status = controller_status_simplify(F_found_not); cache->action.name_action.used = 0; cache->action.name_item.used = 0; @@ -920,8 +920,8 @@ extern "C" { // the error is already fully printed and the entry status is already assigned, so immediately exit. if (missing & 0x2) { - // @fixme review how thread_data.setting->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 thread_data.setting->entry.status; + // @fixme review how main.setting->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 main.setting->entry.status; } } } @@ -929,15 +929,15 @@ extern "C" { } if (F_status_is_error(status)) { - controller_entry_error_print_cache(thread_data.data->error, cache->action); + controller_entry_error_print_cache(main.data->error, cache->action); - thread_data.setting->entry.status = controller_status_simplify(F_status_set_fine(status)); + main.setting->entry.status = controller_status_simplify(F_status_set_fine(status)); } else { - thread_data.setting->entry.status = F_none; + main.setting->entry.status = F_none; } - return thread_data.setting->entry.status; + return main.setting->entry.status; } #endif // _di_controller_entry_read_ diff --git a/level_3/controller/c/private-entry.h b/level_3/controller/c/private-entry.h index e4a8977..1fb516c 100644 --- a/level_3/controller/c/private-entry.h +++ b/level_3/controller/c/private-entry.h @@ -65,8 +65,8 @@ extern "C" { * * @param content_range * The range in the list buffer representing the content. - * @param thread_data - * The thread data. + * @param main + * The main data. * @param cache * A structure for containing and caching relevant data. * @param actions @@ -94,7 +94,7 @@ extern "C" { * @see fll_fss_extended_read() */ #ifndef _di_controller_entry_actions_read_ - extern f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_thread_data_t thread_data, controller_cache_t *cache, controller_entry_actions_t *actions) f_gcc_attribute_visibility_internal; + extern f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_main_t main, controller_cache_t *cache, controller_entry_actions_t *actions) f_gcc_attribute_visibility_internal; #endif // _di_controller_entry_actions_read_ /** @@ -170,11 +170,11 @@ extern "C" { * The string identifying the entry. * This is constructed from the path parts to the file without the file extension and without the settings directory prefix. * "/etc/controller/entries/example/my.entry" would have a rule id of "example/my". - * @param thread_data - * The thread data. + * @param main + * The main data. * @param cache * The cache for the specific thread. - * This should be the cache thread_data.thread->asynchronouss.array[thread_data.id].cache. + * This should be the cache main.thread->asynchronouss.array[main.id].cache. * * @return * F_none on success. @@ -206,7 +206,7 @@ extern "C" { * @see fll_fss_basic_list_read() */ #ifndef _di_controller_entry_read_ - extern f_status_t controller_entry_read(const f_string_static_t entry_name, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + extern f_status_t controller_entry_read(const f_string_static_t entry_name, controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_entry_read_ #ifdef __cplusplus diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 7c8e729..317db16 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -31,13 +31,33 @@ extern "C" { } #endif // _di_controller_rule_action_method_name_ +#ifndef _di_controller_rule_find_ + f_status_t controller_rule_find(const f_string_static_t alias, const controller_rules_t rules, f_array_length_t *at) { + + if (!alias.used) return F_none; + if (!rules.used) return F_false; + + 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; + return F_true; + } + } // for + + return F_false; + } +#endif // _di_controller_rule_find_ + #ifndef _di_controller_rule_parameters_read_ f_status_t controller_rule_parameters_read(const controller_data_t data, const f_string_static_t buffer, f_fss_object_t *object, f_fss_content_t *content, f_string_dynamics_t *parameters) { + f_status_t status = F_none; parameters->used = 0; if (object && object->start <= object->start) { + status = f_string_dynamics_increase(parameters); if (F_status_is_error(status)) { @@ -65,6 +85,7 @@ extern "C" { } if (content && content->used) { + for (f_array_length_t i = 0; i < content->used; ++i) { if (content->array[i].start > content->array[i].start) continue; @@ -181,6 +202,7 @@ extern "C" { #ifndef _di_controller_rule_action_read_ f_status_t controller_rule_action_read(const controller_data_t data, const uint8_t type, const uint8_t method, controller_cache_t *cache, controller_rule_item_t *item, controller_rule_actions_t *actions, f_string_range_t *range) { + f_status_t status = F_none; if (method == controller_rule_action_method_extended_list) { @@ -217,6 +239,7 @@ extern "C" { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamics_increase", F_true); } else { + actions->array[actions->used].type = type; actions->array[actions->used].line = cache->action.line_action; actions->array[actions->used].parameters.used = 0; @@ -249,17 +272,18 @@ extern "C" { fll_error_print(data.error, F_status_set_fine(status), "fll_fss_extended_read", F_true); } else { + status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_item); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true); } else { + f_array_length_t i = 0; f_array_length_t j = 0; for (; i < cache->object_actions.used; ++i) { - status = controller_rule_actions_increase_by(controller_default_allocation_step, actions); if (F_status_is_error(status)) { @@ -304,6 +328,7 @@ extern "C" { } } else { + cache->content_action.used = 0; cache->delimits.used = 0; @@ -333,7 +358,6 @@ extern "C" { actions->array[actions->used].status = F_known_not; for (f_array_length_t i = 0; i < cache->content_action.used; ++i) { - status = f_string_dynamic_partial_mash_nulless(f_string_space_s, f_string_space_length, cache->buffer_item, cache->content_action.array[i], &actions->array[actions->used].parameters.array[0]); if (F_status_is_error(status)) break; } // for @@ -360,6 +384,7 @@ extern "C" { fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true); } else { + actions->array[actions->used].type = type; actions->array[actions->used].line += ++item->line; actions->array[actions->used].parameters.used = 0; @@ -400,6 +425,7 @@ extern "C" { #ifndef _di_controller_rule_copy_ f_status_t controller_rule_copy(const controller_rule_t source, controller_rule_t *destination) { + f_status_t status = F_none; destination->timeout_kill = source.timeout_kill; @@ -414,7 +440,7 @@ extern "C" { destination->timestamp.seconds = source.timestamp.seconds; destination->timestamp.nanoseconds = source.timestamp.nanoseconds; - destination->id.used = 0; + destination->alias.used = 0; destination->name.used = 0; destination->path.used = 0; destination->script.used = 0; @@ -435,8 +461,8 @@ extern "C" { destination->items.used = 0; - if (source.id.used) { - status = f_string_dynamic_append(source.id, &destination->id); + if (source.alias.used) { + status = f_string_dynamic_append(source.alias, &destination->alias); if (F_status_is_error(status)) return status; } @@ -617,8 +643,8 @@ extern "C" { if (status == F_control_group || status == F_limit || status == F_processor || status == F_schedule) { fprintf(output.to.stream, "%s' failed due to a failure to setup the '", output.context.before->string); - fprintf(output.to.stream, "%s%s", output.context.after->string, output.notable.before->string); + if (status == F_control_group) { fprintf(output.to.stream, "%s", controller_string_control_group_s); } @@ -631,6 +657,7 @@ extern "C" { else if (status == F_schedule) { fprintf(output.to.stream, "%s", controller_string_scheduler_s); } + fprintf(output.to.stream, "%s", output.notable.after->string); fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]); } @@ -671,7 +698,8 @@ extern "C" { #endif // _di_controller_rule_error_print_need_want_wish_ #ifndef _di_controller_rule_execute_ - f_status_t controller_rule_execute(const uint8_t type, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) { + 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 status = F_none; f_status_t success = F_false; @@ -721,7 +749,7 @@ extern "C" { status = fll_control_group_prepare(rule->control_group); if (F_status_is_error(status)) { - controller_error_print(thread_data.data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, thread_data.thread); + 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); return status; @@ -762,7 +790,7 @@ extern "C" { status = fl_environment_load_names(rule->environment, &environment); if (F_status_is_error(status)) { - controller_error_print(thread_data.data->error, F_status_set_fine(status), "fl_environment_load_names", F_true, thread_data.thread); + 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); return status; @@ -770,7 +798,7 @@ extern "C" { for (i = 0; i < rule->items.used; ++i) { - if (thread_data.thread->signal) { + if (main.thread->signal) { status = F_signal; break; } @@ -779,7 +807,7 @@ extern "C" { for (j = 0; j < rule->items.array[i].actions.used; ++j) { - if (thread_data.thread->signal) { + if (main.thread->signal) { status = F_signal; break; } @@ -799,7 +827,7 @@ extern "C" { 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, thread_data, rule); + 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); if (status == F_child) break; @@ -812,13 +840,14 @@ extern "C" { success = F_true; } 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]; 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, thread_data, rule); + 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); if (status == F_child) break; @@ -836,7 +865,7 @@ extern "C" { 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, thread_data, rule); + 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); if (status == F_child) break; @@ -850,15 +879,15 @@ extern "C" { } else { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s, thread_data.data->warning.context.after->string, f_string_eol_s[0]); + 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(thread_data.data->warning, cache->action, F_true); + controller_rule_error_print(main.data->warning, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } rule->items.array[i].actions.array[j].status = F_ignore; @@ -897,31 +926,30 @@ extern "C" { #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_thread_data_t thread_data, controller_rule_t *rule) { + 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 status = F_none; int result = 0; pid_t id_process = 0; if (options & controller_rule_option_simulate) { + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Simulating execution of '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, thread_data.data->context.reset.string); - fprintf(thread_data.data->output.stream, "' with the arguments: '%s", thread_data.data->context.important.string); + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Simulating execution of '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, main.data->context.reset.string); + fprintf(main.data->output.stream, "' with the arguments: '%s", main.data->context.important.string); for (f_array_length_t i = program ? 0 : 1; i < arguments.used; ++i) { - fprintf(thread_data.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string); + fprintf(main.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string); } // for - fprintf(thread_data.data->output.stream, "%s' from '", thread_data.data->context.reset.string); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->context.reset.string); - fprintf(thread_data.data->output.stream, "%s'.%c", thread_data.data->context.reset.string, f_string_eol_s[0]); + 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'.%c", main.data->context.reset.string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } // sleep for less than a second to better show simulation of synchronous vs asynchronous. @@ -941,13 +969,13 @@ extern "C" { 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. - thread_data.thread->asynchronouss.array[thread_data.id].child = id_process; + main.thread->asynchronouss.array[main.id].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. - thread_data.thread->asynchronouss.array[thread_data.id].child = 0; + main.thread->asynchronouss.array[main.id].child = 0; // this must explicitly check for 0 (as opposed to checking (!result)). if (!WIFEXITED(result)) { @@ -977,19 +1005,19 @@ extern "C" { if (F_status_is_error(status)) { status = F_status_set_fine(status); - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) { - controller_rule_error_print_execute(thread_data.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); + controller_rule_error_print_execute(main.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); } else if (status == F_file_found_not) { - controller_rule_error_print_execute_not_found(thread_data.data->error, F_false, program); + controller_rule_error_print_execute_not_found(main.data->error, F_false, program); } else { - fll_error_print(thread_data.data->error, status, "fll_execute_program", F_true); + fll_error_print(main.data->error, status, "fll_execute_program", F_true); } - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); status = F_status_set_error(status); } @@ -999,7 +1027,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_thread_data_t thread_data, controller_rule_t *rule) { + 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 status = F_none; int result = 0; @@ -1014,23 +1042,24 @@ extern "C" { if (options & controller_rule_option_simulate) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "Simulating execution of '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, thread_data.data->context.reset.string); - fprintf(thread_data.data->output.stream, "' with the arguments: '%s", thread_data.data->context.important.string); + f_thread_mutex_lock(&main.thread->lock.print); + + fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->output.stream, "Simulating execution of '"); + fprintf(main.data->output.stream, "%s%s%s", main.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, main.data->context.reset.string); + fprintf(main.data->output.stream, "' with the arguments: '%s", main.data->context.important.string); for (f_array_length_t i = program ? 0 : 1; i < arguments.used; ++i) { - fprintf(thread_data.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string); + fprintf(main.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string); } // for - fprintf(thread_data.data->output.stream, "%s' from '", thread_data.data->context.reset.string); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->context.reset.string); - fprintf(thread_data.data->output.stream, "%s'.%c", thread_data.data->context.reset.string, f_string_eol_s[0]); + 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'.%c", main.data->context.reset.string, f_string_eol_s[0]); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } // sleep for less than a second to better show simulation of synchronous vs asynchronous. @@ -1050,13 +1079,13 @@ extern "C" { 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. - thread_data.thread->asynchronouss.array[thread_data.id].child = id_process; + main.thread->asynchronouss.array[main.id].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. - thread_data.thread->asynchronouss.array[thread_data.id].child = 0; + main.thread->asynchronouss.array[main.id].child = 0; // this must explicitly check for 0 (as opposed to checking (!result)). if (!WIFEXITED(result)) { @@ -1065,6 +1094,7 @@ extern "C" { } if (F_status_is_error(status)) { + status = F_status_set_fine(status); if (status == F_child || status == F_capability || status == F_group || status == F_nice || status == F_user) { @@ -1084,21 +1114,22 @@ extern "C" { } if (F_status_is_error(status)) { + status = F_status_set_fine(status); - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) { - controller_rule_error_print_execute(thread_data.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); + controller_rule_error_print_execute(main.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); } else if (status == F_file_found_not) { - controller_rule_error_print_execute_not_found(thread_data.data->error, F_false, program); + controller_rule_error_print_execute_not_found(main.data->error, F_false, program); } else { - fll_error_print(thread_data.data->error, status, "fll_execute_program", F_true); + fll_error_print(main.data->error, status, "fll_execute_program", F_true); } - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); return F_status_set_error(status); } @@ -1109,48 +1140,35 @@ extern "C" { } #endif // _di_controller_rule_execute_pid_with_ -// @todo consider changing this to accept "at" as an argument and returning status so that error status can be returned. -#ifndef _di_controller_rule_find_loaded_ - f_array_length_t controller_rule_find_loaded(const f_string_static_t rule_id, controller_thread_data_t thread_data) { - - f_array_length_t i = thread_data.setting->rules.used; - - for (; i; --i) { - if (fl_string_dynamic_compare(rule_id, thread_data.setting->rules.array[i].id) == F_equal_to) return i; - } // for - - return thread_data.setting->rules.used; - } -#endif // _di_controller_rule_find_loaded_ - #ifndef _di_controller_rule_id_construct_ - f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *id) { + f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *alias) { + f_status_t status = F_none; - id->used = 0; + alias->used = 0; - status = f_string_dynamic_partial_append_nulless(source, directory, id); + status = f_string_dynamic_partial_append_nulless(source, directory, alias); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); return status; } - status = f_string_append(f_path_separator_s, f_path_separator_length, id); + status = f_string_append(f_path_separator_s, f_path_separator_length, alias); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_append", F_true); return status; } - status = f_string_dynamic_partial_append_nulless(source, basename, id); + status = f_string_dynamic_partial_append_nulless(source, basename, alias); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true); return status; } - status = f_string_dynamic_terminate_after(id); + status = f_string_dynamic_terminate_after(alias); if (F_status_is_error(status)) { fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); @@ -1162,6 +1180,7 @@ extern "C" { #ifndef _di_controller_rule_item_read_ f_status_t controller_rule_item_read(const controller_data_t data, controller_cache_t *cache, controller_rule_item_t *item) { + f_status_t status = F_none; f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_item.used); @@ -1276,6 +1295,7 @@ extern "C" { if (multiple) { if (type == controller_rule_action_type_create || type == controller_rule_action_type_group || type == controller_rule_action_type_use || type == controller_rule_action_type_user) { + 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%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); @@ -1459,6 +1479,7 @@ extern "C" { #ifndef _di_controller_rule_path_ f_status_t controller_rule_path(const controller_data_t data, const controller_setting_t setting, const f_string_static_t path_directory, const f_string_static_t path_name, f_string_dynamic_t *path) { + f_status_t status = F_none; path->used = 0; @@ -1528,9 +1549,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 f_array_length_t at_process, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) { - - // @todo need to update accordingly with new parameters "rule" and "at_process". + 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) { switch (action) { case controller_rule_action_type_freeze: @@ -1546,71 +1565,24 @@ extern "C" { default: - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sUnsupported action type '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_rule_action_type_name(action), thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' while attempting to execute rule.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sUnsupported action type '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + 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(thread_data.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } return F_status_set_error(F_parameter); } - if (index >= thread_data.setting->rules.used) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - fll_error_print(thread_data.data->error, F_parameter, "controller_rule_process", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); - - f_thread_mutex_unlock(&thread_data.thread->lock.print); - - return F_status_set_error(F_parameter); - } - f_status_t status = F_none; - f_macro_array_lengths_t_increase_by(status, thread_data.thread->asynchronouss.array[thread_data.id].stack, controller_default_allocation_step) - - if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); - - f_thread_mutex_unlock(&thread_data.thread->lock.print); - - return status; - } - - f_array_length_t i = 0; - - for (; i < thread_data.thread->asynchronouss.array[thread_data.id].stack.used; ++i) { - - if (thread_data.thread->asynchronouss.array[thread_data.id].stack.array[i] == index) { - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe rule '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.setting->rules.array[i].name.string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); - - controller_rule_error_print(thread_data.data->error, cache->action, F_true); - - f_thread_mutex_unlock(&thread_data.thread->lock.print); - } - - // never continue on recursion errors even in simulate mode. - return F_status_set_error(F_recurse); - } - } - cache->action.name_action.used = 0; cache->action.name_item.used = 0; cache->action.name_file.used = 0; @@ -1622,25 +1594,25 @@ extern "C" { } if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); return status; } - status = f_string_dynamic_append(thread_data.setting->rules.array[index].id, &cache->action.name_file); + status = f_string_dynamic_append(rule.alias, &cache->action.name_file); if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); return status; } @@ -1652,12 +1624,12 @@ extern "C" { } if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); return status; } @@ -1665,41 +1637,30 @@ extern "C" { status = f_string_dynamic_terminate_after(&cache->action.name_file); if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); return status; } - thread_data.thread->asynchronouss.array[thread_data.id].stack.array[thread_data.thread->asynchronouss.array[thread_data.id].stack.used++] = index; - - controller_rule_t *rule = &thread_data.setting->rules.array[index]; - - if ((options & controller_rule_option_simulate) && thread_data.data->parameters[controller_parameter_validate].result == f_console_result_found) { - // @fixme the cache should probably store a rule type and then that can used instead of calling controller_rule_copy() here. - controller_rule_t rule_simulate = controller_rule_t_initialize; - - status = controller_rule_copy(rule, &rule_simulate); - - if (F_status_is_error(status)) { - controller_rule_delete_simple(&rule_simulate); - - return status; - } - - controller_rule_simulate(controller_rule_action_type_start, options, thread_data, cache, &rule_simulate); - - controller_rule_delete_simple(&rule_simulate); + 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); } + f_array_length_t i = 0; + { f_array_length_t j = 0; f_array_length_t k = 0; - f_array_length_t at = 0; + f_array_length_t id_rule = 0; + f_array_length_t id_process = 0; + + controller_rule_t *rule_other = 0; + controller_process_t *process_other = 0; f_string_dynamics_t * const dynamics[] = { &rule->need, @@ -1713,174 +1674,157 @@ extern "C" { "wished for", }; + // i==0 is need, i==1 is want, i==2 is wish. + // loop through all dependencies: wait for depedency, execute dependency, fail due to missing required dependency, or skip unrequired missing dependencies. for (i = 0; i < 3; ++i) { for (j = 0; j < dynamics[i]->used; ++j) { - at = controller_rule_find_loaded(*thread_data.data, *thread_data.setting, dynamics[i]->array[j]); - if (at == thread_data.setting->rules.used) { + f_thread_lock_read(&main.thread->lock.rule); + + 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); + } + + if (status != F_true) { + id_rule = main.setting->rules.used; + if (i == 0) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "was not found"); + 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); + + f_thread_mutex_unlock(&main.thread->lock.print); status = F_status_set_error(F_found_not); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + if (!(options & controller_rule_option_simulate)) { + f_thread_unlock(&main.thread->lock.rule); - if (!(options & controller_rule_option_simulate)) break; + break; + } } else { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "was not found"); - controller_rule_error_print(thread_data.data->warning, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } } - if (F_status_is_error_not(status) && at < thread_data.setting->rules.used) { + if (status == F_true && id_rule < main.setting->rules.used) { + f_thread_lock_read(&main.thread->lock.process); - f_thread_mutex_lock(&thread_data.setting->rules.array[at].lock); + process_other = &main.thread->processs->array[id_process]; - while (thread_data.enabled && thread_data.setting->rules.array[at].status == F_known_not) { - f_thread_condition_wait(&thread_data.setting->rules.array[at].wait, &thread_data.setting->rules.array[at].lock); - } // while + f_thread_lock_read(&process_other->active); + f_thread_lock_read(&process_other->lock); - if (!thread_data.enabled) { - f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); - f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); + if (process_other->status == F_known_not && (process_other->state == controller_process_state_active || process_other->state == controller_process_state_busy)) { + f_thread_unlock(&process_other->lock); + f_thread_condition_wait(&process_other->wait, &process_other->running); - status = F_signal; - break; + // always pass the signal along when done waiting. + f_thread_condition_signal(&process->wait); + f_thread_mutex_unlock(&process->running); + } + else { + f_thread_unlock(&process_other->lock); } - // when the status is unknown, then the rule has not been executed, so attempt to execute it. - if (thread_data.setting->rules.array[at].status == F_known_not) { - - f_macro_array_lengths_t_increase_by(status, thread_data.thread->asynchronouss.array[thread_data.id].stack, controller_default_allocation_step) - - if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); - - f_thread_mutex_unlock(&thread_data.thread->lock.print); - - f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); - f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); - - // 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->action.line_action; - const f_array_length_t cache_line_item = cache->action.line_item; + if (!main.thread->enabled) { + f_thread_unlock(&main.thread->lock.process); + f_thread_unlock(&process_other->active); + f_thread_unlock(&main.thread->lock.rule); - const f_array_length_t cache_name_action_used = cache->action.name_action.used; - const f_array_length_t cache_name_item_used = cache->action.name_item.used; - const f_array_length_t cache_name_file_used = cache->action.name_file.used; + status = F_signal; + break; + } - char cache_name_action[cache_name_action_used]; - char cache_name_item[cache_name_item_used]; - char cache_name_file[cache_name_file_used]; + f_thread_unlock(&main.thread->lock.process); - memcpy(cache_name_action, cache->action.name_action.string, cache->action.name_action.used); - memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used); - memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used); + rule_other = &main.setting->rules.array[id_rule]; - // @fixme the cache should probably store a rule type and then that can used instead of calling controller_rule_copy(), which would need to be copied here just like the other cache properties. + // 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) { - // recursive rule processing is to always be synchronous. - status = controller_rule_process(at, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, thread, 0); + 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); if (status == F_child || status == F_signal) { - f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); - f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); + f_thread_unlock(&process_other->active); + f_thread_unlock(&main.thread->lock.rule); break; } - // restore cache. - memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used); - memcpy(cache->action.name_item.string, cache_name_item, cache_name_item_used); - memcpy(cache->action.name_file.string, cache_name_file, cache_name_file_used); - - cache->action.name_action.string[cache_name_action_used] = 0; - cache->action.name_item.string[cache_name_item_used] = 0; - - cache->action.name_action.used = cache_name_action_used; - cache->action.name_item.used = cache_name_item_used; - cache->action.name_file.used = cache_name_file_used; - - cache->action.line_action = cache_line_action; - 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) { + f_thread_mutex_lock(&main.thread->lock.print); - f_thread_mutex_lock(&thread_data.thread->lock.print); - - controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "failed during execution"); - controller_rule_error_print(thread_data.data->error, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) { - f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); - f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); + f_thread_unlock(&process_other->active); + f_thread_unlock(&main.thread->lock.rule); break; } } else { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution"); - controller_rule_error_print(thread_data.data->warning, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } } } - f_thread_condition_signal(&thread_data.setting->rules.array[at].wait); - f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock); - - if (F_status_is_error(thread_data.setting->rules.array[at].status)) { + f_thread_unlock(&process_other->active); + if (F_status_is_error(rule_other->status)) { if (i == 0 || i == 1) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); - controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "is in a failed state"); + 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(thread_data.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); - if (!(options & controller_rule_option_simulate)) break; + if (!(options & controller_rule_option_simulate)) { + f_thread_unlock(&main.thread->lock.rule); + break; + } } else { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + f_thread_mutex_lock(&main.thread->lock.print); - controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state"); - controller_rule_error_print(thread_data.data->warning, cache->action, F_true); + 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); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } } } } + + f_thread_unlock(&main.thread->lock.rule); } // for if (status == F_child || status == F_signal) break; @@ -1893,15 +1837,14 @@ extern "C" { return status; } - if (!thread_data.enabled) { + if (!main.thread->enabled) { return F_signal; } - // @fixme changing design, "wait" will be a distinct thing not associated with individual rules. this will be in its own process function. if (!(options & controller_rule_option_wait) && F_status_is_error_not(status)) { - controller_rule_wait_all(thread); + controller_rule_wait_all(main); - if (!thread_data.enabled) { + if (!main.thread->enabled) { return F_signal; } } @@ -1914,11 +1857,11 @@ extern "C" { f_array_length_t j = 0; - for (i = 0; i < rule->items.used; ++i) { + for (i = 0; i < rule.items.used; ++i) { - for (j = 0; j < rule->items.array[i].actions.used; ++j) { + for (j = 0; j < rule.items.array[i].actions.used; ++j) { - if (rule->items.array[i].actions.array[j].type == action) { + if (rule.items.array[i].actions.array[j].type == action) { missing = F_false; break; } @@ -1926,20 +1869,19 @@ extern "C" { } // for if (missing) { + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->error.to.stream, "%s%sThe rule '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' has no '", thread_data.data->error.context.before->string); - fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_rule_action_type_name(action).string, thread_data.data->error.notable.after->string); - fprintf(thread_data.data->error.to.stream, "%s' action to execute.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe rule '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, rule.name.used ? rule.name.string : f_string_empty_s, main.data->error.notable.after->string); + fprintf(main.data->error.to.stream, "%s' has no '", main.data->error.context.before->string); + 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(thread_data.data->error, cache->action, F_true); + controller_rule_error_print(main.data->error, cache->action, F_true); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } status = F_status_set_error(F_parameter); @@ -1947,37 +1889,23 @@ extern "C" { } if (F_status_is_error_not(status)) { - // @fixme the cache should probably store a rule type and then that can used instead of calling controller_rule_copy() here. - controller_rule_t rule = controller_rule_t_initialize; - - status = controller_rule_copy(thread_data.setting->rules.array[index], &rule); - - if (F_status_is_error_not(status)) { - status = controller_rule_execute(action, options, thread_data, &cache, &rule); - - // @fixme there needs to be a new rule structure for storing the status state and the rule data, for any given execution (this should also be locking and unlocking). - thread_data.setting->rules.array[index].status = rule.status; - } - - controller_rule_delete_simple(&rule); + // @todo make sure to update this function. + status = controller_rule_execute(rule, action, options, main, process); if (status == F_child) { return F_child; } - if (!thread_data.enabled) { + if (!main.thread->enabled) { return F_signal; } if (F_status_is_error(status)) { - controller_rule_error_print_locked(thread_data.data->error, cache->action, F_true, thread); + controller_rule_error_print_locked(main.data->error, cache->action, F_true, thread); } } } - // remove this rule off the stack. - thread_data.thread->asynchronouss.array[thread_data.id].stack.used--; - if (F_status_is_error(status)) { return status; } @@ -1986,178 +1914,290 @@ extern "C" { } #endif // _di_controller_rule_process_ -#ifndef _di_controller_rule_process_do_ - f_status_t controller_rule_process_do(const controller_rule_t rule, const f_array_length_t at_process, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) { +#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); + + if (!main.thread->enabled) { + f_thread_mutex_unlock(&main.thread->lock.process); + + return F_signal; + } + + f_status_t status = F_none; - f_array_length_t at_process = 0; + controller_process_t *process = 0; - f_thread_lock_read(&thread_data.thread->lock.process); + { + f_array_length_t id_process = 0; - if (controller_find_process(rule_id, *thread_data.processs, &at_process) == F_false) { - f_thread_unlock(&thread_data.thread->lock.process); - f_thread_lock_write(&thread_data.thread->lock.process); + if (controller_find_process(alias_rule, *main.thread->processs, &id_process) != F_true) { + status = F_status_set_error(F_found_not); + } - status = controller_processs_increase(thread_data.processs); + f_thread_unlock(&main.thread->lock.process); if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, thread_data.thread); + + 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]); + + controller_entry_error_print_cache(main.data->error, cache->action); + + f_thread_mutex_unlock(&main.thread->lock.print); + } + + return status; } - else { - at_process = thread_data.processs->used; + + f_thread_lock_write(&main.thread->processs->array[id_process].lock); + + process = &main.thread->processs->array[id_process]; + + // 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) { + f_thread_unlock(&process->lock); + + return F_busy; } + + f_thread_lock_read(&process->active); + + // the thread is done, so detach/close the thread. + if (process->state == controller_process_state_done) { + f_thread_detach(process->id_thread); + } + + process->id = id_process; } - f_thread_unlock(&thread_data.thread->lock.process); + process->main.data = main.data; + process->main.setting = main.setting; + process->main.thread = main.thread; - if (F_status_is_error_not(status)) { + process->state = controller_process_state_active; + process->action = action; + process->options = options; - // retrieve a copy of the rule and use that for the lifespan of the rule's execution within the designated process. - controller_rule_t rule = controller_rule_t_initialize; + f_macro_time_spec_t_clear(process->cache.timestamp) + f_macro_string_range_t_clear(process->cache.range_action) + + process->cache.ats.used = 0; + process->cache.stack.used = 0; + process->cache.comments.used = 0; + process->cache.delimits.used = 0; + process->cache.content_action.used = 0; + process->cache.content_actions.used = 0; + process->cache.content_items.used = 0; + process->cache.object_actions.used = 0; + process->cache.object_items.used = 0; + 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; - status = controller_rule_copy(thread_data.setting->rules.array[at], &rule); + process->stack.used = 0; - f_thread_unlock(&thread_data.thread->lock.rule); + 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) { + status = f_type_array_lengths_resize(process->stack.used, &process->stack); + } if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_rule_copy", F_true, thread_data.thread); + 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); } else { - status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, cache); + for (f_array_length_t i = 0; i < stack.used; ++i) { + process->stack.array[process->stack.used++] = stack.array[i]; + } // for + } + } + + if (F_status_is_error_not(status)) { + status = f_string_dynamic_append(process_data.thread->cache_action.name_action, &process->cache.action.name_action); - controller_rule_delete_simple(&rule); + if (F_status_is_error_not(status)) { + status = f_string_dynamic_append(process_data.thread->cache_action.name_file, &process->cache.action.name_file); + } - if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); + if (F_status_is_error_not(status)) { + status = f_string_dynamic_append(process_data.thread->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_cache(thread_data.data->error, cache->action); + f_thread_unlock(&process->lock); - f_thread_mutex_unlock(&thread_data.thread->lock.print); + if (F_status_is_error_not(status)) { + if (asynchronous) { + 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); } } + else { + status = controller_rule_process_do(F_false, process); + } } - } -#endif // _di_controller_rule_process_do_ -#ifndef _di_controller_rule_process_asynchronous_ - f_status_t controller_rule_process_asynchronous(const f_string_static_t id_rule, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) { + f_thread_unlock(&process->active); - f_thread_lock_read(&thread_data.lock.asynchronous); + if (F_status_is_error(status)) { + return status; + } - if (!thread_data.thread->enabled) { - f_thread_mutex_unlock(&thread_data.lock.asynchronous); + return F_none; + } +#endif // _di_controller_rule_process_begin_ - return F_signal; - } +#ifndef _di_controller_rule_process_do_ + f_status_t controller_rule_process_do(const bool asynchronous, controller_process_t *process) { - f_thread_mutex_unlock(&thread_data.lock.asynchronous); - f_thread_lock_write(&thread_data.lock.asynchronous); + f_thread_lock_read(&process->lock); - f_status_t status = controller_asynchronouss_increase(&thread_data.thread->asynchronouss); + 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 (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_asynchronouss_increase", F_true, thread_data.thread); + f_thread_lock_read(&main.thread->lock.process); - f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous); + if (!main.thread->enabled) { + f_thread_unlock(&process->lock); + f_thread_unlock(&main.thread->lock.process); - return status; + return F_signal; } - controller_asynchronous_t *asynchronous = &thread_data.thread->asynchronouss.array[thread_data.thread->asynchronouss.used++]; + f_thread_unlock(&main.thread->lock.process); + f_thread_lock_read(&process->active); + f_thread_mutex_lock(&process->running); - f_thread_lock_read(&thread_data.lock.process); + f_status_t status = F_none; + f_array_length_t id_rule = 0; - if (controller_find_process(id_rule, *thread_data.processs, &asynchronous->id_process) == F_true) { + f_thread_lock_read(&main.thread->lock.rule); - // use read locks to designate that the process is in use. - f_thread_lock_read(&thread_data.processs->array[asynchronous->id_process].lock); - } - else { + if (controller_rule_find(process->alias_rule, main.setting->rules, &id_rule) == F_true) { + controller_rule_t rule = controller_rule_t_initialize; - status = F_status_set_error(F_failure); + status = controller_rule_copy(main.setting->rules.array[id_rule], &rule); - if (thread_data.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&thread_main->thread->lock.print); + f_thread_unlock(&main.thread->lock.rule); - fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]); - fprintf(thread_data.data->output.stream, "The entry item rule '"); - fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, id_rule.string, thread_data.data->context.set.title.after->string); - fprintf(thread_data.data->output.stream, "' is no longer loaded.%c", f_string_eol_s[0]); + 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); + } + else { + for (f_array_length_t i = 0; i < process->stack.used; ++i) { - controller_entry_error_print_cache(thread_data.data->error, cache->action); + if (process->stack.array[i] == id_rule) { + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - f_thread_mutex_unlock(&thread_data.thread->lock.print); - } - } + fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]); + fprintf(main.data->error.to.stream, "%s%sThe rule '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s); + 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]); - f_thread_unlock(&thread_data.lock.process); + controller_rule_error_print(main.data->error, cache->action, F_true); - if (F_status_is_error_not(status)) { + f_thread_mutex_unlock(&main.thread->lock.print); + } - asynchronous->state = controller_asynchronous_state_active; - asynchronous->action = action; - asynchronous->options = options; - asynchronous->thread_data.thread = (void *) thread_data.thread; - //asynchronous->stack.used = 0; // @todo stack should be passed along each call!, might be better to make this a pointer. Maybe make this a id of process id? - - f_macro_time_spec_t_clear(asynchronous->cache.timestamp) - f_macro_string_range_t_clear(asynchronous->cache.range_action) - - asynchronous->cache.ats.used = 0; - asynchronous->cache.stack.used = 0; - asynchronous->cache.comments.used = 0; - asynchronous->cache.delimits.used = 0; - asynchronous->cache.content_action.used = 0; - asynchronous->cache.content_actions.used = 0; - asynchronous->cache.content_items.used = 0; - asynchronous->cache.object_actions.used = 0; - asynchronous->cache.object_items.used = 0; - asynchronous->cache.buffer_file.used = 0; - asynchronous->cache.buffer_item.used = 0; - asynchronous->cache.buffer_path.used = 0; - asynchronous->cache.action.used = 0; - asynchronous->cache.line_action = thread_data.thread->cache_action->line_action; - asynchronous->cache.line_item = thread_data.thread->cache_action->line_item; + // never continue on circular recursion errors even in simulate mode. + status = F_status_set_error(F_recurse); - if (F_status_is_error_not(status)) { - status = f_string_dynamic_append(thread_data.thread->cache_action->name_action, &asynchronous->cache.name_action); + break; + } + } // for if (F_status_is_error_not(status)) { - status = f_string_dynamic_append(thread_data.thread->cache_action->name_file, &asynchronous->cache.name_file); - } + f_thread_unlock(&process->lock); + f_thread_lock_write(&process->lock); - if (F_status_is_error_not(status)) { - status = f_string_dynamic_append(thread_data.thread->cache_action->name_item, &asynchronous->cache.name_item); - } - else { - controller_entry_error_print(thread_data.data->error, asynchronous->cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, thread_data.thread); + 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); + } + else { + process->stack.array[process->stack.used++] = id_rule; + } + + f_thread_unlock(&process->lock); + f_thread_lock_read(&process->lock); } } if (F_status_is_error_not(status)) { - status = f_thread_create(0, &asynchronous->id, controller_thread_asynchronous_process, (void *) asynchronous); + status = controller_rule_process(rule, controller_rule_action_type_start, rule_options, main, 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); + + f_thread_mutex_unlock(&main.thread->lock.print); + } } } + else { + f_thread_unlock(&main.thread->lock.rule); - if (F_status_is_error(status)) { - controller_entry_error_print(thread_data.data->error, asynchronous->cache->action, F_status_set_fine(status), "f_thread_create", F_true, thread_data.thread); + status = F_status_set_error(F_found_not); + + if (main.data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&main.thread->lock.print); - controller_asynchronous_delete_simple(asynchronous); + 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]); - thread_data.thread->asynchronouss.used--; + controller_entry_error_print_cache(main.data->error, process->cache->action); + + f_thread_mutex_unlock(&main.thread->lock.print); + } } - f_thread_unlock(&thread_data->lock.asynchronous); + f_thread_unlock(&process->lock); + f_thread_lock_write(&process->lock); - if (F_status_is_error(status)) { - return status; + if (asynchronous) { + process->state = controller_asynchronous_state_done; + } + else { + process->state = controller_asynchronous_state_idle; } - return F_none; + --process->stack.used; + + // inform all things waiting that the process has finished running. + f_thread_condition_signal(&process->wait); + f_thread_mutex_unlock(&process->running); + + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); + + return status; } -#endif // _di_controller_rule_process_asynchronous_ +#endif // _di_controller_rule_process_do_ #ifndef _di_controller_rule_read_ - f_status_t controller_rule_read(const f_string_static_t rule_id, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) { + f_status_t controller_rule_read(const f_string_static_t rule_id, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) { f_status_t status = F_none; bool for_item = F_true; @@ -2176,7 +2216,7 @@ extern "C" { f_macro_time_spec_t_clear(rule->timestamp); - rule->id.used = 0; + rule->alias.used = 0; rule->name.used = 0; rule->path.used = 0; rule->script.used = 0; @@ -2238,19 +2278,20 @@ extern "C" { cache->action.name_file.used = 0; cache->action.name_item.used = 0; - status = f_string_dynamic_append_nulless(rule_id, &rule->id); + status = f_string_dynamic_append_nulless(rule_id, &rule->alias); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true); } else { - status = f_string_dynamic_terminate_after(&rule->id); + + status = f_string_dynamic_terminate_after(&rule->alias); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); } else { - status = controller_file_load(controller_string_rules_s, rule->id, controller_string_rule_s, controller_string_rules_length, controller_string_rule_length, thread_data, cache); + status = controller_file_load(controller_string_rules_s, rule->alias, controller_string_rule_s, controller_string_rules_length, controller_string_rule_length, main, cache); } } @@ -2263,13 +2304,13 @@ extern "C" { status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true); } else { status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true); } } } @@ -2279,7 +2320,7 @@ extern "C" { status = controller_rule_items_increase_by(cache->object_items.used, &rule->items); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_rule_items_increase_by", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "controller_rule_items_increase_by", F_true); } else { f_array_length_t i = 0; @@ -2316,7 +2357,7 @@ extern "C" { 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(thread_data.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true); break; } @@ -2325,7 +2366,7 @@ extern "C" { 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(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true); break; } @@ -2342,14 +2383,14 @@ extern "C" { rule->items.array[rule->items.used].type = controller_rule_item_type_service; } else { - if (thread_data.data->warning.verbosity == f_console_verbosity_debug) { - fprintf(thread_data.data->warning.to.stream, "%s%sUnknown rule item '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s); - fprintf(thread_data.data->warning.to.stream, "%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string); - f_print_dynamic(thread_data.data->warning.to.stream, cache->action.name_item); - fprintf(thread_data.data->warning.to.stream, "%s", thread_data.data->warning.notable.after->string); - fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]); - - controller_rule_error_print(thread_data.data->warning, cache->action, F_true); + if (main.data->warning.verbosity == f_console_verbosity_debug) { + fprintf(main.data->warning.to.stream, "%s%sUnknown rule item '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s); + fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string); + f_print_dynamic(main.data->warning.to.stream, cache->action.name_item); + fprintf(main.data->warning.to.stream, "%s", main.data->warning.notable.after->string); + fprintf(main.data->warning.to.stream, "%s'.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]); + + controller_rule_error_print(main.data->warning, cache->action, F_true); } continue; @@ -2358,19 +2399,19 @@ extern "C" { status = f_string_dynamic_partial_append(cache->buffer_file, cache->content_items.array[i].array[0], &cache->buffer_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append", F_true); break; } status = f_string_dynamic_terminate_after(&cache->buffer_item); if (F_status_is_error(status)) { - fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); + fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true); break; } if (rule->items.array[rule->items.used].type) { - status = controller_rule_item_read(thread_data, cache, &rule->items.array[rule->items.used]); + status = controller_rule_item_read(*main.data, cache, &rule->items.array[rule->items.used]); if (F_status_is_error(status)) break; rule->items.used++; @@ -2378,7 +2419,7 @@ extern "C" { else { for_item = F_false; - status = controller_rule_setting_read(thread_data, cache, rule); + status = controller_rule_setting_read(*main.data, *main.setting, cache, rule); if (F_status_is_error(status)) { if (F_status_set_fine(status) == F_memory_not) { @@ -2391,7 +2432,7 @@ extern "C" { } if (F_status_is_error(status)) { - controller_rule_error_print(thread_data.data->error, cache->action, for_item); + controller_rule_error_print(main.data->error, cache->action, for_item); rule->status = controller_status_simplify(F_status_set_fine(status)); return F_false; @@ -2403,6 +2444,7 @@ extern "C" { #ifndef _di_controller_rule_setting_read_ f_status_t controller_rule_setting_read(const controller_data_t data, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) { + f_status_t status = F_none; f_status_t status_return = F_none; @@ -2608,7 +2650,6 @@ extern "C" { // @todo use sched_getaffinity() to get the available cpus and do not add an invalid cpu to the affinity array. if (!cache->content_actions.array[i].used) { - if (data.error.verbosity != f_console_verbosity_quiet) { // get the current line number within the settings item. @@ -2665,8 +2706,8 @@ extern "C" { status = F_status_set_fine(status); if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow) { - if (data.error.verbosity != f_console_verbosity_quiet) { + if (status == F_number_overflow || status == F_number_underflow) { fprintf(data.error.to.stream, "%c", f_string_eol_s[0]); fprintf(data.error.to.stream, "%s%sRule setting has an unsupported number '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); @@ -2719,7 +2760,6 @@ extern "C" { if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) { if (cache->content_actions.array[i].used != 2) { - if (data.error.verbosity != f_console_verbosity_quiet) { // get the current line number within the settings item. @@ -2839,7 +2879,6 @@ extern "C" { if (type == controller_rule_setting_type_control_group) { if (cache->content_actions.array[i].used < 2 || rule->has & controller_rule_has_control_group) { - 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%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]); @@ -2955,7 +2994,6 @@ extern "C" { } if (type == controller_rule_setting_type_limit) { - if (cache->content_actions.array[i].used != 3) { if (data.error.verbosity != f_console_verbosity_quiet) { @@ -3105,6 +3143,7 @@ extern "C" { f_number_signed_t number = 0; for (j = 1; j < 3; ++j, number = 0) { + status = fl_conversion_string_to_number_signed(cache->buffer_item.string, &number, cache->content_actions.array[i].array[j]); if (F_status_is_error(status)) { @@ -3172,6 +3211,7 @@ extern "C" { } if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) { + if (type == controller_rule_setting_type_name) { setting_value = &rule->name; } @@ -3183,7 +3223,6 @@ extern "C" { } if (setting_value->used || cache->content_actions.array[i].used != 1) { - 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%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]); @@ -3205,7 +3244,6 @@ extern "C" { } if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) { - status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value); if (F_status_is_error(status)) { @@ -3234,8 +3272,8 @@ extern "C" { status = controller_validate_has_graph(*setting_value); if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) { - if (status == F_false) { + if (status == F_false) { 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%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s); @@ -3323,7 +3361,6 @@ extern "C" { if (type == controller_rule_setting_type_scheduler) { if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2 || rule->has & controller_rule_has_scheduler) { - 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%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]); @@ -3534,7 +3571,6 @@ extern "C" { 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) { - if (F_status_set_fine(status) == F_memory_not) { fll_error_print(data.error, F_status_set_fine(status), "f_capability_from_text", F_true); @@ -4053,12 +4089,11 @@ extern "C" { #endif // _di_controller_rule_setting_read_ #ifndef _di_controller_rule_simulate_ - void controller_rule_simulate(const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) { + void controller_rule_simulate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_cache_t *cache) { - controller_data_t *data = thread_data.thread->data; - controller_setting_t *setting = thread_data.thread->setting; + const controller_data_t *data = main.data; - f_thread_mutex_lock(&thread_data.thread->lock.print); + f_thread_mutex_lock(&main.thread->lock.print); switch (action) { case controller_rule_action_type_kill: @@ -4079,13 +4114,11 @@ extern "C" { controller_rule_error_print(data->error, cache->action, F_true); } - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); return; } - const controller_rule_t *rule = &setting->rules.array[index]; - f_array_length_t i = 0; f_array_length_t j = 0; @@ -4093,11 +4126,11 @@ extern "C" { { bool missing = F_true; - for (; i < rule->items.used; ++i) { + for (; i < rule.items.used; ++i) { - for (j = 0; j < rule->items.array[i].actions.used; ++j) { + for (j = 0; j < rule.items.array[i].actions.used; ++j) { - if (rule->items.array[i].actions.array[j].type == action) { + if (rule.items.array[i].actions.array[j].type == action) { missing = F_false; break; } @@ -4107,7 +4140,7 @@ extern "C" { 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, "%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 '"); @@ -4119,18 +4152,18 @@ extern "C" { } 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, "Rule %s%s%s {%c", data->context.set.title.before->string, rule.alias.used ? rule.alias.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); - if (rule->capability) { + if (rule.capability) { cache->action.generic.used = 0; - if (F_status_is_error_not(f_capability_to_text(rule->capability, &cache->action.generic))) { + if (F_status_is_error_not(f_capability_to_text(rule.capability, &cache->action.generic))) { fprintf(data->output.stream, "%s", cache->action.generic.string); } } @@ -4143,117 +4176,114 @@ extern "C" { } 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); - for (i = 0; i < rule->control_group.groups.used; ++i) { + 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); + + for (i = 0; i < rule.control_group.groups.used; ++i) { - if (rule->control_group.groups.array[i].used) { + 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]); + 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); - if (rule->has & controller_rule_has_nice) { - fprintf(data->output.stream, " %i", rule->nice); + + if (rule.has & controller_rule_has_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); - if (rule->has & controller_rule_has_scheduler) { + + if (rule.has & controller_rule_has_scheduler) { f_string_t policy = ""; - if (rule->scheduler.policy == SCHED_BATCH) { + if (rule.scheduler.policy == SCHED_BATCH) { policy = controller_string_batch_s; } - else if (rule->scheduler.policy == SCHED_DEADLINE) { + else if (rule.scheduler.policy == SCHED_DEADLINE) { policy = controller_string_deadline_s; } - else if (rule->scheduler.policy == SCHED_FIFO) { + else if (rule.scheduler.policy == SCHED_FIFO) { policy = controller_string_fifo_s; } - else if (rule->scheduler.policy == SCHED_IDLE) { + else if (rule.scheduler.policy == SCHED_IDLE) { policy = controller_string_idle_s; } - else if (rule->scheduler.policy == SCHED_OTHER) { + else if (rule.scheduler.policy == SCHED_OTHER) { policy = controller_string_other_s; } - else if (rule->scheduler.policy == SCHED_RR) { + else if (rule.scheduler.policy == SCHED_RR) { 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, " %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, "%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", 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); + + if (rule.has & controller_rule_has_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]); - for (i = 0; i < rule->affinity.used; ++i) { - fprintf(data->output.stream, " %i%c", rule->affinity.array[i], 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]); } // for 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]); - for (i = 0; i < rule->define.used; ++i) { + 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]); + 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]); } } // for 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]); - for (i = 0; i < rule->environment.used; ++i) { + 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]); + if (rule.environment.array[i].used) { + 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, " %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]); + if (rule.has & controller_rule_has_group) { + 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]); + for (i = 0; i < rule.groups.used; ++i) { + 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, " %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]); + 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]); } // for 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]); - for (i = 0; i < rule->need.used; ++i) { + 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]); + if (rule.need.array[i].used) { + fprintf(data->output.stream, " %s%c", rule.need.array[i].string, f_string_eol_s[0]); } } // for @@ -4261,38 +4291,36 @@ extern "C" { 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) { + 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]); + 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]); } } // for 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]); - for (i = 0; i < rule->want.used; ++i) { + 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]); + if (rule.want.array[i].used) { + 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, " %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) { + 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]); + if (rule.wish.array[i].used) { + 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]); - if (rule->items.used) { + if (rule.items.used) { controller_rule_action_t *action = 0; controller_rule_item_t *item = 0; f_string_dynamic_t *parameter = 0; @@ -4300,12 +4328,11 @@ extern "C" { f_array_length_t j = 0; f_array_length_t k = 0; - for (i = 0; i < rule->items.used; ++i) { + for (i = 0; i < rule.items.used; ++i) { - item = &rule->items.array[i]; + 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 %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) { @@ -4313,7 +4340,6 @@ extern "C" { 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 %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) { @@ -4353,53 +4379,68 @@ extern "C" { fprintf(data->output.stream, "}%c", f_string_eol_s[0]); - setting->rules.array[index].status = F_complete; + main.setting->rules.array[index].status = F_complete; - f_thread_mutex_unlock(&thread_data.thread->lock.print); + f_thread_mutex_unlock(&main.thread->lock.print); } #endif // _di_controller_rule_simulate_ #ifndef _di_controller_rule_wait_all_ - void controller_rule_wait_all(controller_thread_t *thread) { + void controller_rule_wait_all(const controller_main_t main) { - for (f_array_length_t i = 0; i < thread->asynchronouss.used && thread->enabled; ++i) { + f_thread_lock_read(&main.thread->lock.process); - // do not need to wait when state is 0 or joined. - if (!thread->asynchronouss.array[i].state || thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) { - continue; - } + controller_process_t *process = 0; - if (thread->asynchronouss.array[i].index >= thread->setting->rules.used) { - continue; - } + for (f_array_length_t i = 0; i < main.thread->processs.used && main.thread->enabled; ++i) { - f_thread_mutex_lock(&thread->setting->rules.array[thread->asynchronouss.array[i].index].lock); + process = &main.thread->processs.array[i]; - while (thread->enabled && thread->setting->rules.array[thread->asynchronouss.array[i].index].status == F_known_not) { - f_thread_condition_wait(&thread->setting->rules.array[thread->asynchronouss.array[i].index].wait, &thread->setting->rules.array[thread->asynchronouss.array[i].index].lock); - } // while + f_thread_lock_read(&process->active); + f_thread_lock_read(&process->lock); - f_thread_mutex_unlock(&thread->setting->rules.array[thread->asynchronouss.array[i].index].lock); + if (process->state == controller_process_state_idle || process->state == controller_process_state_done) { - if (!thread->enabled) break; + if (process->state == controller_process_state_done) { + f_thread_unlock(&process->lock); + f_thread_lock_write(&process->lock); - if (f_thread_mutex_lock_try(&thread->lock.asynchronous) == F_none) { + if (process->state == controller_process_state_done) { + f_thread_join(process->id_thread, 0); - if (thread->asynchronouss.array[i].state != controller_asynchronous_state_joined) { - f_thread_join(thread->asynchronouss.array[i].id, 0); + process->state = controller_process_state_idle; + } } - if (thread->enabled && thread->asynchronouss.array[i].state) { - if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) { - thread->asynchronouss.array[i].state = controller_asynchronous_state_joined; - } + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); - controller_macro_cache_action_t_clear(thread->asynchronouss.array[i].cache); - } + continue; + } + + f_thread_condition_wait(&process->wait, &process->running); + + if (process->state == controller_process_state_done) { + f_thread_unlock(&process->lock); + f_thread_lock_write(&process->lock); - f_thread_mutex_unlock(&thread->lock.asynchronous); + if (process->state == controller_process_state_done) { + f_thread_join(process->id_thread, 0); + + process->state = controller_process_state_idle; + } } + + f_thread_unlock(&process->lock); + + // always pass the signal along when done waiting. + f_thread_condition_signal(&process->wait); + f_thread_mutex_unlock(&process->running); + + f_thread_unlock(&process->active); } // for + + f_thread_unlock(&main.thread->lock.process); } #endif // _di_controller_rule_wait_all_ diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 76b203b..49fd2d5 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -27,6 +27,25 @@ extern "C" { #endif // _di_controller_rule_action_method_name_ /** + * Find the location of the Rule by the Rule alias. + * + * @param alias + * The Rule alias to find. + * @param rules + * The rules to search through. + * @param at + * The index the rule was found at. + * + * @return + * F_none on success, but the id.used is 0. + * F_true on success and rule was found, index is updated. + * F_false on success and rule was not found. + */ +#ifndef _di_controller_rule_find_ + extern f_status_t controller_rule_find(const f_string_static_t alias, const controller_rules_t rules, f_array_length_t *at) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_find_ + +/** * Read the parameters for some rule action. * * The object and content ranges are merged together (in that order) as the action parameters. @@ -275,8 +294,8 @@ 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 thread_data - * The thread data. + * @param main + * The main data. * @param cache * A structure for containing and caching relevant data. * @param rule @@ -292,7 +311,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 uint8_t type, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + 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; #endif // _di_controller_rule_execute_ /** @@ -318,8 +337,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 execute_set * The execute parameter and as settings. - * @param thread_data - * The thread data. + * @param main + * The main data. * @param rule * The rule to process. * @@ -333,7 +352,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_thread_data_t thread_data, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + 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; #endif // _di_controller_rule_execute_foreground_ /** @@ -362,8 +381,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 execute_set * The execute parameter and as settings. - * @param thread - * The thread data. + * @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. @@ -379,33 +398,10 @@ 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_thread_data_t thread_data, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + 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; #endif // _di_controller_rule_execute_pid_with_ /** - * Search the already loaded rules to see if one is found. - * - * Looks up the rules starting from the end so that the latest loaded version of any given rule is found and used first. - * The rule thread should be locked before calling this to ensure the rule is not loaded after this search. - * - * This does not do any locking or unlocking, be sure to lock appropriately before and after calling this. - * - * @param rule_id - * The string identifying the rule. - * This is constructed from the path parts to the file without the file extension and without the settings directory prefix. - * "/etc/controller/rules/example/my.rule" would have a rule id of "example/my". - * @param thread_data - * The thread data. - * - * @return - * If found, a valid location within the setting.rules array. - * If not found, then setting.rules.used is returned. - */ -#ifndef _di_controller_rule_find_loaded_ - extern f_array_length_t controller_rule_find_loaded(const f_string_static_t rule_id, controller_thread_data_t thread_data) f_gcc_attribute_visibility_internal; -#endif // _di_controller_rule_find_loaded_ - -/** * Construct an id from two distinct strings found within a single given source. * * @param data @@ -416,8 +412,8 @@ extern "C" { * A range within the source representing the directory part of a rule id. * @param basename * A range within the source representing the basename part of a rule id. - * @param id - * The constructed id. + * @param alias + * The constructed alias. * * @return * F_none on success. @@ -430,7 +426,7 @@ extern "C" { * @see f_string_dynamic_terminate_after() */ #ifndef _di_controller_rule_id_construct_ - extern f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *id) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *alias) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_id_construct_ /** @@ -546,17 +542,16 @@ extern "C" { #endif // _di_controller_rule_path_ /** - * Synchronously process and execute the given rule by the rule id. + * Process and execute the given rule. * - * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings. + * Any dependent rules are processed and executed as per "need", "want", and "wish" rule settings. * All dependent rules must be already loaded, this function will not load any rules. * + * @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 at_process - * The position within the processs array representing this rule process. * @param action * The action to perform based on the action type codes. * @@ -571,10 +566,10 @@ 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 thread_data - * The thread data. - * @param cache - * A structure for containing and caching relevant data. + * @param main + * The main data. + * @param process + * The process data for processing this rule. * * @return * F_none on success. @@ -582,49 +577,81 @@ 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 f_array_length_t at_process, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; + 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; #endif // _di_controller_rule_process_ /** - * Asynchronously process and execute the given rule by the rule id. + * Synchronously or Asynchronously begin processing some rule. * - * 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 id_rule - * The ID of the rule, such as "boot/init". + * @param asynchronous + * If TRUE, then asynchronously execute a process. + * If FALSE, then synchronously execute a process. + * @param alias_rule + * The alias of the rule, such as "boot/init". * @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_data - * The thread data. + * @param stack + * A stack representing the processes already running in this rule process dependency tree. + * This is used to prevent circular dependencies. + * @param main + * The main data. * @param cache * A structure for containing and caching relevant data. * * @return * F_none on success. + * F_busy on success and the process was found to already be running (nothing to do). * F_signal on (exit) signal received. * - * Errors (with error bit) from: controller_asynchronouss_increase(). + * F_found_not (with error bit) if unable to for a process for the given rule id. + * F_recurse (with error bit) on recursion error (the process is already on the process stack). + * + * Status from: controller_rule_process(). + * + * Errors (with error bit) from: controller_rule_process(). * Errors (with error bit) from: f_string_dynamic_append(). * Errors (with error bit) from: f_thread_create(). + * + * @see controller_rule_process() + * @see f_string_dynamic_append() + * @see f_thread_create() */ -#ifndef _di_controller_rule_process_asynchronous_ - extern f_status_t controller_rule_process_asynchronous(const f_string_static_t id_rule, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal; -#endif // _di_controller_rule_process_asynchronous_ +#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; +#endif // _di_controller_rule_process_begin_ + +/** + * Helper for calling controller_rule_process(). + * + * This does all the preparation work that needs to be synchronously performed within the same thread. + * + * @param asynchronous + * If TRUE, designates that this function is being asynchronously executed. + * If FALSE, designates that this function is being synchronously executed. + * @param process + * The process data. + * + * @return + * F_none on success. + * F_found on success and the process was found to already be running (nothing to do). + * F_signal on (exit) signal received. + * + * F_found_not (with error bit) if unable to for a process for the given rule id. + * + * Status from: controller_rule_process(). + * + * Errors (with error bit) from: controller_rule_copy(). + * Errors (with error bit) from: controller_rule_process(). + * + * @see controller_rule_copy() + * @see controller_rule_process() + * @see controller_rule_process_begin() + */ +#ifndef _di_controller_rule_process_do_ + extern f_status_t controller_rule_process_do(const bool asynchronous, controller_process_t *process) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_process_do_ /** * Read the rule file, extracting all valid items. @@ -633,8 +660,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_data - * The thread data. + * @param main + * The main data. * @param cache * A structure for containing and caching relevant data. * @param rule @@ -657,7 +684,7 @@ extern "C" { * @see fll_fss_basic_list_read(). */ #ifndef _di_controller_rule_read_ - extern f_status_t controller_rule_read(const f_string_static_t rule_id, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_read(const f_string_static_t rule_id, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_read_ /** @@ -706,6 +733,8 @@ extern "C" { * * This automatically sets the rule's status to F_complete. * + * @param rule + * The rule to process. * @param action * The action to perform based on the action type codes. * @@ -720,25 +749,23 @@ 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 thread_data - * The thread data. + * @param main + * The main data. * @param cache * A structure for containing and caching relevant data. - * @param rule - * The rule to process. */ #ifndef _di_controller_rule_simulate_ - extern void controller_rule_simulate(const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal; + extern void controller_rule_simulate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_simulate_ /** - * Wait until all currently running asynchronous execution threads are complete. + * Wait until all currently running Rule processes are complete. * - * @param thread - * The thread data. + * @param main + * The main data. */ #ifndef _di_controller_rule_wait_all_ - extern void controller_rule_wait_all(controller_thread_t *thread) f_gcc_attribute_visibility_internal; + extern void controller_rule_wait_all(const controller_main_t main) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_wait_all_ #ifdef __cplusplus diff --git a/level_3/controller/c/private-thread.c b/level_3/controller/c/private-thread.c index e9be560..81675f3 100644 --- a/level_3/controller/c/private-thread.c +++ b/level_3/controller/c/private-thread.c @@ -9,181 +9,96 @@ extern "C" { #endif -#ifndef _di_controller_thread_asynchronous_process_ - void * controller_thread_asynchronous_process(void *arguments) { - - controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) arguments; - controller_thread_t *main = (controller_thread_t *) asynchronous->thread; - - f_thread_lock_read(&main->lock.asynchronous); - - if (!main->enabled) { - f_thread_unlock(&main->lock.asynchronous); - - return 0; - } - - f_thread_unlock(&main->lock.asynchronous); - - f_array_length_t at_process = 0; - - f_thread_lock_read(&main->thread->lock.process); - - if (controller_find_process(rule.id, *main->processs, &at_process) == F_false) { - f_thread_unlock(&main->thread->lock.process); - f_thread_lock_write(&main->thread->lock.process); - - const f_status_t status = controller_processs_increase(main->processs); - - if (F_status_is_error(status)) { - controller_entry_error_print(main->data->error, asynchronous->cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, main->thread); - - f_thread_unlock(&main->thread->lock.process); - return 0; - } - else { - at_process = main->processs->used++; - } - } - - // once the "active" lock is in place for some process, then it will not be deleted and should be guaranteed to not change or be relocated. - f_thread_lock_read(&main->processs.array[id_process].active); - f_thread_unlock(&main->thread->lock.process); - - // @todo looks like I do need a r/w lock on controller_asynchronous_t after all. - - controller_rule_t rule = controller_rule_t_initialize; - - // @todo copy rule, finding the rule using main->processs.array[id_process].id_rule. - //status = controller_rule_copy(, &rule); - - { - const f_status_t status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, asynchronous->cache); - - asynchronous->state = controller_asynchronous_state_done; - - if (F_status_is_error(status)) { - f_thread_mutex_lock(&thread_data.thread->lock.print); - - controller_entry_error_print_cache(thread_data.data->error, asynchronous->cache->action); - - f_thread_mutex_unlock(&thread_data.thread->lock.print); - } - } - - f_thread_unlock(&main->processs.array[id_process].active); - - return 0; - } -#endif // _di_controller_thread_asynchronous_process_ - -#ifndef _di_controller_thread_asynchronous_cancel_ - void controller_thread_asynchronous_cancel(controller_thread_t *thread) { - - thread->enabled = F_false; - - f_thread_mutex_lock(&thread->lock.asynchronous); +#ifndef _di_controller_thread_cleanup_ + void * controller_thread_cleanup(void *arguments) { - for (f_array_length_t i = 0; i < thread->asynchronouss.used; ++i) { + const controller_main_t *main = (controller_main_t *) arguments; - if (!thread->asynchronouss.array[i].state) continue; + 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; - if (f_thread_mutex_lock_try(&thread->asynchronouss.array[i].lock) == F_none) { - f_thread_cancel(thread->asynchronouss.array[i].id); - f_thread_detach(thread->asynchronouss.array[i].id); - f_thread_mutex_unlock(&thread->asynchronouss.array[i].lock); - } - else { - if (thread->asynchronouss.array[i].child > 0) { - f_signal_send(F_signal_termination, thread->asynchronouss.array[i].child); - } - else { - f_thread_cancel(thread->asynchronouss.array[i].id); - } + while (main->thread->enabled) { - // the cancel make take time so detach the process to allow it to exit on its own. - f_thread_detach(thread->asynchronouss.array[i].id); - } - } // for + sleep(interval); - thread->asynchronouss.used = 0; + if (f_thread_lock_write_try(&main->thread->lock.process) == F_none) { + controller_process_t *process = 0; - f_thread_unlock(&thread->lock.asynchronous); - } -#endif // _di_controller_thread_asynchronous_cancel_ + // index 0 is reserved for "main thread". + f_array_length_t i = 1; -#ifndef _di_controller_thread_cleanup_ - void * controller_thread_cleanup(void *arguments) { + for (; j < main->thread->processs.used; ++i) { - controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments; + process = &main->thread->processs.array[i]; - const unsigned int interval = thread_data->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cache_cleanup_interval_short : controller_thread_cache_cleanup_interval_long; - - f_array_length_t i = 0; + if (f_thread_lock_write_try(&process->active) != F_none) { + continue; + } - for (; thread_data->thread->enabled; ) { - sleep(interval); + if (f_thread_lock_write_try(&process->lock) != F_none) { + f_thread_unlock(&process->active); - /* - if (f_thread_lock_write_try(&thread_data->thread->lock.asynchronous) == F_none) { - controller_thread_t *thread = &thread_data->thread; + continue; + } - if (thread->asynchronouss.used) { - for (i = 0; i < thread->asynchronouss.used; ++i) { + if (process->state == controller_process_state_active || process->state == controller_process_state_busy) { + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); - if (!thread->enabled) break; - if (!thread->asynchronouss.array[i].state) continue; + continue; + } - if (f_thread_lock_write_try(&thread->asynchronouss.array[i].lock) != F_none) continue; + if (process->state == controller_process_state_done) { + f_thread_detach(process->id_thread); + process->state = controller_process_state_idle; + } - if (f_thread_lock_write_try(&thread_data->setting->rules.array[thread->asynchronouss.array[i].index].lock) == F_none) { + // 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); - 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; - } + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); + } // for - if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) { - controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]); + for (i = main->thread->processs.used - 1; main->thread->processs.used; --i, --main->thread->processs.used) { - thread->asynchronouss.array[i].state = 0; - } + process = &main->thread->processs.array[i]; - f_thread_condition_signal(&thread_data->setting->rules.array[thread->asynchronouss.array[i].index].wait); - f_thread_mutex_unlock(&thread_data->setting->rules.array[thread->asynchronouss.array[i].index].lock); - } + if (f_thread_lock_write_try(&process->active) != F_none) { + break; + } - f_thread_mutex_unlock(&thread->asynchronouss.array[i].lock); - } // for + if (f_thread_lock_write_try(&process->lock) != F_none) { + f_thread_unlock(&process->active); - for (i = thread->asynchronouss.used - 1; thread->asynchronouss.used; --i, --thread->asynchronouss.used) { + break; + } - if (!thread->enabled) 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 (f_thread_mutex_lock_try(&thread->asynchronouss.array[i].lock) != F_none) break; + break; + } - if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) { - controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]); + if (process->state == controller_process_state_done) { + f_thread_detach(process->id_thread); + process->state = controller_process_state_idle; + } - thread->asynchronouss.array[i].state = 0; - } - else if (thread->asynchronouss.array[i].state) { - f_thread_unlock(&thread->asynchronouss.array[i].lock); - break; - } + // 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); - f_thread_unlock(&thread->asynchronouss.array[i].lock); - } // for - } + --main->thread->processs.used; - if (thread->enabled && thread->asynchronouss.used < thread->asynchronouss.size) { - controller_asynchronouss_resize(thread->asynchronouss.used, &thread->asynchronouss); - } + f_thread_unlock(&process->active); + f_thread_unlock(&process->lock); + } // for - f_thread_unlock(&thread->lock.asynchronous); + f_thread_unlock(&main->thread->lock.process); } - */ - } // for + } // while return 0; } @@ -192,7 +107,7 @@ extern "C" { #ifndef _di_controller_thread_control_ void * controller_thread_control(void *arguments) { - controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments; + controller_main_t *main = (controller_main_t *) arguments; // @todo @@ -206,27 +121,40 @@ extern "C" { f_status_t status = F_none; controller_thread_t thread = controller_thread_t_initialize; - controller_processs_t processs = controller_processs_t_initialize; - controller_thread_data_t thread_data = controller_macro_thread_data_t_initialize(0, data, setting, &processs, &thread); + controller_main_t main = controller_macro_main_t_initialize(data, setting, &thread); - status = controller_asynchronouss_increase(&thread.asynchronouss); + // the main locks must be initialized, but only once, so initialize immediately upon allocation. + status = controller_lock_create(&thread.lock); - if (F_status_is_error_not(status)) { - status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &thread_data); + if (F_status_is_error(status)) { + if (data->error.verbosity != f_console_verbosity_quiet) { + fll_error_print(data->error, status, "controller_lock_create", F_true); + } } + else { + status = controller_processs_increase(&thread.processs); + + if (F_status_is_error(status)) { + controller_error_print(data->error, F_status_set_fine(status), "controller_processs_increase", F_true, &thread); + } + } + + 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); } } - else { + + if (F_status_is_error_not(status)) { if (data->parameters[controller_parameter_daemon].result == f_console_result_found) { setting->ready = controller_setting_ready_done; if (f_file_exists(setting->path_pid.string) == F_true) { if (data->error.verbosity != f_console_verbosity_quiet) { + f_thread_mutex_lock(&thread.lock.print); fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); @@ -244,22 +172,24 @@ extern "C" { else { // index 0 is reserved for running the main thread cache. - thread.asynchronouss.used = 1; + thread.processs.used = 1; - status = controller_entry_read(entry_name, thread_data, &thread.asynchronouss.array[0].cache); + status = controller_entry_read(entry_name, main, &thread.processs.array[0].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(thread_data, &thread.asynchronouss.array[0].cache); + status = controller_preprocess_entry(main, &thread.processs.array[0].cache); } if (F_status_is_error_not(status) && status != F_signal && status != F_child) { + 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) { + f_thread_mutex_lock(&thread.lock.print); fprintf(data->error.to.stream, "%c", f_string_eol_s[0]); @@ -274,7 +204,7 @@ extern "C" { status = F_status_set_error(F_available_not); } else { - status = controller_process_entry(thread_data, &thread.asynchronouss.array[0].cache); + status = controller_process_entry(main, &thread.processs.array[0].cache); if (F_status_is_error(status)) { setting->ready = controller_setting_ready_fail; @@ -301,20 +231,16 @@ extern "C" { status = F_signal; } - // only make the rule and control threads available once any/all pre-processing and is completed. + // only make the rule and control threads available once any/all pre-processing and are completed. if (F_status_is_error_not(status) && status != F_signal && status != F_child) { if (data->parameters[controller_parameter_validate].result == f_console_result_none) { - controller_rule_wait_all(&thread); - - status = f_thread_create(0, &thread.id_rule, &controller_thread_rule, (void *) &thread_data); + controller_rule_wait_all(main); - if (F_status_is_error_not(status)) { - status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &thread_data); - } + status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &main); if (F_status_is_error_not(status)) { - status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &thread_data); + status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &main); } if (F_status_is_error(status)) { @@ -343,19 +269,15 @@ extern "C" { } if (thread.enabled) { - controller_thread_asynchronous_cancel(&thread); + controller_thread_process_cancel(main); } - // @todo when cancelling, make sure that whatever has a lock, no longer has any lock. f_thread_cancel(thread.id_cleanup); f_thread_cancel(thread.id_control); - f_thread_cancel(thread.id_rule); - f_thread_join(thread.id_cleanup, 0); - f_thread_join(thread.id_control, 0); - f_thread_join(thread.id_rule, 0); + f_thread_detach(thread.id_cleanup); + f_thread_detach(thread.id_control); - controller_processs_delete_simple(&processs); controller_thread_delete_simple(&thread); if (F_status_is_error(status)) { @@ -370,33 +292,91 @@ extern "C" { } #endif // _di_controller_thread_main_ -#ifndef _di_controller_thread_rule_ - void * controller_thread_rule(void *arguments) { - - controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments; +#ifndef _di_controller_thread_process_ + void * controller_thread_process(void *arguments) { - // @todo - // f_thread_mutex_lock(&thread_data->lock.rule); - // f_thread_mutex_unlock(&thread_data->lock.rule); + controller_rule_process_do(F_true, (controller_process_t *) arguments); return 0; } -#endif // _di_controller_thread_rule_ +#endif // _di_controller_thread_process_ + +#ifndef _di_controller_thread_process_cancel_ + void controller_thread_process_cancel(const controller_main_t main) { + + // this must be set, regardless of lock state and only this function changes this. + main.thread->enabled = F_false; + + f_thread_lock_write(&main.thread->lock.process); + + if (!main.thread->processs.used) { + f_thread_unlock(&main.thread->lock.process); + + return; + } + + controller_process_t *process = 0; + + bool locked = 0; + + //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) { + + process = &main.thread->processs.array[i]; + + locked = f_thread_lock_write_try(&process->lock) == F_none; + + if (!locked) { + locked = f_thread_lock_read_try(&process->lock) == F_none; + } + + if (locked) { + if (process->child > 0) { + f_signal_send(F_signal_quit, process->child); + } + + if (process->state == controller_process_state_active || process->state == controller_process_state_busy) { + 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_unlock(&process->lock); + } + } // for + + main.thread->processs.used = 0; + + // @todo: sleep a little, check to see if child processes quit, and if not then sen F_signal_quit_termination. + // this will likely need to be done by: + // 1) create an array of child process ids from above loop. + // 2) search through loop at this location in the code and if the process id is found, sleep a little. + // 3) check again to see if the child process quit and if not, then send the F_signal_quit_termination. + // 4) continue to next child until entire array is processed. + + f_thread_unlock(&main.thread->lock.process); + } +#endif // _di_controller_thread_process_cancel_ #ifndef _di_controller_thread_signal_ void * controller_thread_signal(void *arguments) { - controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments; + controller_main_t *main = (controller_main_t *) arguments; - for (int signal = 0; thread_data->thread->enabled; ) { + for (int signal = 0; main->thread->enabled; ) { - sigwait(&thread_data->data->signal.set, &signal); + sigwait(&main->data->signal.set, &signal); - if (thread_data->data->parameters[controller_parameter_interruptable].result == f_console_result_found) { + if (main->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_data->thread->signal = signal; + main->thread->signal = signal; - controller_thread_asynchronous_cancel(thread_data->thread); + controller_thread_process_cancel(*main); break; } } diff --git a/level_3/controller/c/private-thread.h b/level_3/controller/c/private-thread.h index 22051b3..f0c12e2 100644 --- a/level_3/controller/c/private-thread.h +++ b/level_3/controller/c/private-thread.h @@ -13,35 +13,11 @@ 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_process_ - extern void * controller_thread_asynchronous_process(void *arguments) f_gcc_attribute_visibility_internal; -#endif // _di_controller_thread_asynchronous_process_ - -/** - * 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 cleanup data when not busy. * * @param arguments * The thread arguments. - * Must be of type controller_thread_data_t. + * Must be of type controller_main_t. * * @return * 0, always. @@ -55,7 +31,7 @@ extern "C" { * * @param arguments * The thread arguments. - * Must be of type controller_thread_data_t. + * Must be of type controller_main_t. * * @return * 0, always. @@ -85,18 +61,30 @@ extern "C" { #endif // _di_controller_thread_main_ /** - * Thread for handling loading of rules into memory. + * Asynchronously execute a Rule process. * * @param arguments * The thread arguments. - * Must be of type controller_thread_data_t. + * Must be of type controller_process_t. * * @return * 0, always. + * + * @see controller_rule_process_do() + */ +#ifndef _di_controller_thread_process_ + extern void * controller_thread_process(void *arguments) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_process_ + +/** + * Cancel all process threads. + * + * @param main + * The main thread data. */ -#ifndef _di_controller_thread_rule_ - extern void * controller_thread_rule(void *arguments) f_gcc_attribute_visibility_internal; -#endif // _di_controller_thread_rule_ +#ifndef _di_controller_thread_process_cancel_ + void controller_thread_process_cancel(const controller_main_t main) f_gcc_attribute_visibility_internal; +#endif // _di_controller_thread_process_cancel_ /** * Thread for handling signals/interrupts. @@ -105,7 +93,7 @@ extern "C" { * * @param arguments * The thread arguments. - * Must be of type controller_thread_data_t. + * Must be of type controller_main_t. * * @return * 0, always. -- 1.8.3.1