From: Kevin Day Date: Sun, 21 Sep 2025 02:04:57 +0000 (-0500) Subject: Progress: Begin changes to locking. X-Git-Tag: 0.7.3~25 X-Git-Url: https://www.git.kevux.org/?a=commitdiff_plain;h=857a9aca19d8763d70178a7d3ded210460dcf81c;p=controller Progress: Begin changes to locking. I was investigating different locking change structures then I got interrupted. I hadn't had a chance to get back to this yet and this commit is done to save the state. These changes very likely will not work and I may end up doing this differently once I get back to this at a future date. --- diff --git a/data/build/settings b/data/build/settings index e8f614f..e6eb8d2 100644 --- a/data/build/settings +++ b/data/build/settings @@ -57,7 +57,7 @@ build_sources_library common/type/cache.c common/type/control.c common/type/entr build_sources_library common/string/general.c common/string/rule.c build_sources_library convert.c instance.c instance/prepare.c instance/wait.c build_sources_library entry.c entry/action.c entry/preprocess.c entry/process.c entry/setting.c -build_sources_library file.c lock.c path.c process.c +build_sources_library file.c lock.c mutex.c path.c process.c build_sources_library rule.c rule/action.c rule/execute.c rule/expand.c rule/instance.c rule/is.c rule/item.c rule/parameter.c rule/read.c rule/setting.c rule/wait.c build_sources_library perform.c build_sources_library print/debug.c print/debug/rule/action.c print/debug/rule/execute.c print/debug/rule/instance.c print/debug/perform/control.c print/debug/perform/pid.c @@ -80,7 +80,7 @@ build_sources_headers common/string/general.h common/string/rule.h build_sources_headers common/type/cache.h common/type/control.h common/type/defs.h common/type/entry.h common/type/execute.h common/type/instance.h common/type/interrupt.h common/type/lock.h common/type/process.h common/type/rule.h common/type/thread.h build_sources_headers convert.h instance.h instance/prepare.h instance/wait.h build_sources_headers entry.h entry/action.h entry/preprocess.h entry/process.h entry/setting.h -build_sources_headers file.h lock.h path.h process.h +build_sources_headers file.h lock.h mutex.h path.h process.h build_sources_headers rule.h rule/action.h rule/execute.h rule/expand.h rule/instance.h rule/is.h rule/item.h rule/parameter.h rule/read.h rule/setting.h rule/wait.h build_sources_headers perform.h build_sources_headers print/debug.h print/debug/rule/action.h print/debug/rule/execute.h print/debug/rule/instance.h print/debug/perform/control.h print/debug/perform/pid.h diff --git a/data/build/stand_alone/settings.controller b/data/build/stand_alone/settings.controller index 170dda9..03316b0 100644 --- a/data/build/stand_alone/settings.controller +++ b/data/build/stand_alone/settings.controller @@ -104,7 +104,7 @@ build_sources_program program/controller/main/common/type/cache.c program/contro build_sources_program program/controller/main/common/string/general.c program/controller/main/common/string/rule.c build_sources_program program/controller/main/convert.c program/controller/main/instance.c program/controller/main/instance/prepare.c program/controller/main/instance/wait.c build_sources_program program/controller/main/entry.c program/controller/main/entry/action.c program/controller/main/entry/preprocess.c program/controller/main/entry/process.c program/controller/main/entry/setting.c -build_sources_program program/controller/main/file.c program/controller/main/lock.c program/controller/main/path.c program/controller/main/process.c +build_sources_program program/controller/main/file.c program/controller/main/lock.c program/controller/main/mutex.c program/controller/main/path.c program/controller/main/process.c build_sources_program program/controller/main/rule.c program/controller/main/rule/action.c program/controller/main/rule/execute.c program/controller/main/rule/expand.c program/controller/main/rule/instance.c program/controller/main/rule/is.c program/controller/main/rule/item.c program/controller/main/rule/parameter.c program/controller/main/rule/read.c program/controller/main/rule/setting.c program/controller/main/rule/wait.c build_sources_program program/controller/main/perform.c build_sources_program program/controller/main/print/debug.c program/controller/main/print/debug/rule/action.c program/controller/main/print/debug/rule/execute.c program/controller/main/print/debug/rule/instance.c program/controller/main/print/debug/perform/control.c program/controller/main/print/debug/perform/pid.c diff --git a/data/build/stand_alone/settings.init b/data/build/stand_alone/settings.init index 562897f..deae549 100644 --- a/data/build/stand_alone/settings.init +++ b/data/build/stand_alone/settings.init @@ -104,7 +104,7 @@ build_sources_program program/controller/main/common/type/cache.c program/contro build_sources_program program/controller/main/common/string/general.c program/controller/main/common/string/rule.c build_sources_program program/controller/main/convert.c program/controller/main/instance.c program/controller/main/instance/prepare.c program/controller/main/instance/wait.c build_sources_program program/controller/main/entry.c program/controller/main/entry/action.c program/controller/main/entry/preprocess.c program/controller/main/entry/process.c program/controller/main/entry/setting.c -build_sources_program program/controller/main/file.c program/controller/main/lock.c program/controller/main/path.c program/controller/main/process.c +build_sources_program program/controller/main/file.c program/controller/main/lock.c program/controller/main/mutex.c program/controller/main/path.c program/controller/main/process.c build_sources_program program/controller/main/rule.c program/controller/main/rule/action.c program/controller/main/rule/execute.c program/controller/main/rule/expand.c program/controller/main/rule/instance.c program/controller/main/rule/is.c program/controller/main/rule/item.c program/controller/main/rule/parameter.c program/controller/main/rule/read.c program/controller/main/rule/setting.c program/controller/main/rule/wait.c build_sources_program program/controller/main/perform.c build_sources_program program/controller/main/print/debug.c program/controller/main/print/debug/rule/action.c program/controller/main/print/debug/rule/execute.c program/controller/main/print/debug/rule/instance.c program/controller/main/print/debug/perform/control.c program/controller/main/print/debug/perform/pid.c diff --git a/sources/c/program/controller/init/signal.c b/sources/c/program/controller/init/signal.c index c01c219..b37f74b 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_enable_is(&main->thread, is_normal)) return; + if (!controller_thread_enable_is_normal(&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_enable_is(&main->thread, is_normal)) { + while (controller_thread_enable_is_normal(&main->thread, is_normal)) { memset((void *) &information, 0, sizeof(siginfo_t)); diff --git a/sources/c/program/controller/main/common/type/instance.c b/sources/c/program/controller/main/common/type/instance.c index 40d4e0a..7241ebb 100644 --- a/sources/c/program/controller/main/common/type/instance.c +++ b/sources/c/program/controller/main/common/type/instance.c @@ -71,7 +71,7 @@ extern "C" { } if (F_status_is_error_not(status)) { - status = controller_lock_create_mutex_full(&(*instance)->wait); + status = controller_mutex_full_create(&(*instance)->wait); } if (F_status_is_error_not(status)) { diff --git a/sources/c/program/controller/main/common/type/instance.h b/sources/c/program/controller/main/common/type/instance.h index 94fbe29..8ace18b 100644 --- a/sources/c/program/controller/main/common/type/instance.h +++ b/sources/c/program/controller/main/common/type/instance.h @@ -26,6 +26,9 @@ extern "C" { * * The typedef for this is located in the defs.h header. * + * The "active" lock is used for asynchronous operations. + * This can be used to check if anything is asynchronously operating the rule. + * * Properties: * - id: The ID of this process relative to the processes array. * - id_thread: The thread ID, a valid ID when state is "active", and an invalid ID when the state is "busy". diff --git a/sources/c/program/controller/main/common/type/lock.h b/sources/c/program/controller/main/common/type/lock.h index 5e55fbc..d4f81d1 100644 --- a/sources/c/program/controller/main/common/type/lock.h +++ b/sources/c/program/controller/main/common/type/lock.h @@ -29,15 +29,18 @@ extern "C" { * * Properties: * - flag: A set of flags associated with the locks. + * * - alert: The alert mutex lock for waking up on alerts. * - cancel: The cancel mutex lock for locking the cancel operation. * - entry: The entry mutex lock for entry reading (preventing entry and exit from overlapping). * - 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. * - signal: The signal r/w lock. + * * - alert_condition: The condition used to trigger alerts. * - reap_condition: The condition used to trigger zombie reaping. */ diff --git a/sources/c/program/controller/main/controller.h b/sources/c/program/controller/main/controller.h index f9a1362..46aba6b 100644 --- a/sources/c/program/controller/main/controller.h +++ b/sources/c/program/controller/main/controller.h @@ -108,6 +108,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 f783e5c..107a726 100644 --- a/sources/c/program/controller/main/entry.c +++ b/sources/c/program/controller/main/entry.c @@ -9,7 +9,7 @@ extern "C" { if (!main) return F_status_set_error(F_parameter); - f_status_t status = controller_lock_mutex_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.entry); + f_status_t status = controller_mutex_lock_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.entry); if (F_status_is_error(status)) return status; status = controller_entry_read_do(main, is_entry); @@ -125,7 +125,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_enable_is(&main->thread, is_entry); ++i) { + for (i = 0; i < main->thread.cache.object_items.used && controller_thread_enable_is_normal(&main->thread, is_entry); ++i) { code &= ~0x2; at = 0; @@ -282,7 +282,7 @@ extern "C" { for (j = 0; j < entry->items.array[i].actions.used; ++j) { - if (!controller_thread_enable_is(&main->thread, is_entry)) { + if (!controller_thread_enable_is_normal(&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.h b/sources/c/program/controller/main/entry.h index 67a2a2f..65ee230 100644 --- a/sources/c/program/controller/main/entry.h +++ b/sources/c/program/controller/main/entry.h @@ -35,10 +35,10 @@ extern "C" { * Success from controller_entry_read_do(). * * Errors (with error bit) from: controller_entry_read_do(). - * Errors (with error bit) from: controller_lock_mutex_standard(). + * Errors (with error bit) from: controller_mutex_lock_standard(). * * @see controller_entry_read_do() - * @see controller_lock_mutex_standard() + * @see controller_mutex_lock_standard() */ #ifndef _di_controller_entry_read_ extern f_status_t controller_entry_read(controller_t * const main, const uint8_t is_entry); diff --git a/sources/c/program/controller/main/entry/preprocess.c b/sources/c/program/controller/main/entry/preprocess.c index b87b5c3..4e2f24c 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_enable_is(&main->thread, is_entry)) { + while (controller_thread_enable_is_normal(&main->thread, is_entry)) { actions = &entry->items.array[cache->ats.array[at_i]].actions; - for (; cache->ats.array[at_j] < actions->used && controller_thread_enable_is(&main->thread, is_entry); ++cache->ats.array[at_j]) { + for (; cache->ats.array[at_j] < actions->used && controller_thread_enable_is_normal(&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_enable_is(&main->thread, is_entry); ++i) { + for (i = 1; i < entry->items.used && controller_thread_enable_is_normal(&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_enable_is(&main->thread, is_entry)) return F_status_set_error(F_interrupt); + if (!controller_thread_enable_is_normal(&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/preprocess.h b/sources/c/program/controller/main/entry/preprocess.h index d92601b..dc3f975 100644 --- a/sources/c/program/controller/main/entry/preprocess.h +++ b/sources/c/program/controller/main/entry/preprocess.h @@ -32,13 +32,11 @@ extern "C" { * F_recurse (with error bit) on a recursion error. * F_valid_not (with error bit) on invalid Entry Item, Entry Item Action, or Entry Item Action value. * - * Errors (with error bit) from: macro_f_number_unsigneds_t_increase_by(). * Errors (with error bit) from: f_string_dynamic_append(). * * This will detect and report all errors, but only the first error is returned. * Memory related errors return immediately. - * @see macro_f_number_unsigneds_t_increase_by() * @see f_string_dynamic_append() */ #ifndef _di_controller_entry_preprocess_ diff --git a/sources/c/program/controller/main/entry/process.c b/sources/c/program/controller/main/entry/process.c index 2e99aa0..9e146e2 100644 --- a/sources/c/program/controller/main/entry/process.c +++ b/sources/c/program/controller/main/entry/process.c @@ -27,6 +27,7 @@ extern "C" { cache->ats.used = 0; cache->stack.used = 0; + // @todo Should this have a separate cache for entries and rules (this is important if/when an exit is running while rules are running)? cache->action.line_action = 0; cache->action.line_item = 0; cache->action.name_action.used = 0; @@ -68,11 +69,11 @@ extern "C" { if (F_status_is_error(status)) return status; } - while (controller_thread_enable_is(&main->thread, is_entry)) { + while (controller_thread_enable_is_normal(&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_enable_is(&main->thread, is_entry); ++cache->ats.array[at_j]) { + for (; cache->ats.array[at_j] < entry_actions->used && controller_thread_enable_is_normal(&main->thread, is_entry); ++cache->ats.array[at_j]) { entry_action = &entry_actions->array[cache->ats.array[at_j]]; @@ -230,7 +231,7 @@ extern "C" { controller_print_message_entry_item_rule(&main->program.message, entry, entry_action, is_entry, alias_rule); } - if (!controller_thread_enable_is(&main->thread, is_entry)) break; + if (!controller_thread_enable_is_normal(&main->thread, is_entry)) break; // The Rule is not yet loaded, ensure that it is loaded. if (status != F_true) { @@ -279,7 +280,7 @@ extern "C" { break; } - if (F_status_set_fine(status) == F_interrupt || !controller_thread_enable_is(&main->thread, is_entry)) { + if (F_status_set_fine(status) == F_interrupt || !controller_thread_enable_is_normal(&main->thread, is_entry)) { f_thread_unlock(&main->thread.lock.rule); break; @@ -464,7 +465,7 @@ extern "C" { } } // while - if (!controller_thread_enable_is(&main->thread, is_entry)) return F_status_set_error(F_interrupt); + if (!controller_thread_enable_is_normal(&main->thread, is_entry)) return F_status_set_error(F_interrupt); if (status == F_child) return status; if (status_lock != F_okay) return status_lock; diff --git a/sources/c/program/controller/main/entry/process.h b/sources/c/program/controller/main/entry/process.h index e4294f6..db4bf50 100644 --- a/sources/c/program/controller/main/entry/process.h +++ b/sources/c/program/controller/main/entry/process.h @@ -40,12 +40,10 @@ extern "C" { * * Errors (with error bit) from: f_string_dynamic_append_nulless(). * - * Errors (with error bit) from: macro_f_number_unsigneds_t_increase_by(). * Errors (with error bit) from: controller_perform_ready(). * * @see f_string_dynamic_append_nulless() * - * @see macro_f_number_unsigneds_t_increase_by() * @see controller_perform_ready() */ #ifndef _di_controller_entry_process_ diff --git a/sources/c/program/controller/main/instance/wait.c b/sources/c/program/controller/main/instance/wait.c index 3b9987d..d35c50a 100644 --- a/sources/c/program/controller/main/instance/wait.c +++ b/sources/c/program/controller/main/instance/wait.c @@ -18,7 +18,7 @@ extern "C" { uint8_t count = 0; do { - status = controller_lock_mutex_instance(instance, &instance->wait); + status = controller_mutex_lock_instance(instance, &instance->wait); if (!controller_thread_is_enabled_instance(instance)) return F_status_set_error(F_interrupt); if (F_status_is_error(status)) break; @@ -58,7 +58,7 @@ extern "C" { if (status != F_time) { - // move up the wait timer after a trigger was received. + // Move up the wait timer after a trigger was received. if (count < controller_thread_timeout_wait_2_before_d) { count = 0; } diff --git a/sources/c/program/controller/main/lock.c b/sources/c/program/controller/main/lock.c index 5444cc0..cb98750 100644 --- a/sources/c/program/controller/main/lock.c +++ b/sources/c/program/controller/main/lock.c @@ -9,19 +9,19 @@ extern "C" { if (!lock) return F_status_set_error(F_parameter); - f_status_t status = controller_lock_create_mutex_full(&lock->alert); + f_status_t status = controller_mutex_full_create(&lock->alert); if (F_status_is_error(status)) return status; - status = controller_lock_create_mutex_full(&lock->cancel); + status = controller_mutex_full_create(&lock->cancel); if (F_status_is_error_not(status)) { - status = controller_lock_create_mutex_full(&lock->entry); + status = controller_mutex_full_create(&lock->entry); if (F_status_is_error_not(status)) { - status = controller_lock_create_mutex_full(&lock->print); + status = controller_mutex_full_create(&lock->print); if (F_status_is_error_not(status)) { - status = controller_lock_create_mutex_full(&lock->reap); + status = controller_mutex_full_create(&lock->reap); if (F_status_is_error_not(status)) { status = f_thread_lock_create(0, &lock->enable); @@ -47,12 +47,12 @@ extern "C" { } if (F_status_is_error(status)) { - f_thread_lock_delete(&lock->rule); + f_thread_lock_delete(&lock->signal); } } if (F_status_is_error(status)) { - f_thread_lock_delete(&lock->signal); + f_thread_lock_delete(&lock->rule); } } @@ -98,79 +98,6 @@ extern "C" { } #endif // _di_controller_lock_create_ -#ifndef _di_controller_lock_create_mutex_full_ - f_status_t controller_lock_create_mutex_full(f_thread_mutex_full_t * const full) { - - if (!full) return F_status_set_error(F_parameter); - - f_status_t status = f_thread_mutex_attribute_create(&full->attribute); - if (F_status_is_error(status)) return status; - - status = f_thread_mutex_attribute_type_set(f_thread_mutex_type_error_check_d, &full->attribute); - - if (F_status_is_error_not(status)) { - status = f_thread_mutex_create(0, &full->mutex); - } - - // De-allocate the attribute set on failure. - if (F_status_is_error(status)) { - f_thread_mutex_attribute_delete(&full->attribute); - - return status; - } - - return F_okay; - } -#endif // _di_controller_lock_create_mutex_full_ - -#ifndef _di_controller_lock_mutex_ - f_status_t controller_lock_mutex(const uint8_t is_normal, const uint8_t check, const time_t seconds, const long nanoseconds, controller_thread_t * const thread, f_thread_mutex_full_t * const full) { - - if (!thread || !full) return F_status_set_error(F_parameter); - - f_status_t status = 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); - - status = f_thread_mutex_lock_timed(&time, &full->mutex); - - if (status == F_time) { - if (check) { - if (check == controller_lock_check_flag_error_d) { - if (F_status_is_error(status)) return status; - } - else if (!controller_thread_enable_is(thread, is_normal)) return F_status_set_error(F_interrupt); - } - } - else if (status == F_okay) { - break; - } - } // for - - return F_okay; - } -#endif // _di_controller_lock_mutex_ - -#ifndef _di_controller_lock_mutex_standard_ - f_status_t controller_lock_mutex_standard(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_mutex_full_t * const full) { - - return controller_lock_mutex(is_normal, check, controller_thread_timeout_lock_read_seconds_d, controller_thread_timeout_lock_read_nanoseconds_d, thread, full); - } -#endif // _di_controller_lock_mutex_standard_ - -#ifndef _di_controller_lock_mutex_instance_ - f_status_t controller_lock_mutex_instance(controller_instance_t * const instance, f_thread_mutex_full_t * const full) { - - if (!instance) return F_status_set_error(F_parameter); - - return controller_lock_mutex_standard(instance->type != controller_instance_type_exit_e, controller_lock_check_flag_yes_d, &instance->main->thread, full); - } -#endif // _di_controller_lock_mutex_instance_ - #ifndef _di_controller_lock_read_ f_status_t controller_lock_read(const uint8_t is_normal, const uint8_t check, const time_t seconds, const long nanoseconds, controller_thread_t * const thread, f_thread_lock_t * const lock) { @@ -191,7 +118,7 @@ extern "C" { if (check == controller_lock_check_flag_error_d) { if (F_status_is_error(status)) return status; } - else if (!controller_thread_enable_is(thread, is_normal)) return F_status_set_error(F_interrupt); + else if (!controller_thread_enable_is_normal(thread, is_normal)) return F_status_set_error(F_interrupt); } } else if (status == F_okay) { @@ -237,7 +164,7 @@ extern "C" { if (check == controller_lock_check_flag_error_d) { if (F_status_is_error(status)) return status; } - else if (!controller_thread_enable_is(thread, is_normal)) return F_status_set_error(F_interrupt); + else if (!controller_thread_enable_is_normal(thread, is_normal)) return F_status_set_error(F_interrupt); } } else if (status == F_okay) { diff --git a/sources/c/program/controller/main/lock.h b/sources/c/program/controller/main/lock.h index bf21743..5ce5448 100644 --- a/sources/c/program/controller/main/lock.h +++ b/sources/c/program/controller/main/lock.h @@ -31,146 +31,17 @@ extern "C" { * * Errors (with error bit) from: f_thread_lock_delete(). * Errors (with error bit) from: f_thread_mutex_full_delete(). - * Errors (with error bit) from: controller_lock_create_mutex_full(). + * Errors (with error bit) from: controller_mutex_full_create(). * * @see f_thread_lock_delete() * @see f_thread_mutex_full_delete() - * @see controller_lock_create_mutex_full() + * @see controller_mutex_full_create() */ #ifndef _di_controller_lock_create_ extern f_status_t controller_lock_create(controller_lock_t * const lock); #endif // _di_controller_lock_create_ /** - * Perform the initial, required, allocation for a single full mutex lock. - * - * The mutex attribute will be deallocated on any errors following its allocation before returning. - * - * @param full - * The full mutex lock to allocate. - * - * Must not be NULL. - * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * - * Errors (with error bit) from: f_thread_mutex_attribute_create(). - * Errors (with error bit) from: f_thread_mutex_attribute_delete(). - * Errors (with error bit) from: f_thread_mutex_attribute_type_set(). - * Errors (with error bit) from: f_thread_mutex_create(). - * - * @see f_thread_mutex_attribute_create() - * @see f_thread_mutex_attribute_delete() - * @see f_thread_mutex_attribute_type_set() - * @see f_thread_mutex_create() - */ -#ifndef _di_controller_lock_create_mutex_full_ - extern f_status_t controller_lock_create_mutex_full(f_thread_mutex_full_t * const full); -#endif // _di_controller_lock_create_mutex_full_ - -/** - * Wait to get a mutex lock. - * - * Given a mutex lock, periodically check to see if main thread is disabled while waiting. - * - * @param is_normal - * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is() and returns on any lock error. - * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. - * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. - * @param check - * If TRUE, then check if the state is enabled and if it is not then abort. - * If FALSE, then do not check if the state is enabled and keep looping. - * @param seconds - * The seconds to add to current time. - * @param nanoseconds - * The nanoseconds to add to current time. - * @param thread - * The thread data used to determine if the main thread is disabled or not. - * - * Must not be NULL. - * @param full - * The full mutex to lock. - * - * Must not be NULL. - * - * @return - * F_okay on success. - * - * F_interrupt (with error bit set) on (exit) signal received, lock will not be set when this is returned. - * F_parameter (with error bit) if a parameter is invalid. - * - * Status from: f_thread_mutex_lock_timed(). - * - * Errors (with error bit) from: f_thread_mutex_lock_timed(). - * - * @see f_thread_mutex_lock_timed() - */ -#ifndef _di_controller_lock_mutex_ - extern f_status_t controller_lock_mutex(const uint8_t is_normal, const uint8_t check, const time_t seconds, const long nanoseconds, controller_thread_t * const thread, f_thread_mutex_full_t * const full); -#endif // _di_controller_lock_mutex_ - -/** - * Wait to get a mutex lock, using standard seconds and nanoseconds. - * - * Given a mutex lock, periodically check to see if main thread is disabled while waiting. - * - * @param is_normal - * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is() and returns on any lock error. - * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. - * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. - * @param check - * If TRUE, then check if the state is enabled and if it is not then abort. - * If FALSE, then do not check if the state is enabled and keep looping. - * @param thread - * The thread data used to determine if the main thread is disabled or not. - * - * Must not be NULL. - * @param full - * The full mutex to lock. - * - * Must not be NULL. - * - * @return - * Status from: controller_lock_mutex(). - * - * Errors (with error bit) from: controller_lock_mutex(). - * - * @see controller_lock_mutex() - */ -#ifndef _di_controller_lock_mutex_standard_ - extern f_status_t controller_lock_mutex_standard(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_mutex_full_t * const full); -#endif // _di_controller_lock_mutex_standard_ - -/** - * Wait to get a mutex lock for some instance. - * - * Given a mutex lock, periodically check to see if main thread is disabled while waiting. - * - * @param instance - * The instance to use when checking if thread is enabled. - * - * Must not be NULL. - * @param full - * The full mutex to lock. - * - * Must not be NULL. - * - * @return - * Status from: controller_lock_mutex(). - * - * 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_mutex_instance_ - extern f_status_t controller_lock_mutex_instance(controller_instance_t * const instance, f_thread_mutex_full_t * const full); -#endif // _di_controller_lock_mutex_instance_ - -/** * Wait to get a read lock. * * Given a r/w lock, periodically check to see if main thread is disabled while waiting. @@ -179,7 +50,7 @@ extern "C" { * If TRUE, then perform as if this operates during a normal operation (Entry and Control). * If FALSE, then perform as if this operates during a an Exit operation. * @param check - * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is() and returns on any lock error. + * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is_normal() and returns on any lock error. * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. * @param seconds @@ -220,7 +91,7 @@ extern "C" { * If TRUE, then perform as if this operates during a normal operation (Entry and Control). * If FALSE, then perform as if this operates during a an Exit operation. * @param check - * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is() and returns on any lock error. + * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is_normal() and returns on any lock error. * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. * @param thread @@ -279,7 +150,7 @@ extern "C" { * If TRUE, then perform as if this operates during a normal operation (Entry and Control). * If FALSE, then perform as if this operates during a an Exit operation. * @param check - * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is() and returns on any lock error. + * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is_normal() and returns on any lock error. * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. * @param seconds @@ -320,7 +191,7 @@ extern "C" { * If TRUE, then perform as if this operates during a normal operation (Entry and Control). * If FALSE, then perform as if this operates during a an Exit operation. * @param check - * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is() and returns on any lock error. + * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is_normal() and returns on any lock error. * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. * @param thread diff --git a/sources/c/program/controller/main/mutex.c b/sources/c/program/controller/main/mutex.c new file mode 100644 index 0000000..89e2cf5 --- /dev/null +++ b/sources/c/program/controller/main/mutex.c @@ -0,0 +1,106 @@ +#include "controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_mutex_condition_or_sleep_ + f_status_t controller_mutex_condition_or_sleep(f_thread_mutex_full_t * const full, f_thread_condition_t * const condition, f_time_spec_t * const delay) { + + if (!full || !condition || !delay) return F_status_set_error(F_parameter); + + f_status_t status = F_okay; + + if (f_thread_mutex_lock(&full->mutex) == F_okay) { + status = f_thread_condition_wait_timed(delay, condition, &full->mutex); + + if (F_status_is_error_not(status)) { + f_thread_mutex_unlock(&full->mutex); + } + } + else { + status = F_wait; + + f_time_sleep_spec(*delay, 0); + } + + return status; + } +#endif // _di_controller_mutex_condition_or_sleep_ + +#ifndef _di_controller_mutex_full_create_ + f_status_t controller_mutex_full_create(f_thread_mutex_full_t * const full) { + + if (!full) return F_status_set_error(F_parameter); + + f_status_t status = f_thread_mutex_attribute_create(&full->attribute); + if (F_status_is_error(status)) return status; + + status = f_thread_mutex_attribute_type_set(f_thread_mutex_type_error_check_d, &full->attribute); + + if (F_status_is_error_not(status)) { + status = f_thread_mutex_create(0, &full->mutex); + } + + // De-allocate the attribute set on failure. + if (F_status_is_error(status)) { + f_thread_mutex_attribute_delete(&full->attribute); + + return status; + } + + return F_okay; + } +#endif // _di_controller_mutex_full_create_ + +#ifndef _di_controller_mutex_lock_ + f_status_t controller_mutex_lock(const uint8_t is_normal, const uint8_t check, const time_t seconds, const long nanoseconds, controller_thread_t * const thread, f_thread_mutex_full_t * const full) { + + if (!thread || !full) return F_status_set_error(F_parameter); + + f_status_t status = 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); + + status = f_thread_mutex_lock_timed(&time, &full->mutex); + + if (status == F_time) { + if (check) { + if (check == controller_lock_check_flag_error_d) { + if (F_status_is_error(status)) return status; + } + else if (!controller_thread_enable_is_normal(thread, is_normal)) return F_status_set_error(F_interrupt); + } + } + else if (status == F_okay) { + break; + } + } // for + + return F_okay; + } +#endif // _di_controller_mutex_lock_ + +#ifndef _di_controller_mutex_lock_standard_ + f_status_t controller_mutex_lock_standard(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_mutex_full_t * const full) { + + return controller_mutex_lock(is_normal, check, controller_thread_timeout_lock_read_seconds_d, controller_thread_timeout_lock_read_nanoseconds_d, thread, full); + } +#endif // _di_controller_mutex_lock_standard_ + +#ifndef _di_controller_mutex_lock_instance_ + f_status_t controller_mutex_lock_instance(controller_instance_t * const instance, f_thread_mutex_full_t * const full) { + + if (!instance) return F_status_set_error(F_parameter); + + return controller_mutex_lock_standard(instance->type != controller_instance_type_exit_e, controller_lock_check_flag_yes_d, &instance->main->thread, full); + } +#endif // _di_controller_mutex_lock_instance_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/program/controller/main/mutex.h b/sources/c/program/controller/main/mutex.h new file mode 100644 index 0000000..7fe5174 --- /dev/null +++ b/sources/c/program/controller/main/mutex.h @@ -0,0 +1,193 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides lock functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_mutex_h +#define _controller_main_mutex_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wait to get a mutex condition or sleep if unable to get mutex lock. + * + * Lock a condition mutex. + * If that lock fails then do a timed wait (a sleep) for the delay. + * If that lock succeeds, then wait for a condition to be triggered or until delay is reached. + * (The condition will result in the lock being released. + * + * The mutex will be unlocked regardless of the return state when this function returns. + * + * @param full + * The full mutex to lock. + * + * Must not be NULL. + * + * @param condition + * The condition to wait on. + * + * Must not be NULL. + * + * @param delay + * The time delay to wait for the condition or to sleep for. + * + * Must not be NULL. + * + * @return + * Status from: f_thread_condition_wait_timed() on success and . + * F_wait on success if calling sleep (f_time_sleep_spec()). + * + * F_parameter (with error bit) if a parameter is invalid. + * + * Errors (with error bit) from: f_thread_condition_wait_timed(). + * Errors (with error bit) from: f_time_sleep_spec(). + * + * @see f_thread_condition_wait_timed() + * @see f_time_sleep_spec() + */ +#ifndef _di_controller_mutex_condition_or_sleep_ + extern f_status_t controller_mutex_condition_or_sleep(f_thread_mutex_full_t * const full, f_thread_condition_t * const condition, f_time_spec_t * const delay); +#endif // _di_controller_mutex_condition_or_sleep_ + +/** + * Perform the initial, required, allocation for a single full mutex lock. + * + * The mutex attribute will be deallocated on any errors following its allocation before returning. + * + * @param full + * The full mutex lock to allocate. + * + * Must not be NULL. + * + * @return + * F_okay on success. + * + * F_parameter (with error bit) if a parameter is invalid. + * + * Errors (with error bit) from: f_thread_mutex_attribute_create(). + * Errors (with error bit) from: f_thread_mutex_attribute_delete(). + * Errors (with error bit) from: f_thread_mutex_attribute_type_set(). + * Errors (with error bit) from: f_thread_mutex_create(). + * + * @see f_thread_mutex_attribute_create() + * @see f_thread_mutex_attribute_delete() + * @see f_thread_mutex_attribute_type_set() + * @see f_thread_mutex_create() + */ +#ifndef _di_controller_mutex_full_create_ + extern f_status_t controller_mutex_full_create(f_thread_mutex_full_t * const full); +#endif // _di_controller_mutex_full_create_ + +/** + * Wait to get a mutex lock. + * + * Given a mutex lock, periodically check to see if main thread is disabled while waiting. + * + * @param is_normal + * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is_normal() and returns on any lock error. + * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. + * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. + * @param check + * If TRUE, then check if the state is enabled and if it is not then abort. + * If FALSE, then do not check if the state is enabled and keep looping. + * @param seconds + * The seconds to add to current time. + * @param nanoseconds + * The nanoseconds to add to current time. + * @param thread + * The thread data used to determine if the main thread is disabled or not. + * + * Must not be NULL. + * @param full + * The full mutex to lock. + * + * Must not be NULL. + * + * @return + * F_okay on success. + * + * F_interrupt (with error bit set) on (exit) signal received, lock will not be set when this is returned. + * F_parameter (with error bit) if a parameter is invalid. + * + * Status from: f_thread_mutex_lock_timed(). + * + * Errors (with error bit) from: f_thread_mutex_lock_timed(). + * + * @see f_thread_mutex_lock_timed() + */ +#ifndef _di_controller_mutex_lock_ + extern f_status_t controller_mutex_lock(const uint8_t is_normal, const uint8_t check, const time_t seconds, const long nanoseconds, controller_thread_t * const thread, f_thread_mutex_full_t * const full); +#endif // _di_controller_mutex_lock_ + +/** + * Wait to get a mutex lock, using standard seconds and nanoseconds. + * + * Given a mutex lock, periodically check to see if main thread is disabled while waiting. + * + * @param is_normal + * IF controller_lock_check_flag_error_d, then this is is also TRUE, but it does not call controller_thread_enable_is_normal() and returns on any lock error. + * If controller_lock_check_flag_no_d, then do not check if the state is enabled and keep looping. + * If controller_lock_check_flag_yes_d, then check if the state is enabled and if it is not then abort. + * @param check + * If TRUE, then check if the state is enabled and if it is not then abort. + * If FALSE, then do not check if the state is enabled and keep looping. + * @param thread + * The thread data used to determine if the main thread is disabled or not. + * + * Must not be NULL. + * @param full + * The full mutex to lock. + * + * Must not be NULL. + * + * @return + * Status from: controller_mutex_lock(). + * + * Errors (with error bit) from: controller_mutex_lock(). + * + * @see controller_mutex_lock() + */ +#ifndef _di_controller_mutex_lock_standard_ + extern f_status_t controller_mutex_lock_standard(const uint8_t is_normal, const uint8_t check, controller_thread_t * const thread, f_thread_mutex_full_t * const full); +#endif // _di_controller_mutex_lock_standard_ + +/** + * Wait to get a mutex lock for some instance. + * + * Given a mutex lock, periodically check to see if main thread is disabled while waiting. + * + * @param instance + * The instance to use when checking if thread is enabled. + * + * Must not be NULL. + * @param full + * The full mutex to lock. + * + * Must not be NULL. + * + * @return + * Status from: controller_mutex_lock(). + * + * F_parameter (with error bit) if a parameter is invalid. + * + * Errors (with error bit) from: controller_mutex_lock(). + * + * @see controller_mutex_lock() + */ +#ifndef _di_controller_mutex_lock_instance_ + extern f_status_t controller_mutex_lock_instance(controller_instance_t * const instance, f_thread_mutex_full_t * const full); +#endif // _di_controller_mutex_lock_instance_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_mutex_h diff --git a/sources/c/program/controller/main/print/error/entry.c b/sources/c/program/controller/main/print/error/entry.c index a4470c5..6906edc 100644 --- a/sources/c/program/controller/main/print/error/entry.c +++ b/sources/c/program/controller/main/print/error/entry.c @@ -13,7 +13,6 @@ extern "C" { controller_t * const main = (controller_t *) print->custom; - // fll_error_print() automatically locks, so manually handle only the mutex locking and flushing rather than calling controller_lock_print(). f_thread_mutex_lock(&main->thread.lock.print.mutex); fll_error_print(print, status, function, fallback); diff --git a/sources/c/program/controller/main/print/error/rule.c b/sources/c/program/controller/main/print/error/rule.c index f0a44ea..990745c 100644 --- a/sources/c/program/controller/main/print/error/rule.c +++ b/sources/c/program/controller/main/print/error/rule.c @@ -13,7 +13,6 @@ extern "C" { controller_t * const main = (controller_t *) print->custom; - // fll_error_print() automatically locks, so manually handle only the mutex locking and flushing rather than calling controller_lock_print(). f_thread_mutex_lock(&main->thread.lock.print.mutex); fll_error_print(print, status, function, fallback); diff --git a/sources/c/program/controller/main/print/message.h b/sources/c/program/controller/main/print/message.h index 75c2961..6b3c5ae 100644 --- a/sources/c/program/controller/main/print/message.h +++ b/sources/c/program/controller/main/print/message.h @@ -19,6 +19,8 @@ extern "C" { /** * Print help. * + * This does not lock the print mutex because it is intended to be called before threads are enabled. + * * @param print * The output structure to print to. * diff --git a/sources/c/program/controller/main/process.c b/sources/c/program/controller/main/process.c index f310135..35b646d 100644 --- a/sources/c/program/controller/main/process.c +++ b/sources/c/program/controller/main/process.c @@ -126,7 +126,7 @@ extern "C" { return F_child; } - 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 (F_status_is_error_not(status) && status != F_failure && !(main->setting.flag & controller_main_flag_validate_d) && controller_thread_enable_is_normal(&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 69b3b21..2eb5ebe 100644 --- a/sources/c/program/controller/main/rule/execute.c +++ b/sources/c/program/controller/main/rule/execute.c @@ -440,8 +440,8 @@ extern "C" { 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_standard(instance->type != controller_instance_type_exit_e, controller_lock_check_flag_no_d, &main->thread, &instance->lock); - //if (status != F_okay) return F_status_set_error(F_lock_read); + status = controller_lock_write_standard(instance->type != controller_instance_type_exit_e, controller_lock_check_flag_no_d, &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); @@ -606,8 +606,8 @@ extern "C" { 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_standard(instance->type != controller_instance_type_exit_e, controller_lock_check_flag_no_d, &main->thread, &instance->lock); - //if (status != F_okay) return F_status_set_error(F_lock_read); + status = controller_lock_write_standard(instance->type != controller_instance_type_exit_e, controller_lock_check_flag_no_d, &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); diff --git a/sources/c/program/controller/main/rule/instance.c b/sources/c/program/controller/main/rule/instance.c index 945b632..d015229 100644 --- a/sources/c/program/controller/main/rule/instance.c +++ b/sources/c/program/controller/main/rule/instance.c @@ -29,14 +29,13 @@ extern "C" { return F_status_set_error(F_parameter); } - f_status_t status = F_okay; f_status_t status_lock = F_okay; instance->cache.action.name_action.used = 0; instance->cache.action.name_item.used = 0; instance->cache.action.name_file.used = 0; - status = f_string_dynamic_append(controller_rules_s, &instance->cache.action.name_file); + f_status_t status = f_string_dynamic_append(controller_rules_s, &instance->cache.action.name_file); if (F_status_is_error_not(status)) { status = f_string_dynamic_append(f_path_separator_s, &instance->cache.action.name_file); @@ -533,6 +532,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); + f_thread_condition_signal_all(&instance->wait_condition); } @@ -673,66 +673,70 @@ extern "C" { #endif // _di_controller_rule_instance_begin_ #ifndef _di_controller_rule_instance_perform_ - /** - * Inline helper function to conditionally unlock instance.active. - * - * @param instance - * The instance data. - * - * Must not be NULL. - * @param options_force - * Force the given instance options, only supporting a subset of instance options. - * - * If controller_instance_option_asynchronous_e, then asynchronously execute. - * If not controller_instance_option_asynchronous_e, then synchronously execute. - */ - static inline void private_controller_rule_instance_perform_unlock_active(controller_instance_t * const instance, const uint8_t options_force) { - - if (options_force & controller_instance_option_asynchronous_e) { - f_thread_unlock(&instance->active); - } - } - f_status_t controller_rule_instance_perform(controller_instance_t * const instance, const uint8_t options_force) { if (!instance || !instance->main) return F_status_set_error(F_parameter); - f_status_t status_lock = F_okay; + { + f_status_t status_lock = F_okay; + + if (options_force & controller_instance_option_asynchronous_e) { + status_lock = controller_lock_read_instance(instance, &instance->active); - // 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) { // @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)) { + controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true); + + return status_lock; + } + } + + status_lock = controller_lock_read_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true); + if (options_force & controller_instance_option_asynchronous_e) { + f_thread_unlock(&instance->active); + } + return status_lock; } } - status_lock = controller_lock_read_instance(instance, &instance->lock); + uint8_t flag = 0x2; - if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true); + const f_status_t status = controller_rule_instance_perform_details(instance, options_force, &flag); - private_controller_rule_instance_perform_unlock_active(instance, options_force); + if (flag & 0x2) { + f_thread_unlock(&instance->lock); + } - return status_lock; + if (options_force & controller_instance_option_asynchronous_e) { + f_thread_unlock(&instance->active); + } + + if (flag & 0x1) { + controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), !(flag & 0x4)); } + return status; + } +#endif // _di_controller_rule_instance_perform_ + +#ifndef _di_controller_rule_instance_perform_details_ + f_status_t controller_rule_instance_perform_details(controller_instance_t * const instance, const uint8_t options_force, uint8_t * const flag) { + + if (!instance || !instance->main) return F_status_set_error(F_parameter); + f_status_t status = F_okay; f_number_unsigned_t id_rule = 0; const f_number_unsigned_t used_original_stack = instance->stack.used; - status_lock = controller_lock_read_instance(instance, &instance->main->thread.lock.rule); + f_status_t status_lock = controller_lock_read_instance(instance, &instance->main->thread.lock.rule); // @fixme Wrong lock function? if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true); - - f_thread_unlock(&instance->lock); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); + *flag |= 0x1; return status_lock; } @@ -740,37 +744,37 @@ extern "C" { if (controller_rule_find(instance->rule.alias, instance->main->process.rules, &id_rule) == F_true) { f_thread_unlock(&instance->lock); + *flag &= ~0x2; + status_lock = controller_lock_write_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_false); - - f_thread_unlock(&instance->main->thread.lock.rule); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); + *flag |= 0x5; return status_lock; } + *flag |= 0x2; + controller_rule_delete(&instance->rule); status = controller_rule_copy(instance->main->process.rules.array[id_rule], &instance->rule); f_thread_unlock(&instance->lock); - status_lock = controller_lock_read_instance(instance, &instance->lock); + *flag &= ~0x2; - if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true); + status_lock = controller_lock_read_instance(instance, &instance->lock); - f_thread_unlock(&instance->main->thread.lock.rule); + f_thread_unlock(&instance->main->thread.lock.rule); - private_controller_rule_instance_perform_unlock_active(instance, options_force); + if (F_status_is_error(status_lock)) { + *flag |= 0x1; return status_lock; } - f_thread_unlock(&instance->main->thread.lock.rule); + *flag |= 0x2; if (F_status_is_error(status)) { controller_print_error_status(&instance->main->program.error, macro_controller_f(controller_rule_copy), F_status_set_fine(status)); @@ -778,10 +782,6 @@ extern "C" { else if (!instance->action) { // This is a "consider" Action, so do not actually execute the Rule. - f_thread_unlock(&instance->lock); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); - return F_process_not; } else { @@ -798,13 +798,7 @@ extern "C" { } } // for - if (!controller_thread_is_enabled_instance(instance)) { - f_thread_unlock(&instance->lock); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); - - return F_status_set_error(F_interrupt); - } + if (!controller_thread_is_enabled_instance(instance)) return F_status_set_error(F_interrupt); if (F_status_is_error_not(status)) { status = f_memory_array_increase(controller_allocation_small_d, sizeof(f_number_unsigned_t), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size); @@ -815,12 +809,12 @@ extern "C" { else { f_thread_unlock(&instance->lock); + *flag &= ~0x2; + status_lock = controller_lock_write_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_false); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); + *flag |= 0x5; return status_lock; } @@ -832,12 +826,12 @@ extern "C" { status_lock = controller_lock_read_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); + *flag |= 0x1; return status_lock; } + + *flag |= 0x2; } } } @@ -854,25 +848,17 @@ extern "C" { controller_print_error_rule_item_rule_not_loaded(&instance->main->program.error, &instance->cache.action, instance->rule.alias); } - if (status == F_child) { - f_thread_unlock(&instance->lock); - - private_controller_rule_instance_perform_unlock_active(instance, options_force); - - return status; - } + if (status == F_child) return status; status_lock = controller_lock_write_instance(instance, &instance->main->thread.lock.rule); if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_false); + *flag |= 0x5; - if (F_status_set_fine(status) != F_lock) { - f_thread_unlock(&instance->lock); + if (F_status_set_fine(status) == F_lock) { + *flag &= ~0x2; } - private_controller_rule_instance_perform_unlock_active(instance, options_force); - return status_lock; } @@ -884,21 +870,18 @@ extern "C" { f_thread_unlock(&instance->main->thread.lock.rule); - if (F_status_set_fine(status) != F_lock) { - f_thread_unlock(&instance->lock); + if (F_status_set_fine(status) == F_lock) { + *flag &= ~0x2; } if (F_status_set_fine(status) == F_interrupt || F_status_set_fine(status) == F_lock && !controller_thread_is_enabled_instance(instance)) { - private_controller_rule_instance_perform_unlock_active(instance, options_force); - return F_status_set_error(F_interrupt); } status_lock = controller_lock_write_instance(instance, &instance->lock); if (F_status_is_error(status_lock)) { - controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_false); - private_controller_rule_instance_perform_unlock_active(instance, options_force); + *flag |= 0x5; return status_lock; } @@ -907,12 +890,10 @@ extern "C" { instance->stack.used = used_original_stack; f_thread_condition_signal_all(&instance->wait_condition); - f_thread_unlock(&instance->lock); - private_controller_rule_instance_perform_unlock_active(instance, options_force); return controller_thread_is_enabled_instance(instance) ? status : F_status_set_error(F_interrupt); } -#endif // _di_controller_rule_instance_perform_ +#endif // _di_controller_rule_instance_perform_details_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/program/controller/main/rule/instance.h b/sources/c/program/controller/main/rule/instance.h index 6b1b371..ed8d43d 100644 --- a/sources/c/program/controller/main/rule/instance.h +++ b/sources/c/program/controller/main/rule/instance.h @@ -105,7 +105,36 @@ extern "C" { #endif // _di_controller_rule_instance_begin_ /** - * Perform the work + * A wrapper to controller_rule_instance_perform_details() that handles the active and instance locks. + * + * Enable active lock before calling controller_rule_instance_perform_details(). + * Disable active lock after calling controller_rule_instance_perform_details(). + * + * The instance and active locks shall be held for the duration of this instance processing (aside from switching between read to/from write). + * + * @param instance + * The instance data. + * + * Must not be NULL. + * @param options_force + * Force the given instance options, only supporting a subset of instance options. + * + * If controller_instance_option_asynchronous_e, then asynchronously execute. + * If not controller_instance_option_asynchronous_e, then synchronously execute. + * + * @return + * Status from: controller_rule_instance_perform_details(). + * + * F_parameter (with error bit) on invalid parameter. + * + * @see controller_rule_instance_perform_details() + */ +#ifndef _di_controller_rule_instance_perform_ + extern f_status_t controller_rule_instance_perform(controller_instance_t * const instance, const uint8_t options_force); +#endif // _di_controller_rule_instance_perform_ + +/** + * Perform the work. * * This does all the preparation work that needs to be synchronously performed within the same thread. * This will copy the Rule by the alias to the instance structure. @@ -119,6 +148,13 @@ extern "C" { * * If controller_instance_option_asynchronous_e, then asynchronously execute. * If not controller_instance_option_asynchronous_e, then synchronously execute. + * @param flag + * Designate lock states: + * - 0x1: Locking error. + * - 0x2: The instance lock is set. + * - 0x4: Locking error is a write lock. + * + * Must not be NULL. * * @return * F_okay on success. @@ -137,9 +173,9 @@ extern "C" { * @see controller_rule_instance() * @see controller_rule_instance_begin() */ -#ifndef _di_controller_rule_instance_perform_ - extern f_status_t controller_rule_instance_perform(controller_instance_t * const instance, const uint8_t options_force); -#endif // _di_controller_rule_instance_perform_ +#ifndef _di_controller_rule_instance_perform_details_ + extern f_status_t controller_rule_instance_perform_details(controller_instance_t * const instance, const uint8_t options_force, uint8_t * const flag); +#endif // _di_controller_rule_instance_perform_details_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/program/controller/main/rule/wait.c b/sources/c/program/controller/main/rule/wait.c index 4cb2d68..b1c6bd5 100644 --- a/sources/c/program/controller/main/rule/wait.c +++ b/sources/c/program/controller/main/rule/wait.c @@ -42,7 +42,7 @@ extern "C" { for (i = 0; i < instance_total; ++i) { - if (!controller_thread_enable_is(&main->thread, is_normal)) break; + if (!controller_thread_enable_is_normal(&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_standard(is_normal, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.instance); @@ -195,7 +195,7 @@ extern "C" { return status_lock; } - if (!controller_thread_enable_is(&main->thread, is_normal)) return F_status_set_error(F_interrupt); + if (!controller_thread_enable_is_normal(&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 9838dff..1e1bbc4 100644 --- a/sources/c/program/controller/main/thread/cleanup.c +++ b/sources/c/program/controller/main/thread/cleanup.c @@ -22,9 +22,6 @@ extern "C" { while (controller_thread_enable_get(&main->thread) == controller_thread_enable_e) { - // Allow thread to be interrupted and auto-cancelled while sleeping. - f_thread_cancel_state_set(PTHREAD_CANCEL_ASYNCHRONOUS, 0); - controller_time_now( main->setting.flag & controller_main_flag_simulate_d ? controller_thread_cleanup_interval_short_d @@ -33,19 +30,10 @@ extern "C" { &delay ); - // Use mutex lock and conditional wait, but if that fails fall back to a regular timed wait. - if (f_thread_mutex_lock(&main->thread.lock.reap.mutex) == F_okay) { - status = f_thread_condition_wait_timed(&delay, &main->thread.lock.reap_condition, &main->thread.lock.reap.mutex); - - if (F_status_is_error_not(status)) { - f_thread_mutex_unlock(&main->thread.lock.reap.mutex); - } - } - else { - status = F_okay; + // Allow thread to be interrupted and auto-cancelled while sleeping. + f_thread_cancel_state_set(PTHREAD_CANCEL_ASYNCHRONOUS, 0); - f_time_sleep_spec(delay, 0); - } + status = controller_mutex_condition_or_sleep(&main->thread.lock.reap, &main->thread.lock.reap_condition, &delay); // Prevent thread from being interrupted and auto-cancelled. f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); @@ -188,6 +176,7 @@ extern "C" { if (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.mutex); break; } diff --git a/sources/c/program/controller/main/thread/enable.c b/sources/c/program/controller/main/thread/enable.c index 84ae16b..f4dc8d6 100644 --- a/sources/c/program/controller/main/thread/enable.c +++ b/sources/c/program/controller/main/thread/enable.c @@ -27,8 +27,8 @@ extern "C" { } #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) { +#ifndef _di_controller_thread_enable_is_normal_ + f_status_t controller_thread_enable_is_normal(controller_thread_t * const thread, const uint8_t is_normal) { if (!thread) return F_false; @@ -36,10 +36,10 @@ extern "C" { return is_normal ? enable == controller_thread_enable_e : enable; } -#endif // _di_controller_thread_enable_is_ +#endif // _di_controller_thread_enable_is_normal_ #ifndef _di_controller_thread_enable_set_ - f_status_t controller_thread_enable_set(controller_thread_t * const thread, const uint8_t value) { + f_status_t controller_thread_enable_set(controller_thread_t * const thread, const uint8_t value, uint8_t * const original) { if (!thread) return F_status_set_error(F_parameter); @@ -53,6 +53,10 @@ extern "C" { } // for } + if (original) { + *original = thread->enable; + } + thread->enable = value; f_thread_unlock(&thread->lock.enable); diff --git a/sources/c/program/controller/main/thread/enable.h b/sources/c/program/controller/main/thread/enable.h index 9baa00b..72b1833 100644 --- a/sources/c/program/controller/main/thread/enable.h +++ b/sources/c/program/controller/main/thread/enable.h @@ -64,9 +64,9 @@ extern "C" { * * @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_ +#ifndef _di_controller_thread_enable_is_normal_ + extern f_status_t controller_thread_enable_is_normal(controller_thread_t * const thread, const uint8_t is_normal); +#endif // _di_controller_thread_enable_is_normal_ /** * Set the enable state of the system in a thread-safe manner. @@ -85,6 +85,11 @@ extern "C" { * Must not be NULL. * @param value * The new value to assign to the thread enable. + * @param original + * (optional) If specified, then the original value will be saved. + * This avoids needing to make a separate read to get the original value. + * + * This only gets updated on successful assignment of the new value. * * @return * F_okay on success. @@ -96,7 +101,7 @@ extern "C" { * @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); + extern f_status_t controller_thread_enable_set(controller_thread_t * const thread, const uint8_t value, uint8_t * const original); #endif // _di_controller_thread_enable_set_ #ifdef __cplusplus diff --git a/sources/c/program/controller/main/thread/entry.c b/sources/c/program/controller/main/thread/entry.c index 11b7c56..3a459cd 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_enable_is(&main->thread, F_true)) return 0; + if (!controller_thread_enable_is_normal(&main->thread, F_true)) return 0; f_status_t * const status = &main->thread.status; @@ -49,9 +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 = controller_thread_enable_get(&main->thread); + uint8_t original_enabled = 0; - controller_thread_enable_set(&main->thread, controller_thread_enable_e); + controller_thread_enable_set(&main->thread, controller_thread_enable_e, &original_enabled); // Restart the signal main->thread to allow for signals while operating the failsafe Items. if (!main->thread.id_signal) { @@ -66,7 +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 { - controller_thread_enable_set(&main->thread, original_enabled); + controller_thread_enable_set(&main->thread, original_enabled, 0); *status = F_failure; } @@ -143,12 +143,11 @@ 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 = controller_thread_enable_get(&main->thread); + uint8_t original_enabled = 0; // Restore operating mode so that the failsafe can execute. if (F_status_set_fine(*status) == F_execute) { - controller_thread_enable_set(&main->thread, controller_thread_enable_exit_e); + controller_thread_enable_set(&main->thread, controller_thread_enable_exit_e, &original_enabled); // Restart the signal thread to allow for signals while operating the failsafe Items. if (!main->thread.id_signal) { @@ -164,7 +163,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 { - controller_thread_enable_set(&main->thread, original_enabled); + controller_thread_enable_set(&main->thread, original_enabled, 0); *status = F_failure; } @@ -185,7 +184,7 @@ extern "C" { controller_delete(main); } else { - controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); + controller_thread_enable_set(&main->thread, controller_thread_enable_not_e, 0); f_thread_condition_signal_all(&main->thread.lock.alert_condition); } diff --git a/sources/c/program/controller/main/thread/instance.c b/sources/c/program/controller/main/thread/instance.c index 959a671..94129d1 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_enable_is(&instance->main->thread, is_normal)) return; + if (!controller_thread_enable_is_normal(&instance->main->thread, is_normal)) return; const f_status_t status = controller_rule_instance_perform(instance, controller_instance_option_asynchronous_e); @@ -28,11 +28,11 @@ extern "C" { if (!main) return; - f_status_t status = controller_lock_mutex(is_normal, controller_lock_check_flag_error_d, controller_thread_timeout_cancel_seconds_d, controller_thread_timeout_cancel_nanoseconds_d, &main->thread, &main->thread.lock.cancel); + f_status_t status = controller_mutex_lock(is_normal, controller_lock_check_flag_error_d, controller_thread_timeout_cancel_seconds_d, controller_thread_timeout_cancel_nanoseconds_d, &main->thread, &main->thread.lock.cancel); if (F_status_is_error(status)) return; // Only cancel when enabled. - if (!controller_thread_enable_is(&main->thread, is_normal)) { + if (!controller_thread_enable_is_normal(&main->thread, is_normal)) { f_thread_mutex_unlock(&main->thread.lock.cancel.mutex); return; @@ -85,7 +85,7 @@ extern "C" { enable = controller_thread_enable_exit_execute_e; } - controller_thread_enable_set(&main->thread, enable); + controller_thread_enable_set(&main->thread, enable, 0); } if (main->thread.id_cleanup) { @@ -386,7 +386,7 @@ extern "C" { controller_print_error_status(&main->program.error, macro_controller_f(f_thread_create), F_status_set_fine(status)); } - controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); + controller_thread_enable_set(&main->thread, controller_thread_enable_not_e, 0); } else { f_time_spec_t time = f_time_spec_t_initialize; @@ -403,7 +403,7 @@ extern "C" { } 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_enable_set(&main->thread, controller_thread_enable_not_e); + if (F_status_is_error(status)) controller_thread_enable_set(&main->thread, controller_thread_enable_not_e, 0); } // The sigtimedwait() function that is run inside of signal must be interrupted directly via f_thread_signal_write(). @@ -417,7 +417,7 @@ extern "C" { controller_thread_instance_cancel(main, F_false, controller_thread_cancel_exit_e); } else { - controller_thread_enable_set(&main->thread, controller_thread_enable_not_e); + controller_thread_enable_set(&main->thread, controller_thread_enable_not_e, 0); } } #endif // _di_controller_thread_instance_exit_ diff --git a/sources/c/program/controller/main/thread/is.c b/sources/c/program/controller/main/thread/is.c index 90f57f0..1a68943 100644 --- a/sources/c/program/controller/main/thread/is.c +++ b/sources/c/program/controller/main/thread/is.c @@ -16,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_enable_is(thread, type != controller_instance_type_exit_e); + return controller_thread_enable_is_normal(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 3675eb5..cd3789d 100644 --- a/sources/c/program/controller/main/thread/is.h +++ b/sources/c/program/controller/main/thread/is.h @@ -45,9 +45,9 @@ extern "C" { * The instance type to use when checking if thread is enabled. * * @return - * Success from controller_thread_enable_is(). + * Success from controller_thread_enable_is_normal(). * - * @see controller_thread_enable_is() + * @see controller_thread_enable_is_normal() */ #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 3f421b1..e5daa4d 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_enable_is(&main->thread, F_true)) return 0; + if (!controller_thread_enable_is_normal(&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 1008861..631fab5 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_enable_is(&main->thread, is_normal)) return; + if (!controller_thread_enable_is_normal(&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_enable_is(&main->thread, is_normal)) { + while (controller_thread_enable_is_normal(&main->thread, is_normal)) { memset((void *) &information, 0, sizeof(siginfo_t)); @@ -126,7 +126,7 @@ extern "C" { if (!interrupt->main) return; - if (!controller_thread_enable_is(&interrupt->main->thread, interrupt->is_normal)) { + if (!controller_thread_enable_is_normal(&interrupt->main->thread, interrupt->is_normal)) { controller_thread_signal_received_set(interrupt->main, F_signal_abort); } else { @@ -148,7 +148,7 @@ extern "C" { if (!interrupt->main) return; - if (!controller_thread_enable_is(&interrupt->main->thread, interrupt->is_normal)) { + if (!controller_thread_enable_is_normal(&interrupt->main->thread, interrupt->is_normal)) { controller_thread_signal_received_set(interrupt->main, F_signal_abort); } else {