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.
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
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
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
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
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));
}
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)) {
*
* 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".
*
* 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.
*/
#include <program/controller/main/entry/process.h>
#include <program/controller/main/entry/setting.h>
#include <program/controller/main/lock.h>
+#include <program/controller/main/mutex.h>
#include <program/controller/main/path.h>
#include <program/controller/main/perform.h>
#include <program/controller/main/print/debug.h>
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);
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;
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);
* 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);
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;
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) {
}
} // 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) {
* 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_
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;
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]];
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) {
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;
}
} // 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;
*
* 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_
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;
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;
}
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);
}
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);
}
}
}
#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) {
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) {
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) {
*
* 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.
* 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
* 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
* 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
* 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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
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);
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);
/**
* 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.
*
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);
}
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);
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);
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);
// 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);
}
#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;
}
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));
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 {
}
} // 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);
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;
}
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;
}
}
}
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;
}
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;
}
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"
#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.
*
* 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.
* @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"
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);
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;
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
&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);
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;
}
}
#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;
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);
} // for
}
+ if (original) {
+ *original = thread->enable;
+ }
+
thread->enable = value;
f_thread_unlock(&thread->lock.enable);
*
* @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.
* 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.
* @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
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;
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) {
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;
}
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) {
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;
}
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);
}
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);
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;
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) {
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;
} 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().
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_
#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_
* 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);
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;
}
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));
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 {
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 {