From: Kevin Day Date: Sun, 10 Aug 2025 01:32:18 +0000 (-0500) Subject: Update: Major improvements in locking logic. X-Git-Tag: 0.7.3~38 X-Git-Url: https://www.git.kevux.org/?a=commitdiff_plain;h=efdd3047649966affa46ac0195be18d457e089d3;p=controller Update: Major improvements in locking logic. Major Improvements: - Add custom thread status checking functions (also replacing `controller_thread_is_enabled()` with `controller_thread_enable_is()`). - The thread enable property is now `enable` rather than `enabled`. - Add new `controller_thread_enable_none_e` to allow for handling default behavior. - Add new `enable` read/write lock to better handle the reading and writing of the enable property. - Change the signalling logic to directly call `f_thread_condition_signal_all()` and to not read lock the conditions on signal send. - Change the lock status checks to more explicitly check for `F_okay` so that unknown conditions without error bit set are ignored. Being explicit on handling the `F_okay` helps ensures that the lock is guaranteed to be set. I think I need to additional review and re-structuring of the thread logic beyond this commit. There will likely be additional commits in the future to further improve the locking logic. I believe that there are some cases where unlock might be called on a not-locked lock. The additional work will likely include addressing this. I suspect this is happening in cases where the same function is called in two different contexts. One context is directly from a thread and another is in the middle of processing something. The lock might not be set in the case of the directly calling from the thread. --- diff --git a/data/build/settings b/data/build/settings index 4dc0fa8..e8f614f 100644 --- a/data/build/settings +++ b/data/build/settings @@ -70,7 +70,7 @@ build_sources_library print/output/entry/setting.c print/output/rule/execute.c p build_sources_library print/message.c print/message/entry.c print/message/entry/action.c print/message/entry/item.c build_sources_library print/warning/entry/action.c print/warning/entry/item.c print/warning/entry/setting.c print/warning/rule/action.c print/warning/rule/item.c print/warning/rule/setting.c build_sources_library signal.c status.c time.c -build_sources_library thread.c thread/cleanup.c thread/control.c thread/entry.c thread/instance.c thread/is.c thread/rule.c thread/signal.c +build_sources_library thread.c thread/cleanup.c thread/control.c thread/enable.c thread/entry.c thread/instance.c thread/is.c thread/rule.c thread/signal.c build_sources_library validate.c build_sources_headers common.h controller.h common/define.h common/enumeration.h common/print.h common/string.h common/thread.h common/type.h @@ -93,7 +93,7 @@ build_sources_headers print/output/entry/setting.h print/output/rule/execute.h p build_sources_headers print/message.h print/message/entry.h print/message/entry/action.h print/message/entry/item.h build_sources_headers print/warning/entry/action.h print/warning/entry/item.h print/warning/entry/setting.h print/warning/rule/action.h print/warning/rule/item.h print/warning/rule/setting.h build_sources_headers signal.h status.h time.h -build_sources_headers thread.h thread/cleanup.h thread/control.h thread/entry.h thread/instance.h thread/is.h thread/rule.h thread/signal.h +build_sources_headers thread.h thread/cleanup.h thread/control.h thread/enable.h thread/entry.h thread/instance.h thread/is.h thread/rule.h thread/signal.h build_sources_headers validate.h build_sources_documentation man diff --git a/data/build/stand_alone/settings.controller b/data/build/stand_alone/settings.controller index 6ddbce3..2cefe19 100644 --- a/data/build/stand_alone/settings.controller +++ b/data/build/stand_alone/settings.controller @@ -105,7 +105,7 @@ build_sources_program program/controller/main/print/output/entry/setting.c progr build_sources_program program/controller/main/print/message.c program/controller/main/print/message/entry.c program/controller/main/print/message/entry/action.c program/controller/main/print/message/entry/item.c build_sources_program program/controller/main/print/warning/entry/action.c program/controller/main/print/warning/entry/item.c program/controller/main/print/warning/entry/setting.c program/controller/main/print/warning/rule/action.c program/controller/main/print/warning/rule/item.c program/controller/main/print/warning/rule/setting.c build_sources_program program/controller/main/signal.c program/controller/main/status.c program/controller/main/time.c -build_sources_program program/controller/main/thread.c program/controller/main/thread/cleanup.c program/controller/main/thread/control.c program/controller/main/thread/entry.c program/controller/main/thread/instance.c program/controller/main/thread/is.c program/controller/main/thread/rule.c program/controller/main/thread/signal.c +build_sources_program program/controller/main/thread.c program/controller/main/thread/cleanup.c program/controller/main/thread/control.c program/controller/main/thread/enable.c program/controller/main/thread/entry.c program/controller/main/thread/instance.c program/controller/main/thread/is.c program/controller/main/thread/rule.c program/controller/main/thread/signal.c build_sources_program program/controller/main/validate.c build_sources_program program/controller/controller/config.c program/controller/controller/main.c program/controller/controller/controller.c program/controller/controller/string.c diff --git a/data/build/stand_alone/settings.init b/data/build/stand_alone/settings.init index 7639b49..5c90e11 100644 --- a/data/build/stand_alone/settings.init +++ b/data/build/stand_alone/settings.init @@ -105,7 +105,7 @@ build_sources_program program/controller/main/print/output/entry/setting.c progr build_sources_program program/controller/main/print/message.c program/controller/main/print/message/entry.c program/controller/main/print/message/entry/action.c program/controller/main/print/message/entry/item.c build_sources_program program/controller/main/print/warning/entry/action.c program/controller/main/print/warning/entry/item.c program/controller/main/print/warning/entry/setting.c program/controller/main/print/warning/rule/action.c program/controller/main/print/warning/rule/item.c program/controller/main/print/warning/rule/setting.c build_sources_program program/controller/main/signal.c program/controller/main/status.c program/controller/main/time.c -build_sources_program program/controller/main/thread.c program/controller/main/thread/cleanup.c program/controller/main/thread/control.c program/controller/main/thread/entry.c program/controller/main/thread/instance.c program/controller/main/thread/is.c program/controller/main/thread/rule.c program/controller/main/thread/signal.c +build_sources_program program/controller/main/thread.c program/controller/main/thread/cleanup.c program/controller/main/thread/control.c program/controller/main/thread/enable.c program/controller/main/thread/entry.c program/controller/main/thread/instance.c program/controller/main/thread/is.c program/controller/main/thread/rule.c program/controller/main/thread/signal.c build_sources_program program/controller/main/validate.c build_sources_program program/controller/init/config.c program/controller/init/main.c program/controller/init/init.c program/controller/init/print.c program/controller/init/signal.c program/controller/init/string.c diff --git a/sources/c/program/controller/init/signal.c b/sources/c/program/controller/init/signal.c index 7e777a4..2a64c7f 100644 --- a/sources/c/program/controller/init/signal.c +++ b/sources/c/program/controller/init/signal.c @@ -8,13 +8,13 @@ extern "C" { void controller_init_signal_thread(controller_t * const main, const uint8_t is_normal) { if (!main) return; - if (!controller_thread_is_enabled(&main->thread, is_normal)) return; + if (!controller_thread_enable_is(&main->thread, is_normal)) return; if (!(main->setting.flag & controller_main_flag_interruptible_d)) return; siginfo_t information; f_time_spec_t time = f_time_spec_t_initialize; - while (controller_thread_is_enabled(&main->thread, is_normal)) { + while (controller_thread_enable_is(&main->thread, is_normal)) { memset((void *) &information, 0, sizeof(siginfo_t)); @@ -30,7 +30,7 @@ extern "C" { // Send F_signal_reserved_35 to cleanup process to reap child processes. if (information.si_signo == F_signal_child || information.si_signo == F_signal_reserved_35) { - controller_lock_signal(&main->thread.lock.reap_condition, &main->thread.lock.reap); + f_thread_condition_signal_all(&main->thread.lock.reap_condition); continue; } @@ -38,7 +38,7 @@ extern "C" { if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) { main->thread.signal = information.si_signo; - controller_lock_signal(&main->thread.lock.reap_condition, &main->thread.lock.reap); + f_thread_condition_signal_all(&main->thread.lock.reap_condition); controller_thread_instance_cancel(main, is_normal, controller_thread_cancel_signal_e); break; diff --git a/sources/c/program/controller/main/common/enumeration/thread.h b/sources/c/program/controller/main/common/enumeration/thread.h index 9411ed9..05eb318 100644 --- a/sources/c/program/controller/main/common/enumeration/thread.h +++ b/sources/c/program/controller/main/common/enumeration/thread.h @@ -19,8 +19,9 @@ extern "C" { /** * States for the thread, designating how to stop the process. * - * controller_thread_*_e: - * - enabled_not: The controller is no longer enabled, shut down and abort all work. + * controller_thread_enable_*_e: + * - enabled_none: The enable state is not set or unknown (may be returned to designate failure to read enable state). + * - enabled_not: The controller is no longer enabled, shut down and abort all work (this is expected to be smaller than all enabled modes other than "none". * - enabled: The controller is operating normally. * - enabled_execute: The controller is executing another process, all running operations must terminate. * - enabled_exit: The controller is shutting down, only process Exit rules. @@ -28,12 +29,13 @@ extern "C" { * - enabled_exit_ready: The controller is shutting down, only process Exit rules, and now ready to send termination signals. */ enum { - controller_thread_enabled_not_e = 0, - controller_thread_enabled_e, - controller_thread_enabled_execute_e, - controller_thread_enabled_exit_e, - controller_thread_enabled_exit_execute_e, - controller_thread_enabled_exit_ready_e, + controller_thread_enable_none_e = 0, + controller_thread_enable_not_e, + controller_thread_enable_e, + controller_thread_enable_execute_e, + controller_thread_enable_exit_e, + controller_thread_enable_exit_execute_e, + controller_thread_enable_exit_ready_e, }; // enum /** diff --git a/sources/c/program/controller/main/common/type/lock.c b/sources/c/program/controller/main/common/type/lock.c index d7b45db..a3a16cc 100644 --- a/sources/c/program/controller/main/common/type/lock.c +++ b/sources/c/program/controller/main/common/type/lock.c @@ -14,6 +14,7 @@ extern "C" { f_thread_mutex_delete(&lock->print); f_thread_mutex_delete(&lock->reap); + f_thread_lock_delete(&lock->enable); f_thread_lock_delete(&lock->instance); f_thread_lock_delete(&lock->rule); diff --git a/sources/c/program/controller/main/common/type/lock.h b/sources/c/program/controller/main/common/type/lock.h index 34ce5e5..5734438 100644 --- a/sources/c/program/controller/main/common/type/lock.h +++ b/sources/c/program/controller/main/common/type/lock.h @@ -21,9 +21,10 @@ extern "C" { * * The alert lock is intended for a generic waiting on alerts operations. * The cancel lock is intended for preventing double cancellation calls (which can happen due to interrupts). + * The enable lock is intended for a handling checks to the enable state. * The print lock is intended to lock any activity printing to stdout/stderr. * The instance lock is intended to lock any activity on the instance structure. - * The Rule lock is intended to lock any activity on the rules structure. + * The rule lock is intended to lock any activity on the rules structure. * * Properties: * - flag: A set of flags associated with the locks. @@ -31,8 +32,9 @@ extern "C" { * - cancel: The cancel mutex lock for locking the cancel operation. * - print: The print mutex lock. * - reap: The reap_condition mutex lock. + * - enable: The enable r/w lock. * - instance: The instance r/w lock. - * - rule: The Rule r/w lock. + * - rule: The rule r/w lock. * - alert_condition: The condition used to trigger alerts. * - reap_condition: The condition used to trigger zombie reaping. */ @@ -45,6 +47,7 @@ extern "C" { f_thread_mutex_t print; f_thread_mutex_t reap; + f_thread_lock_t enable; f_thread_lock_t instance; f_thread_lock_t rule; @@ -60,6 +63,7 @@ extern "C" { f_thread_mutex_t_initialize, \ f_thread_lock_t_initialize, \ f_thread_lock_t_initialize, \ + f_thread_lock_t_initialize, \ f_thread_condition_t_initialize, \ f_thread_condition_t_initialize, \ } diff --git a/sources/c/program/controller/main/common/type/thread.h b/sources/c/program/controller/main/common/type/thread.h index 1d17bae..0f11527 100644 --- a/sources/c/program/controller/main/common/type/thread.h +++ b/sources/c/program/controller/main/common/type/thread.h @@ -21,17 +21,12 @@ extern "C" { * * This is essentially data shared globally between threads, about threads. * - * The "enabled" and "signal" utilize the lock: lock.process. - * - * The lock.alert must be used when writing to any of: - * - enabled. - * * The typedef for this is located in the defs.h header. * * Properties: - * - enabled: F_true when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when F_false. - * - signal: The code of any signal received. - * - status: A status used by the main entry/rule processing thread for synchronous operations. + * - enable: F_true when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when F_false. + * - signal: The code of any signal received. + * - status: A status used by the main entry/rule processing thread for synchronous operations. * * - id_cleanup: The thread ID representing the Cleanup Process. * - id_control: The thread ID representing the Control Process. @@ -45,7 +40,7 @@ extern "C" { */ #ifndef _di_controller_thread_t_ struct controller_thread_t_ { - uint8_t enabled; + uint8_t enable; int signal; f_status_t status; @@ -61,7 +56,7 @@ extern "C" { }; #define controller_thread_t_initialize { \ - controller_thread_enabled_e, \ + controller_thread_enable_e, \ 0, \ F_none, \ f_thread_id_t_initialize, \ diff --git a/sources/c/program/controller/main/controller.h b/sources/c/program/controller/main/controller.h index d020314..f9a1362 100644 --- a/sources/c/program/controller/main/controller.h +++ b/sources/c/program/controller/main/controller.h @@ -148,6 +148,7 @@ #include #include #include +#include #include #include #include diff --git a/sources/c/program/controller/main/entry.c b/sources/c/program/controller/main/entry.c index 07941ca..3978e19 100644 --- a/sources/c/program/controller/main/entry.c +++ b/sources/c/program/controller/main/entry.c @@ -109,7 +109,7 @@ extern "C" { f_number_unsigned_t at = 0; f_number_unsigned_t j = 0; - for (i = 0; i < main->thread.cache.object_items.used && controller_thread_is_enabled(&main->thread, is_entry); ++i) { + for (i = 0; i < main->thread.cache.object_items.used && controller_thread_enable_is(&main->thread, is_entry); ++i) { code &= ~0x2; at = 0; @@ -266,7 +266,7 @@ extern "C" { for (j = 0; j < entry->items.array[i].actions.used; ++j) { - if (!controller_thread_is_enabled(&main->thread, is_entry)) { + if (!controller_thread_enable_is(&main->thread, is_entry)) { entry->status = controller_status_simplify_error(F_interrupt); return F_status_set_error(F_interrupt); diff --git a/sources/c/program/controller/main/entry/preprocess.c b/sources/c/program/controller/main/entry/preprocess.c index 29a50ad..b87b5c3 100644 --- a/sources/c/program/controller/main/entry/preprocess.c +++ b/sources/c/program/controller/main/entry/preprocess.c @@ -58,11 +58,11 @@ extern "C" { return status; } - while (controller_thread_is_enabled(&main->thread, is_entry)) { + while (controller_thread_enable_is(&main->thread, is_entry)) { actions = &entry->items.array[cache->ats.array[at_i]].actions; - for (; cache->ats.array[at_j] < actions->used && controller_thread_is_enabled(&main->thread, is_entry); ++cache->ats.array[at_j]) { + for (; cache->ats.array[at_j] < actions->used && controller_thread_enable_is(&main->thread, is_entry); ++cache->ats.array[at_j]) { cache->action.line_action = actions->array[cache->ats.array[at_j]].line; cache->action.name_action.used = 0; @@ -91,7 +91,7 @@ extern "C" { else if (f_compare_dynamic(controller_settings_s, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) continue; // Walk though each items and check to see if the item actually exists. - for (i = 1; i < entry->items.used && controller_thread_is_enabled(&main->thread, is_entry); ++i) { + for (i = 1; i < entry->items.used && controller_thread_enable_is(&main->thread, is_entry); ++i) { if (f_compare_dynamic(entry->items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) { @@ -193,7 +193,7 @@ extern "C" { } } // while - if (!controller_thread_is_enabled(&main->thread, is_entry)) return F_status_set_error(F_interrupt); + if (!controller_thread_enable_is(&main->thread, is_entry)) return F_status_set_error(F_interrupt); // If ready is not found in the entry, then default to always ready. if (main->process.ready == controller_process_ready_no_e) { diff --git a/sources/c/program/controller/main/entry/process.c b/sources/c/program/controller/main/entry/process.c index 5ddebb2..402bf48 100644 --- a/sources/c/program/controller/main/entry/process.c +++ b/sources/c/program/controller/main/entry/process.c @@ -16,8 +16,8 @@ extern "C" { uint8_t options_force = 0; uint8_t options_instance = 0; - controller_entry_t * const entry = is_entry ? &main->process.entry : &main->process.exit; controller_cache_t * const cache = &main->thread.cache; + controller_entry_t * const entry = is_entry ? &main->process.entry : &main->process.exit; controller_entry_action_t *entry_action = 0; controller_entry_actions_t *entry_actions = 0; @@ -68,11 +68,11 @@ extern "C" { if (F_status_is_error(status)) return status; } - while (controller_thread_is_enabled(&main->thread, is_entry)) { + while (controller_thread_enable_is(&main->thread, is_entry)) { entry_actions = &entry->items.array[cache->ats.array[at_i]].actions; - for (; cache->ats.array[at_j] < entry_actions->used && controller_thread_is_enabled(&main->thread, is_entry); ++cache->ats.array[at_j]) { + for (; cache->ats.array[at_j] < entry_actions->used && controller_thread_enable_is(&main->thread, is_entry); ++cache->ats.array[at_j]) { entry_action = &entry_actions->array[cache->ats.array[at_j]]; @@ -188,7 +188,7 @@ extern "C" { else if (entry_action->type == controller_entry_action_type_consider_e || controller_entry_action_type_is_rule(entry_action->type)) { status_lock = controller_lock_write(is_entry, F_true, &main->thread, &main->thread.lock.rule); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); break; @@ -216,7 +216,7 @@ extern "C" { status_lock = controller_lock_read(is_entry, F_true, &main->thread, &main->thread.lock.rule); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); break; @@ -230,7 +230,7 @@ extern "C" { controller_print_message_entry_item_rule(&main->program.message, entry, entry_action, is_entry, alias_rule); } - if (!controller_thread_is_enabled(&main->thread, is_entry)) break; + if (!controller_thread_enable_is(&main->thread, is_entry)) break; // The Rule is not yet loaded, ensure that it is loaded. if (status != F_true) { @@ -253,7 +253,7 @@ extern "C" { status_lock = controller_lock_write(is_entry, F_true, &main->thread, &main->thread.lock.rule); - if (F_status_is_fine(status_lock)) { + if (status_lock == F_okay) { status = controller_rule_read(main, cache, is_entry, alias_rule, entry, &main->process.rules.array[main->process.rules.used]); } @@ -273,13 +273,13 @@ extern "C" { cache->action.line_action = cache_line_action; cache->action.line_item = cache_line_item; - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); break; } - if (F_status_set_fine(status) == F_interrupt || !controller_thread_is_enabled(&main->thread, is_entry)) { + if (F_status_set_fine(status) == F_interrupt || !controller_thread_enable_is(&main->thread, is_entry)) { f_thread_unlock(&main->thread.lock.rule); break; @@ -464,9 +464,9 @@ extern "C" { } } // while - if (!controller_thread_is_enabled(&main->thread, is_entry)) return F_status_set_error(F_interrupt); + if (!controller_thread_enable_is(&main->thread, is_entry)) return F_status_set_error(F_interrupt); if (status == F_child) return status; - if (F_status_is_error(status_lock)) return status_lock; + if (status_lock != F_okay) return status_lock; // Check to see if any required processes failed, but do not do this if already operating in failsafe. if (F_status_is_error_not(status) && !failsafe && !(main->setting.flag & controller_main_flag_validate_d) && main->process.mode != controller_process_mode_helper_e) { diff --git a/sources/c/program/controller/main/instance.c b/sources/c/program/controller/main/instance.c index f0b1f51..7ad9a91 100644 --- a/sources/c/program/controller/main/instance.c +++ b/sources/c/program/controller/main/instance.c @@ -23,22 +23,6 @@ extern "C" { } #endif // _di_controller_instance_find_ -#ifndef _di_controller_instance_signal_wait_ - f_status_t controller_instance_signal_wait(controller_instance_t * const instance) { - - if (!instance) return F_status_set_error(F_parameter); - - const f_status_t status = controller_lock_mutex(instance->type != controller_instance_type_exit_e, F_true, &instance->main->thread, &instance->wait); - - if (status == F_okay) { - f_thread_condition_signal_all(&instance->wait_condition); - f_thread_mutex_unlock(&instance->wait); - } - - return F_okay; - } -#endif // _di_controller_instance_signal_wait_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/program/controller/main/instance.h b/sources/c/program/controller/main/instance.h index f93771e..44a5acb 100644 --- a/sources/c/program/controller/main/instance.h +++ b/sources/c/program/controller/main/instance.h @@ -41,29 +41,6 @@ extern "C" { f_status_t controller_instance_find(const f_number_unsigned_t action, const f_string_static_t alias, const controller_instances_t instances, f_number_unsigned_t * const at); #endif // _di_controller_instance_find_ -/** - * Send a signal to the wait condition. - * - * Used to inform all things waiting on a specific instance that the specific instance has finished running. - * - * @param instance - * The Controller Instance. - * - * Must not be NULL. - * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * - * Errors (with error bit) from: controller_lock_mutex(). - * - * @see controller_lock_mutex() - */ -#ifndef _di_controller_instance_signal_wait_ - extern f_status_t controller_instance_signal_wait(controller_instance_t * const instance); -#endif // _di_controller_instance_signal_wait_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/program/controller/main/instance/prepare.c b/sources/c/program/controller/main/instance/prepare.c index f1a2b85..078f233 100644 --- a/sources/c/program/controller/main/instance/prepare.c +++ b/sources/c/program/controller/main/instance/prepare.c @@ -16,7 +16,7 @@ extern "C" { status = controller_lock_write(is_normal, F_true, &main->thread, &main->thread.lock.instance); - if (F_status_is_error(status)) { + if (status != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_false); } else { @@ -34,7 +34,7 @@ extern "C" { controller_instance_t * const instance = F_status_is_error_not(status) ? main->thread.instances.array[main->thread.instances.used] : 0; - if (F_status_is_error_not(status)) { + if (status == F_okay) { status = controller_lock_write(is_normal, F_true, &main->thread, &instance->lock); } diff --git a/sources/c/program/controller/main/lock.c b/sources/c/program/controller/main/lock.c index 9bfe2d9..ebb4412 100644 --- a/sources/c/program/controller/main/lock.c +++ b/sources/c/program/controller/main/lock.c @@ -21,29 +21,37 @@ extern "C" { status = f_thread_mutex_create(0, &lock->reap); if (F_status_is_error_not(status)) { - status = f_thread_lock_create(0, &lock->instance); + status = f_thread_lock_create(0, &lock->enable); if (F_status_is_error_not(status)) { - status = f_thread_lock_create(0, &lock->rule); + status = f_thread_lock_create(0, &lock->instance); if (F_status_is_error_not(status)) { - status = f_thread_condition_create(0, &lock->alert_condition); + status = f_thread_lock_create(0, &lock->rule); if (F_status_is_error_not(status)) { - status = f_thread_condition_create(0, &lock->reap_condition); + status = f_thread_condition_create(0, &lock->alert_condition); + + if (F_status_is_error_not(status)) { + status = f_thread_condition_create(0, &lock->reap_condition); + + if (F_status_is_error(status)) { + f_thread_condition_delete(&lock->alert_condition); + } + } if (F_status_is_error(status)) { - f_thread_condition_delete(&lock->alert_condition); + f_thread_lock_delete(&lock->rule); } } if (F_status_is_error(status)) { - f_thread_lock_delete(&lock->rule); + f_thread_lock_delete(&lock->instance); } } if (F_status_is_error(status)) { - f_thread_lock_delete(&lock->instance); + f_thread_lock_delete(&lock->enable); } } @@ -90,14 +98,14 @@ extern "C" { status = f_thread_mutex_lock_timed(&time, mutex); if (status == F_time) { - if (check && !controller_thread_is_enabled(thread, is_normal)) return F_status_set_error(F_interrupt); + if (check && !controller_thread_enable_is(thread, is_normal)) return F_status_set_error(F_interrupt); } - else { + else if (status == F_okay) { break; } } // for - return status; + return F_okay; } #endif // _di_controller_lock_mutex_ @@ -126,14 +134,14 @@ extern "C" { status = f_thread_lock_read_timed(&time, lock); if (status == F_time) { - if (check && !controller_thread_is_enabled(thread, is_normal)) return F_status_set_error(F_interrupt); + if (check && !controller_thread_enable_is(thread, is_normal)) return F_status_set_error(F_interrupt); } - else { + else if (status == F_okay) { break; } } // for - return status; + return F_okay; } #endif // _di_controller_lock_read_ @@ -146,22 +154,6 @@ extern "C" { } #endif // _di_controller_lock_read_instance_ -#ifndef _di_controller_lock_signal_ - f_status_t controller_lock_signal(f_thread_condition_t * const condition, f_thread_mutex_t * const mutex) { - - if (!condition || !mutex) return F_status_set_error(F_parameter); - - const f_status_t status = f_thread_mutex_lock(mutex); - - if (status == F_okay) { - f_thread_condition_signal_all(condition); - f_thread_mutex_unlock(mutex); - } - - return F_okay; - } -#endif // _di_controller_lock_signal_ - #ifndef _di_controller_lock_write_ f_status_t controller_lock_write(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_lock_t * const lock) { @@ -176,14 +168,14 @@ extern "C" { status = f_thread_lock_write_timed(&time, lock); if (status == F_time) { - if (check && !controller_thread_is_enabled(thread, is_normal)) return F_status_set_error(F_interrupt); + if (check && !controller_thread_enable_is(thread, is_normal)) return F_status_set_error(F_interrupt); } - else { + else if (status == F_okay) { break; } } // for - return status; + return F_okay; } #endif // _di_controller_lock_write_ diff --git a/sources/c/program/controller/main/lock.h b/sources/c/program/controller/main/lock.h index 9c3f72c..6f53642 100644 --- a/sources/c/program/controller/main/lock.h +++ b/sources/c/program/controller/main/lock.h @@ -166,32 +166,6 @@ extern "C" { #endif // _di_controller_lock_read_instance_ /** - * Send a signal to the given condition. - * - * @param condition - * The condition to send the signal too. - * - * Must not be NULL. - * - * @param mutex - * The mutex lock associated with the condition. - * - * Must not be NULL. - * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * - * Errors (with error bit) from: controller_lock_mutex(). - * - * @see controller_lock_mutex() - */ -#ifndef _di_controller_lock_signal_ - extern f_status_t controller_lock_signal(f_thread_condition_t * const condition, f_thread_mutex_t * const mutex); -#endif // _di_controller_lock_signal_ - -/** * Wait to get a write lock. * * Given a r/w lock, periodically check to see if main thread is disabled while waiting. diff --git a/sources/c/program/controller/main/process.c b/sources/c/program/controller/main/process.c index 54cb4ed..57d4d42 100644 --- a/sources/c/program/controller/main/process.c +++ b/sources/c/program/controller/main/process.c @@ -101,13 +101,13 @@ extern "C" { } // Only make the Rule and control threads available once any/all pre-processing is complete. - if (F_status_is_error_not(status) && status != F_failure && status != F_child && main->thread.enabled == controller_thread_enabled_e) { + if (F_status_is_error_not(status) && status != F_failure && status != F_child && controller_thread_enable_get(&main->thread) == controller_thread_enable_e) { if (!(main->setting.flag & controller_main_flag_validate_d)) { // Wait for the Entry thread to complete before starting the Rule thread. controller_thread_join(&main->thread.id_rule); - if (main->thread.enabled && main->process.mode == controller_process_mode_service_e) { + if (controller_thread_enable_get(&main->thread) > controller_thread_enable_not_e && main->process.mode == controller_process_mode_service_e) { status = f_thread_create(0, &main->thread.id_rule, &controller_thread_rule, (void *) main); if (F_status_is_error(status)) { @@ -129,7 +129,7 @@ extern "C" { return; } - if (F_status_is_error_not(status) && status != F_failure && !(main->setting.flag & controller_main_flag_validate_d) && controller_thread_is_enabled(&main->thread, F_true)) { + if (F_status_is_error_not(status) && status != F_failure && !(main->setting.flag & controller_main_flag_validate_d) && controller_thread_enable_is(&main->thread, F_true)) { if (main->process.mode == controller_process_mode_service_e) { controller_thread_join(&main->thread.id_signal); } diff --git a/sources/c/program/controller/main/rule/execute.c b/sources/c/program/controller/main/rule/execute.c index 6ccdcd2..93b72cb 100644 --- a/sources/c/program/controller/main/rule/execute.c +++ b/sources/c/program/controller/main/rule/execute.c @@ -411,7 +411,7 @@ extern "C" { if (F_status_set_fine(status) == F_lock_read) { status = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &main->thread, &instance->lock); - if (F_status_is_error(status)) return F_status_set_error(F_lock_read); + if (status != F_okay) return F_status_set_error(F_lock_read); status = F_status_set_error(F_lock); } @@ -435,12 +435,14 @@ extern "C" { if (!instance || !instance->main) return F_status_set_error(F_parameter); - f_status_t status = F_okay; - controller_t * const main = instance->main; - + f_status_t status = F_okay; f_execute_result_t result = f_execute_result_t_initialize; + // @fixme Lock the instance.childs.used with write access. (active should already have a read lock) + //status = controller_lock_write(instance->type != controller_instance_type_exit_e, F_false, &main->thread, &instance->lock); + //if (status != F_okay) return F_status_set_error(F_lock_read); + status = f_memory_array_increase(controller_allocation_small_d, sizeof(pid_t), (void **) &instance->childs.array, &instance->childs.used, &instance->childs.size); if (F_status_is_error(status)) { @@ -449,7 +451,7 @@ extern "C" { return status; } - pid_t * const process_child_id = controller_rule_execute_next_child(instance); + pid_t * const process_child_id = controller_rule_execute_next_child(instance); // @fixme should be included in write lock. if (options & controller_instance_option_simulate_e) { controller_print_entry_output_execute_simulate(&main->program.output, instance, program, arguments); @@ -490,7 +492,7 @@ extern "C" { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); - if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); + if (status_lock != F_okay) return F_status_set_error(F_lock_read); return F_status_set_error(F_lock); } @@ -504,14 +506,14 @@ extern "C" { status_lock = controller_lock_read_instance(instance, &instance->lock); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { // Try again, after the first interrupt. if (F_status_set_fine(status_lock) == F_interrupt) { status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); } - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); return F_status_set_error(F_lock_read); @@ -599,10 +601,14 @@ extern "C" { if (!execute_set || !instance || !instance->main) return F_status_set_error(F_parameter); - f_status_t status = F_okay; controller_t * const main = instance->main; + f_status_t status = F_okay; f_execute_result_t result = f_execute_result_t_initialize; + // @fixme Lock the instance.childs.used with write access. (active should already have a read lock) + //status = controller_lock_write(instance->type != controller_instance_type_exit_e, F_false, &main->thread, &instance->lock); + //if (status != F_okay) return F_status_set_error(F_lock_read); + status = f_memory_array_increase(controller_allocation_small_d, sizeof(pid_t), (void **) &instance->childs.array, &instance->childs.used, &instance->childs.size); if (F_status_is_error_not(status)) { @@ -615,7 +621,7 @@ extern "C" { return status; } - pid_t * const process_child_id = controller_rule_execute_next_child(instance); + pid_t * const process_child_id = controller_rule_execute_next_child(instance); // @fixme should be included in write lock. f_string_dynamic_t * const process_child_pid_file = controller_rule_execute_next_pid_path(instance); status = f_file_exists(pid_file, F_true); @@ -676,11 +682,11 @@ extern "C" { f_status_t status_lock = controller_lock_write_instance(instance, &instance->lock); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); - if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); + if (status_lock != F_okay) return F_status_set_error(F_lock_read); return F_status_set_error(F_lock); } @@ -701,11 +707,11 @@ extern "C" { status_lock = controller_lock_write_instance(instance, &instance->lock); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &instance->main->thread, &instance->lock); - if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); + if (status_lock != F_okay) return F_status_set_error(F_lock_read); return F_status_set_error(F_lock); } diff --git a/sources/c/program/controller/main/rule/instance.c b/sources/c/program/controller/main/rule/instance.c index a2b5f2c..932c087 100644 --- a/sources/c/program/controller/main/rule/instance.c +++ b/sources/c/program/controller/main/rule/instance.c @@ -136,7 +136,7 @@ extern "C" { status_lock = controller_lock_read_instance(instance, &main->thread.lock.instance); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); } else { @@ -365,7 +365,7 @@ extern "C" { // Find at least one of the requested Action when the Rule is required. if (instance->options & controller_instance_option_require_e) { - bool missing = F_true; + uint8_t missing = F_true; f_number_unsigned_t j = 0; for (i = 0; i < instance->rule.items.used; ++i) { @@ -408,7 +408,7 @@ extern "C" { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &main->thread, &instance->lock); - if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); + if (status_lock != F_okay) return F_status_set_error(F_lock_read); return F_status_set_error(F_lock); } @@ -429,7 +429,7 @@ extern "C" { f_thread_unlock(&instance->lock); status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &main->thread, &instance->lock); - if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); + if (status_lock != F_okay) return F_status_set_error(F_lock_read); return F_status_set_error(F_lock); } @@ -460,7 +460,7 @@ extern "C" { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); status_lock = controller_lock_read(instance->type != controller_instance_type_exit_e, F_false, &main->thread, &instance->lock); - if (F_status_is_error(status_lock)) return F_status_set_error(F_lock_read); + if (status_lock != F_okay) return F_status_set_error(F_lock_read); return F_status_set_error(F_lock); } @@ -477,7 +477,7 @@ extern "C" { f_status_t status = controller_lock_read(type != controller_instance_type_exit_e, F_true, &main->thread, &main->thread.lock.instance); - if (F_status_is_error(status)) { + if (status != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_true); return status; @@ -499,7 +499,7 @@ extern "C" { status = controller_lock_read(type != controller_instance_type_exit_e, F_true, &main->thread, &instance->active); - if (F_status_is_error(status)) { + if (status != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_true); controller_print_error_rule_item(&main->program.error, &cache->action, F_false, F_status_set_fine(status)); @@ -533,7 +533,7 @@ extern "C" { // The thread is done, so close the thread. if (instance->state == controller_instance_state_done_e) { controller_thread_join(&instance->id_thread); - controller_instance_signal_wait(instance); + f_thread_condition_signal_all(&instance->wait_condition); } instance->id = at; @@ -661,7 +661,7 @@ extern "C" { instance->state = controller_instance_state_idle_e; } - controller_instance_signal_wait(instance); + f_thread_condition_signal_all(&instance->wait_condition); f_thread_unlock(&instance->lock); } @@ -700,7 +700,7 @@ extern "C" { f_status_t status_lock = F_okay; // The instance and active locks shall be held for the duration of this instanceing (aside from switching between read to/from write). - if (options_force & controller_instance_option_asynchronous_e) { + if (options_force & controller_instance_option_asynchronous_e) { // @fixme are all of these async "active" locks save/valid? status_lock = controller_lock_read_instance(instance, &instance->active); if (F_status_is_error(status_lock)) { @@ -906,7 +906,7 @@ extern "C" { instance->state = (options_force & controller_instance_option_asynchronous_e) ? controller_instance_state_done_e : controller_instance_state_idle_e; instance->stack.used = used_original_stack; - controller_instance_signal_wait(instance); + f_thread_condition_signal_all(&instance->wait_condition); f_thread_unlock(&instance->lock); private_controller_rule_instance_perform_unlock_active(instance, options_force); diff --git a/sources/c/program/controller/main/rule/wait.c b/sources/c/program/controller/main/rule/wait.c index 7be4247..93ecae2 100644 --- a/sources/c/program/controller/main/rule/wait.c +++ b/sources/c/program/controller/main/rule/wait.c @@ -11,7 +11,7 @@ extern "C" { f_status_t status_lock = controller_lock_read(is_normal, F_false, &main->thread, &main->thread.lock.instance); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true); return status_lock; @@ -42,11 +42,11 @@ extern "C" { for (i = 0; i < instance_total; ++i) { - if (!controller_thread_is_enabled(&main->thread, is_normal)) break; + if (!controller_thread_enable_is(&main->thread, is_normal)) break; // Re-establish instance read lock to wait for or protect from the cleanup thread while checking the read instance. status_lock = controller_lock_read(is_normal, F_true, &main->thread, &main->thread.lock.instance); - if (F_status_is_error(status_lock)) break; + if (status_lock != F_okay) break; if (!instance_list[i]) { f_thread_unlock(&main->thread.lock.instance); @@ -56,7 +56,7 @@ extern "C" { status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->active); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { f_thread_unlock(&main->thread.lock.instance); break; @@ -67,7 +67,7 @@ extern "C" { status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->lock); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { f_thread_unlock(&instance_list[i]->active); break; @@ -89,7 +89,7 @@ extern "C" { status_lock = controller_lock_write(is_normal, F_true, &main->thread, &instance_list[i]->lock); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false); f_thread_unlock(&instance_list[i]->active); @@ -106,12 +106,12 @@ extern "C" { instance_list[i]->state = controller_instance_state_idle_e; f_thread_unlock(&instance_list[i]->active); - controller_instance_signal_wait(instance_list[i]); + f_thread_condition_signal_all(&instance_list[i]->wait_condition); } status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->active); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { f_thread_unlock(&instance_list[i]->lock); break; @@ -121,7 +121,7 @@ extern "C" { f_thread_unlock(&instance_list[i]->lock); status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->lock); - if (F_status_is_error(status_lock)) break; + if (status_lock != F_okay) break; } if (instance_list[i]->options & controller_instance_option_require_e) { @@ -159,7 +159,7 @@ extern "C" { status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->lock); - if (F_status_is_error(status_lock)) { + if (status_lock != F_okay) { f_thread_unlock(&instance_list[i]->active); break; @@ -195,7 +195,7 @@ extern "C" { return status_lock; } - if (!controller_thread_is_enabled(&main->thread, is_normal)) return F_status_set_error(F_interrupt); + if (!controller_thread_enable_is(&main->thread, is_normal)) return F_status_set_error(F_interrupt); if (F_status_set_fine(status) == F_require) return status; if (required_not_run) return F_require; diff --git a/sources/c/program/controller/main/thread/cleanup.c b/sources/c/program/controller/main/thread/cleanup.c index 108bf99..09468d6 100644 --- a/sources/c/program/controller/main/thread/cleanup.c +++ b/sources/c/program/controller/main/thread/cleanup.c @@ -17,9 +17,10 @@ extern "C" { f_time_spec_t delay = f_time_spec_t_initialize; siginfo_t signal_data; uint8_t reap_count = 0; + uint8_t enable = controller_thread_enable_none_e; f_status_t status = F_okay; - while (main->thread.enabled == controller_thread_enabled_e) { + while (controller_thread_enable_get(&main->thread) == controller_thread_enable_e) { controller_time_now( main->setting.flag & controller_main_flag_simulate_d @@ -65,8 +66,10 @@ extern "C" { } while (F_false); } - if (main->thread.enabled != controller_thread_enabled_e) { - if (main->thread.enabled == controller_thread_enabled_exit_e) continue; + enable = controller_thread_enable_get(&main->thread); + + if (enable != controller_thread_enable_e) { + if (enable == controller_thread_enable_exit_e) continue; break; } @@ -76,32 +79,57 @@ extern "C" { f_number_unsigned_t i = 0; - for (status = F_okay; i < main->thread.instances.size && main->thread.enabled == controller_thread_enabled_e; ++i) { + for (status = F_okay; i < main->thread.instances.used && controller_thread_enable_get(&main->thread) == controller_thread_enable_e; ++i) { if (!main->thread.instances.array[i]) continue; - if (i >= main->thread.instances.used) { - status = controller_instance_initialize(&main->thread.instances.array[i]); - } - instance = main->thread.instances.array[i]; + { + f_time_spec_t time; + + do { + if (controller_thread_enable_get(&main->thread) != controller_thread_enable_e) { + status = F_enable_not; + + break; + } + + memset((void *) &time, 0, sizeof(struct timespec)); + + controller_time_now(controller_thread_timeout_cancel_seconds_d, controller_thread_timeout_cancel_nanoseconds_d, &time); + + status = f_thread_mutex_lock_timed(&time, &main->thread.lock.cancel); + if (F_status_is_error(status)) break; + + } while (status != F_okay); + + if (status == F_enable_not) break; + if (F_status_is_error(status)) continue; + } + // If "active" has a read or write lock, then do not attempt to clean it. - if (f_thread_lock_write_try(&instance->active) != F_okay) continue; + if (f_thread_lock_write_try(&instance->active) != F_okay) { + f_thread_mutex_unlock(&main->thread.lock.cancel); + + continue; + } // If "lock" has a read or write lock, then do not attempt to clean it. if (f_thread_lock_write_try(&instance->lock) != F_okay) { f_thread_unlock(&instance->active); + f_thread_mutex_unlock(&main->thread.lock.cancel); continue; } // If instance is active or busy, then do not attempt to clean it. - if (instance->state == controller_instance_state_active_e || instance->state == controller_instance_state_busy_e || main->thread.enabled != controller_thread_enabled_e) { + if (instance->state == controller_instance_state_active_e || instance->state == controller_instance_state_busy_e || controller_thread_enable_get(&main->thread) != controller_thread_enable_e) { f_thread_unlock(&instance->lock); f_thread_unlock(&instance->active); + f_thread_mutex_unlock(&main->thread.lock.cancel); - if (main->thread.enabled == controller_thread_enabled_e) continue; + if (controller_thread_enable_get(&main->thread) == controller_thread_enable_e) continue; break; } @@ -110,18 +138,19 @@ extern "C" { if (instance->path_pids.used) { f_number_unsigned_t j = 0; - for (; j < instance->path_pids.used && main->thread.enabled == controller_thread_enabled_e; ++j) { + for (; j < instance->path_pids.used && controller_thread_enable_get(&main->thread) == controller_thread_enable_e; ++j) { if (instance->path_pids.array[j].used && f_file_exists(instance->path_pids.array[j], F_true) == F_true) { break; } } // for - if (j < instance->path_pids.used || main->thread.enabled != controller_thread_enabled_e) { + if (j < instance->path_pids.used || controller_thread_enable_get(&main->thread) != controller_thread_enable_e) { f_thread_unlock(&instance->lock); f_thread_unlock(&instance->active); + f_thread_mutex_unlock(&main->thread.lock.cancel); - if (main->thread.enabled == controller_thread_enabled_e) continue; + if (controller_thread_enable_get(&main->thread) == controller_thread_enable_e) continue; break; } @@ -135,11 +164,12 @@ extern "C" { instance->state = controller_instance_state_idle_e; instance->id_thread = 0; - controller_instance_signal_wait(instance); + f_thread_condition_signal_all(&instance->wait_condition); } else { f_thread_unlock(&instance->lock); f_thread_unlock(&instance->active); + f_thread_mutex_unlock(&main->thread.lock.cancel); continue; } @@ -151,11 +181,11 @@ extern "C" { // Shrink the childs array. if (instance->childs.used) { - for (; instance->childs.used && main->thread.enabled == controller_thread_enabled_e; --instance->childs.used) { + for (; instance->childs.used && controller_thread_enable_get(&main->thread) == controller_thread_enable_e; --instance->childs.used) { if (instance->childs.array[instance->childs.used]) break; } // for - if (main->thread.enabled != controller_thread_enabled_e) { + if (controller_thread_enable_get(&main->thread) != controller_thread_enable_e) { f_thread_unlock(&instance->lock); f_thread_unlock(&instance->active); @@ -181,6 +211,7 @@ extern "C" { f_thread_unlock(&instance->lock); f_thread_unlock(&instance->active); + f_thread_mutex_unlock(&main->thread.lock.cancel); } // for f_thread_unlock(&main->thread.lock.instance); diff --git a/sources/c/program/controller/main/thread/control.c b/sources/c/program/controller/main/thread/control.c index cd2f222..1241d06 100644 --- a/sources/c/program/controller/main/thread/control.c +++ b/sources/c/program/controller/main/thread/control.c @@ -14,7 +14,7 @@ extern "C" { controller_t * const main = (controller_t *) argument; - if (main->thread.enabled != controller_thread_enabled_e) return 0; + if (controller_thread_enable_get(&main->thread) != controller_thread_enable_e) return 0; f_status_t status = F_okay; diff --git a/sources/c/program/controller/main/thread/enable.c b/sources/c/program/controller/main/thread/enable.c new file mode 100644 index 0000000..84ae16b --- /dev/null +++ b/sources/c/program/controller/main/thread/enable.c @@ -0,0 +1,66 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_thread_enable_get_ + uint8_t controller_thread_enable_get(controller_thread_t * const thread) { + + if (!thread) return controller_thread_enable_none_e; + + if (f_thread_lock_read_try(&thread->lock.enable) != F_okay) { + for (f_time_spec_t time; ; ) { + + memset(&time, 0, sizeof(f_time_spec_t)); + + controller_time_now(controller_thread_timeout_lock_read_seconds_d, controller_thread_timeout_lock_read_nanoseconds_d, &time); + if (f_thread_lock_read_timed(&time, &thread->lock.enable) == F_okay) break; + } // for + } + + const uint8_t enable = thread->enable; + + f_thread_unlock(&thread->lock.enable); + + return enable; + } +#endif // _di_controller_thread_enable_get_ + +#ifndef _di_controller_thread_enable_is_ + f_status_t controller_thread_enable_is(controller_thread_t * const thread, const uint8_t is_normal) { + + if (!thread) return F_false; + + const uint8_t enable = controller_thread_enable_get(thread); + + return is_normal ? enable == controller_thread_enable_e : enable; + } +#endif // _di_controller_thread_enable_is_ + +#ifndef _di_controller_thread_enable_set_ + f_status_t controller_thread_enable_set(controller_thread_t * const thread, const uint8_t value) { + + if (!thread) return F_status_set_error(F_parameter); + + if (f_thread_lock_write_try(&thread->lock.enable) != F_okay) { + for (f_time_spec_t time; ; ) { + + memset(&time, 0, sizeof(f_time_spec_t)); + + controller_time_now(controller_thread_timeout_lock_write_seconds_d, controller_thread_timeout_lock_write_nanoseconds_d, &time); + if (f_thread_lock_write_timed(&time, &thread->lock.enable) == F_okay) break; + } // for + } + + thread->enable = value; + + f_thread_unlock(&thread->lock.enable); + + return F_okay; + } +#endif // _di_controller_thread_enable_set_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/program/controller/main/thread/enable.h b/sources/c/program/controller/main/thread/enable.h new file mode 100644 index 0000000..9baa00b --- /dev/null +++ b/sources/c/program/controller/main/thread/enable.h @@ -0,0 +1,106 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the thread "enable" functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_thread_enable_h +#define _controller_main_thread_enable_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the enable state of the system in a thread-safe manner. + * + * This infinitely tries to obtain the read lock. + * + * Locks used on run: + * - main.thread.lock.enable (read lock). + * + * Locks held on exit: + * - None. + * + * @param thread + * The thread data. + * + * Must not be NULL. + * + * @return + * The enable status on success. + * + * controller_thread_enable_none_e on any error. + * + * @see controller_time_now() + * + * @see f_thread_lock_read_timed() + * @see f_thread_lock_read_try() + * @see f_thread_unlock() + */ +#ifndef _di_controller_thread_enable_get_ + extern uint8_t controller_thread_enable_get(controller_thread_t * const thread); +#endif // _di_controller_thread_enable_get_ + +/** + * Check to see if thread is enabled for the normal operations like Entry and Control or for Exit operations in a thread-safe manner. + * + * @param thread + * The thread data. + * + * Must not be NULL. + * @param is_normal + * If TRUE, then instance as if this operates during a normal operation (Entry and Control). + * If FALSE, then instance as if this operates during an Exit operation. + * + * @return + * F_true when enabled. + * F_false when disabled. + * + * @see controller_thread_enable_get() + */ +#ifndef _di_controller_thread_enable_is_ + extern f_status_t controller_thread_enable_is(controller_thread_t * const thread, const uint8_t is_normal); +#endif // _di_controller_thread_enable_is_ + +/** + * Set the enable state of the system in a thread-safe manner. + * + * This infinitely tries to obtain the write lock. + * + * Locks used on run: + * - main.thread.lock.enable (write lock). + * + * Locks held on exit: + * - None. + * + * @param thread + * The thread data. + * + * Must not be NULL. + * @param value + * The new value to assign to the thread enable. + * + * @return + * F_okay on success. + * + * F_parameter (with error bit) if a parmeter is invalid. + * + * @see f_thread_lock_write_timed() + * @see f_thread_lock_write_try() + * @see f_thread_unlock() + */ +#ifndef _di_controller_thread_enable_set_ + extern f_status_t controller_thread_enable_set(controller_thread_t * const thread, const uint8_t value); +#endif // _di_controller_thread_enable_set_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_thread_enable_h diff --git a/sources/c/program/controller/main/thread/entry.c b/sources/c/program/controller/main/thread/entry.c index c484f68..11b7c56 100644 --- a/sources/c/program/controller/main/thread/entry.c +++ b/sources/c/program/controller/main/thread/entry.c @@ -14,7 +14,7 @@ extern "C" { controller_t * const main = (controller_t *) argument; - if (!controller_thread_is_enabled(&main->thread, F_true)) return 0; + if (!controller_thread_enable_is(&main->thread, F_true)) return 0; f_status_t * const status = &main->thread.status; @@ -49,16 +49,9 @@ extern "C" { main->process.ready = controller_process_ready_fail_e; if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (main->process.flag & controller_process_flag_failsafe_e)) { - const uint8_t original_enabled = main->thread.enabled; + const uint8_t original_enabled = controller_thread_enable_get(&main->thread); - // Restore operating mode so that the failsafe can execute. - *status = f_thread_mutex_lock(&main->thread.lock.alert); - - if (F_status_is_error_not(*status)) { - main->thread.enabled = controller_thread_enabled_e; - - f_thread_mutex_unlock(&main->thread.lock.alert); - } + controller_thread_enable_set(&main->thread, controller_thread_enable_e); // Restart the signal main->thread to allow for signals while operating the failsafe Items. if (!main->thread.id_signal) { @@ -73,15 +66,7 @@ extern "C" { controller_print_error_failsafe_item(&main->program.error, &main->thread, main->process.entry.items.array[main->process.failsafe_item_id].name); } else { - - // Restore operating mode to value prior to failsafe mode. - *status = f_thread_mutex_lock(&main->thread.lock.alert); - - if (F_status_is_error_not(*status)) { - main->thread.enabled = original_enabled; - - f_thread_mutex_unlock(&main->thread.lock.alert); - } + controller_thread_enable_set(&main->thread, original_enabled); *status = F_failure; } @@ -113,7 +98,7 @@ extern "C" { // According to the manpages, pthread_exit() calls exit(0), which the value of main->program.child should be returned instead. if (main->program.child) exit(main->program.child); } else { - controller_lock_signal(&main->thread.lock.alert_condition, &main->thread.lock.alert); + f_thread_condition_signal_all(&main->thread.lock.alert_condition); } return 0; @@ -159,17 +144,11 @@ extern "C" { if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (main->process.flag & controller_process_flag_failsafe_e)) { - const uint8_t original_enabled = main->thread.enabled; + const uint8_t original_enabled = controller_thread_enable_get(&main->thread); // Restore operating mode so that the failsafe can execute. if (F_status_set_fine(*status) == F_execute) { - *status = f_thread_mutex_lock(&main->thread.lock.alert); - - if (F_status_is_error_not(*status)) { - main->thread.enabled = controller_thread_enabled_exit_e; - - f_thread_mutex_unlock(&main->thread.lock.alert); - } + controller_thread_enable_set(&main->thread, controller_thread_enable_exit_e); // Restart the signal thread to allow for signals while operating the failsafe Items. if (!main->thread.id_signal) { @@ -185,15 +164,7 @@ extern "C" { controller_print_error_failsafe_item(&main->program.error, &main->thread, main->process.entry.items.array[main->process.failsafe_item_id].name); } else { - - // Restore operating mode to value prior to failsafe mode. - *status = f_thread_mutex_lock(&main->thread.lock.alert); - - if (F_status_is_error_not(*status)) { - main->thread.enabled = original_enabled; - - f_thread_mutex_unlock(&main->thread.lock.alert); - } + controller_thread_enable_set(&main->thread, original_enabled); *status = F_failure; } @@ -214,8 +185,9 @@ extern "C" { controller_delete(main); } else { - controller_thread_instance_force_set_disable(main); - controller_lock_signal(&main->thread.lock.alert_condition, &main->thread.lock.alert); + controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); + + f_thread_condition_signal_all(&main->thread.lock.alert_condition); } return 0; diff --git a/sources/c/program/controller/main/thread/instance.c b/sources/c/program/controller/main/thread/instance.c index fba2a57..96d357c 100644 --- a/sources/c/program/controller/main/thread/instance.c +++ b/sources/c/program/controller/main/thread/instance.c @@ -8,7 +8,7 @@ extern "C" { void controller_thread_instance(controller_instance_t * const instance, const uint8_t is_normal) { if (!instance || !instance->main) return; - if (!controller_thread_is_enabled(&instance->main->thread, is_normal)) return; + if (!controller_thread_enable_is(&instance->main->thread, is_normal)) return; const f_status_t status = controller_rule_instance_perform(instance, controller_instance_option_asynchronous_e); @@ -34,7 +34,7 @@ extern "C" { f_time_spec_t time; do { - if (!controller_thread_is_enabled(&main->thread, is_normal)) return; + if (!controller_thread_enable_is(&main->thread, is_normal)) return; memset((void *) &time, 0, sizeof(struct timespec)); @@ -43,13 +43,13 @@ extern "C" { status = f_thread_mutex_lock_timed(&time, &main->thread.lock.cancel); if (F_status_is_error(status)) return; - } while (status == F_time); + } while (status != F_okay); status = F_okay; } // Only cancel when enabled. - if (!controller_thread_is_enabled(&main->thread, is_normal)) { + if (!controller_thread_enable_is(&main->thread, is_normal)) { f_thread_mutex_unlock(&main->thread.lock.cancel); return; @@ -85,28 +85,20 @@ extern "C" { } // for } - for (f_number_unsigned_t i = 0; i < controller_lock_mutex_max_retry_d; ++i) { - - status = f_thread_mutex_lock(&main->thread.lock.alert); - - if (F_status_is_error_not(status) || F_status_set_fine(status) == F_parameter || F_status_set_fine(status) == F_deadlock) break; - } // for + { + uint8_t enable = controller_thread_enable_exit_e; - if (F_status_is_error_not(status) && F_status_set_fine(status) != F_parameter && F_status_set_fine(status) != F_deadlock) { if (by == controller_thread_cancel_execute_e) { - main->thread.enabled = controller_thread_enabled_execute_e; + enable = controller_thread_enable_execute_e; } else if (by == controller_thread_cancel_exit_e) { - main->thread.enabled = controller_thread_enabled_not_e; + enable = controller_thread_enable_not_e; } else if (by == controller_thread_cancel_exit_execute_e) { - main->thread.enabled = controller_thread_enabled_exit_execute_e; - } - else { - main->thread.enabled = controller_thread_enabled_exit_e; + enable = controller_thread_enable_exit_execute_e; } - f_thread_mutex_unlock(&main->thread.lock.alert); + controller_thread_enable_set(&main->thread, enable); } if (main->thread.id_cleanup) { @@ -144,7 +136,7 @@ extern "C" { instance = main->thread.instances.array[i]; // Do not cancel Exit Instances, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) { + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) { continue; } @@ -177,7 +169,7 @@ extern "C" { instance = main->thread.instances.array[i]; // Do not wait for Instances, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) { + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) { continue; } @@ -238,7 +230,7 @@ extern "C" { instance = main->thread.instances.array[i]; // Do not kill Exit Instances, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) continue; + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) continue; if (instance->id_thread) { if (instance->childs.used) { @@ -266,7 +258,7 @@ extern "C" { for (j = 0; j < instance->childs.size; ++j) { // Do not kill Exit processes, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) continue; + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) continue; if (instance->childs.array[j]) { @@ -284,7 +276,7 @@ extern "C" { for (j = 0; j < instance->path_pids.used; ++j) { // Do not kill Exit processes, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) continue; + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) continue; if (f_file_exists(instance->path_pids.array[j], F_true) == F_true) { status = controller_file_pid_read(instance->path_pids.array[j], &pid); @@ -303,7 +295,7 @@ extern "C" { while (instance->childs.used) { // Do not shrink below an Exit Instances, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) break; + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) break; if (instance->childs.array[j] > 0) break; --instance->childs.used; @@ -313,7 +305,7 @@ extern "C" { while (instance->path_pids.used) { // Do not shrink below an Exit Instances, when not performing "execute" during exit. - if (instance->type == controller_instance_type_exit_e && main->thread.enabled != controller_thread_enabled_exit_execute_e) break; + if (instance->type == controller_instance_type_exit_e && controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_execute_e) break; if (instance->path_pids.array[j].used) break; --instance->path_pids.used; @@ -327,7 +319,7 @@ extern "C" { #ifndef _di_controller_thread_instance_exit_ void controller_thread_instance_exit(controller_t * const main) { - if (!main || main->thread.enabled != controller_thread_enabled_exit_e) return; + if (!main || controller_thread_enable_get(&main->thread) != controller_thread_enable_exit_e) return; if (main->process.ready == controller_process_ready_done_e) { @@ -356,7 +348,7 @@ extern "C" { controller_print_error_status(&main->program.error, macro_controller_f(f_thread_create), F_status_set_fine(status)); } - controller_thread_instance_force_set_disable(main); + controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); } else { f_time_spec_t time = f_time_spec_t_initialize; @@ -371,9 +363,9 @@ extern "C" { f_thread_mutex_unlock(&main->thread.lock.alert); - } while (F_status_is_error_not(status) && main->thread.enabled == controller_thread_enabled_exit_e); + } while (F_status_is_error_not(status) && controller_thread_enable_get(&main->thread) == controller_thread_enable_exit_e); - if (F_status_is_error(status)) controller_thread_instance_force_set_disable(main); + if (F_status_is_error(status)) controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); } // The sigtimedwait() function that is run inside of signal must be interrupted directly via f_thread_signal_write(). @@ -387,46 +379,11 @@ extern "C" { controller_thread_instance_cancel(main, F_false, controller_thread_cancel_exit_e); } else { - controller_thread_instance_force_set_disable(main); + controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); } } #endif // _di_controller_thread_instance_exit_ -#ifndef _di_controller_thread_instance_force_set_disable_ - void controller_thread_instance_force_set_disable(controller_t * const main) { - - if (!main) return; - - if (F_status_is_error_not(f_thread_mutex_lock(&main->thread.lock.alert))) { - main->thread.enabled = controller_thread_enabled_not_e; - - f_thread_mutex_unlock(&main->thread.lock.alert); - - return; - } - - f_time_spec_t time; - - for (uint8_t i = 0; i < controller_thread_exit_disable_force_times; ++i) { - - memset((void *) &time, 0, sizeof(struct timespec)); - - controller_time_now(controller_thread_timeout_exit_disable_force_seconds_d, controller_thread_timeout_exit_disable_force_nanoseconds_d, &time); - - if (F_status_is_error_not(f_thread_mutex_lock_timed(&time, &main->thread.lock.alert))) { - main->thread.enabled = controller_thread_enabled_not_e; - - f_thread_mutex_unlock(&main->thread.lock.alert); - - return; - } - } // for - - // Forcibly set disable regardless of the risk. - main->thread.enabled = controller_thread_enabled_not_e; - } -#endif // _di_controller_thread_instance_force_set_disable_ - #ifndef _di_controller_thread_instance_normal_ void * controller_thread_instance_normal(void * const argument) { diff --git a/sources/c/program/controller/main/thread/instance.h b/sources/c/program/controller/main/thread/instance.h index 1215dec..f8a3f3a 100644 --- a/sources/c/program/controller/main/thread/instance.h +++ b/sources/c/program/controller/main/thread/instance.h @@ -71,28 +71,6 @@ extern "C" { #endif // _di_controller_thread_instance_exit_ /** - * Set the execution state to disabled during exiting and force the case if need be. - * - * The program must exit during the Exit process. - * The state must be properly set. - * Perform a limited number of attempts to set the state to exiting. - * Should this fail, then force the case regardless of the risk. - * - * @param main - * The main program data. - * - * Must not be NULL. - * - * This does not alter main.setting.state.status. - * - * The main.thread.lock.alert lock will be set and then unset if possible. - * The main.thread.enabled will be updated and set to controller_thread_enabled_not_e. - */ -#ifndef _di_controller_thread_instance_force_set_disable_ - extern void controller_thread_instance_force_set_disable(controller_t * const main); -#endif // _di_controller_thread_instance_force_set_disable_ - -/** * Asynchronously execute a Rule process during normal operations. * * @param argument diff --git a/sources/c/program/controller/main/thread/is.c b/sources/c/program/controller/main/thread/is.c index 577d2e2..90f57f0 100644 --- a/sources/c/program/controller/main/thread/is.c +++ b/sources/c/program/controller/main/thread/is.c @@ -4,17 +4,6 @@ extern "C" { #endif -#ifndef _di_controller_thread_is_enabled_ - f_status_t controller_thread_is_enabled(controller_thread_t * const thread, const uint8_t is_normal) { - - if (!thread) return F_false; - - const uint8_t enabled = thread->enabled; - - return is_normal ? enabled == controller_thread_enabled_e : enabled; - } -#endif // _di_controller_thread_is_enabled_ - #ifndef _di_controller_thread_is_enabled_instance_ f_status_t controller_thread_is_enabled_instance(controller_instance_t * const instance) { @@ -27,7 +16,7 @@ extern "C" { #ifndef _di_controller_thread_is_enabled_instance_type_ f_status_t controller_thread_is_enabled_instance_type(controller_thread_t * const thread, const uint8_t type) { - return controller_thread_is_enabled(thread, type != controller_instance_type_exit_e); + return controller_thread_enable_is(thread, type != controller_instance_type_exit_e); } #endif // _di_controller_thread_is_enabled_instance_type_ diff --git a/sources/c/program/controller/main/thread/is.h b/sources/c/program/controller/main/thread/is.h index d645816..3675eb5 100644 --- a/sources/c/program/controller/main/thread/is.h +++ b/sources/c/program/controller/main/thread/is.h @@ -17,25 +17,6 @@ extern "C" { #endif /** - * Check to see if thread is enabled for the normal operations like Entry and Control or for Exit operations. - * - * @param thread - * The thread data. - * - * Must not be NULL. - * @param is_normal - * If TRUE, then instance as if this operates during a normal operation (Entry and Control). - * If FALSE, then instance as if this operates during an Exit operation. - * - * @return - * F_true when enabled. - * F_false when disabled. - */ -#ifndef _di_controller_thread_is_enabled_ - extern f_status_t controller_thread_is_enabled(controller_thread_t * const thread, const uint8_t is_normal); -#endif // _di_controller_thread_is_enabled_ - -/** * Check to see if thread is enabled for the normal operations like Entry and Control or for Exit operations for some instance. * * @param instance @@ -64,9 +45,9 @@ extern "C" { * The instance type to use when checking if thread is enabled. * * @return - * Success from controller_thread_is_enabled(). + * Success from controller_thread_enable_is(). * - * @see controller_thread_is_enabled() + * @see controller_thread_enable_is() */ #ifndef _di_controller_thread_is_enabled_instance_type_ extern f_status_t controller_thread_is_enabled_instance_type(controller_thread_t * const thread, const uint8_t type); diff --git a/sources/c/program/controller/main/thread/rule.c b/sources/c/program/controller/main/thread/rule.c index 4506f59..3f421b1 100644 --- a/sources/c/program/controller/main/thread/rule.c +++ b/sources/c/program/controller/main/thread/rule.c @@ -14,7 +14,7 @@ extern "C" { controller_t * const main = (controller_t *) argument; - if (!controller_thread_is_enabled(&main->thread, F_true)) return 0; + if (!controller_thread_enable_is(&main->thread, F_true)) return 0; return 0; } diff --git a/sources/c/program/controller/main/thread/signal.c b/sources/c/program/controller/main/thread/signal.c index 86762b2..e5dd9fa 100644 --- a/sources/c/program/controller/main/thread/signal.c +++ b/sources/c/program/controller/main/thread/signal.c @@ -8,13 +8,13 @@ extern "C" { void controller_thread_signal(controller_t * const main, const uint8_t is_normal) { if (!main) return; - if (!controller_thread_is_enabled(&main->thread, is_normal)) return; + if (!controller_thread_enable_is(&main->thread, is_normal)) return; if (!(main->setting.flag & controller_main_flag_interruptible_d)) return; siginfo_t information; f_time_spec_t time = f_time_spec_t_initialize; - while (controller_thread_is_enabled(&main->thread, is_normal)) { + while (controller_thread_enable_is(&main->thread, is_normal)) { memset((void *) &information, 0, sizeof(siginfo_t)); @@ -30,7 +30,7 @@ extern "C" { // Send F_signal_reserved_35 to cleanup process to reap child processes. if (information.si_signo == F_signal_child || information.si_signo == F_signal_reserved_35) { - controller_lock_signal(&main->thread.lock.reap_condition, &main->thread.lock.reap); + f_thread_condition_signal_all(&main->thread.lock.reap_condition); continue; } @@ -38,7 +38,7 @@ extern "C" { if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) { main->thread.signal = information.si_signo; - controller_lock_signal(&main->thread.lock.reap_condition, &main->thread.lock.reap); + f_thread_condition_signal_all(&main->thread.lock.reap_condition); controller_thread_instance_cancel(main, is_normal, controller_thread_cancel_signal_e); break; @@ -56,7 +56,7 @@ extern "C" { if (!interrupt->main) return; - if (!controller_thread_is_enabled(&interrupt->main->thread, interrupt->is_normal)) { + if (!controller_thread_enable_is(&interrupt->main->thread, interrupt->is_normal)) { interrupt->main->program.signal_received = F_signal_abort; interrupt->main->setting.state.status = F_status_set_error(F_interrupt); } @@ -76,7 +76,7 @@ extern "C" { if (!interrupt->main) return; - if (!controller_thread_is_enabled(&interrupt->main->thread, interrupt->is_normal)) { + if (!controller_thread_enable_is(&interrupt->main->thread, interrupt->is_normal)) { interrupt->main->program.signal_received = F_signal_abort; interrupt->main->setting.state.status = F_status_set_error(F_interrupt); }