From 0dfd08630d49b281d636bd1deac2b548eb6ec056 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Tue, 28 May 2024 21:24:35 -0500 Subject: [PATCH] Progress: Continue migrating the project. --- data/build/settings | 6 +- sources/c/main/common/define/thread.h | 18 +-- sources/c/main/common/type/entry.h | 2 +- sources/c/main/controller.h | 11 ++ sources/c/main/rule/action.c | 6 +- sources/c/main/rule/instance.c | 4 +- sources/c/main/rule/item.c | 3 +- sources/c/main/rule/read.c | 2 +- sources/c/main/rule/setting.c | 4 +- sources/c/main/rule/wait.c | 4 +- sources/c/main/thread.c | 48 +++--- sources/c/main/thread.h | 22 ++- sources/c/main/thread/control.c | 35 +++++ sources/c/main/thread/control.h | 38 +++++ sources/c/main/thread/entry.c | 272 ++++++++++++++++++++++++++++++++++ sources/c/main/thread/entry.h | 62 ++++++++ sources/c/main/thread/instance.c | 51 ++++--- sources/c/main/thread/instance.h | 51 ++++--- sources/c/main/thread/rule.c | 24 +++ sources/c/main/thread/rule.h | 43 ++++++ 20 files changed, 599 insertions(+), 107 deletions(-) create mode 100644 sources/c/main/thread/control.c create mode 100644 sources/c/main/thread/control.h create mode 100644 sources/c/main/thread/entry.c create mode 100644 sources/c/main/thread/entry.h create mode 100644 sources/c/main/thread/rule.c create mode 100644 sources/c/main/thread/rule.h diff --git a/data/build/settings b/data/build/settings index be6b199..65517fe 100644 --- a/data/build/settings +++ b/data/build/settings @@ -46,7 +46,8 @@ build_sources_library main/common/string/general.c main/common/string/rule.c build_sources_library main/instance.c main/path.c build_sources_library main/rule.c main/rule/action.c main/rule/execute.c main/rule/expand.c main/rule/instance.c main/rule/is.c main/rule/item.c main/rule/parameter.c main/rule/read.c main/rule/setting.c main/rule/validate.c main/rule/wait.c build_sources_library main/print/data.c main/print/debug.c main/print/error.c main/print/lock.c main/print/message.c main/print/rule.c main/print/verbose.c main/print/warning.c -build_sources_library main/signal.c main/time.c main/thread.c main/thread/instance.c main/thread/is.c +build_sources_library main/signal.c main/time.c +build_sources_library main/thread.c main/thread/control.c main/thread/entry.c main/thread/instance.c main/thread/is.c main/thread/rule.c build_sources_headers main/common.h main/controller.h main/common/define.h main/common/enumeration.h main/common/print.h main/common/string.h main/common/thread.h main/common/type.h build_sources_headers main/common/define/control.h main/common/define/entry.h main/common/define/rule.h main/common/define/thread.h @@ -56,7 +57,8 @@ build_sources_headers main/common/type/cache.h main/common/type/control.h main/c build_sources_headers main/instance.h main/path.h build_sources_headers main/rule.h main/rule/action.h main/rule/execute.h main/rule/expand.h main/rule/instance.h main/rule/is.h main/rule/item.h main/rule/parameter.h main/rule/read.h main/rule/setting.h main/rule/validate.h main/rule/wait.h build_sources_headers main/print/data.h main/print/debug.h main/print/error.h main/print/lock.h main/print/message.h main/print/rule.h main/print/verbose.h main/print/warning.h -build_sources_headers main/signal.h main/time.h main/thread.h main/thread/instance.h main/thread/is.h +build_sources_headers main/signal.h main/time.h +build_sources_headers main/thread.h main/thread/control.h main/thread/entry.h main/thread/instance.h main/thread/is.h main/thread/rule.h build_sources_documentation man diff --git a/sources/c/main/common/define/thread.h b/sources/c/main/common/define/thread.h index 0a72c81..40474db 100644 --- a/sources/c/main/common/define/thread.h +++ b/sources/c/main/common/define/thread.h @@ -22,13 +22,13 @@ extern "C" { #ifndef _di_controller_thread_d_ #define controller_thread_cleanup_interval_long_d 3600 // 1 hour in seconds. #define controller_thread_cleanup_interval_short_d 180 // 3 minutes in seconds. - #define controller_thread_exit_timeout_d 500 // 0.5 seconds in milliseconds. - #define controller_thread_exit_process_cancel_wait_d 600000000 // 0.6 seconds in nanoseconds. - #define controller_thread_exit_process_cancel_total_d 150 // 90 seconds in multiples of wait. + #define controller_main_thread_exit_timeout_d 500 // 0.5 seconds in milliseconds. + #define controller_main_thread_exit_process_cancel_wait_d 600000000 // 0.6 seconds in nanoseconds. + #define controller_main_thread_exit_process_cancel_total_d 150 // 90 seconds in multiples of wait. #define controller_thread_simulation_timeout_d 200 // 0.2 seconds in milliseconds. - #define controller_thread_signal_wait_timeout_seconds_d 70 - #define controller_thread_signal_wait_timeout_nanoseconds_d 0 + #define controller_main_thread_signal_wait_timeout_seconds_d 70 + #define controller_main_thread_signal_wait_timeout_nanoseconds_d 0 #define controller_thread_lock_read_timeout_seconds_d 3 #define controller_thread_lock_read_timeout_nanoseconds_d 0 @@ -48,11 +48,11 @@ extern "C" { #define controller_thread_wait_timeout_4_seconds_d 20 #define controller_thread_wait_timeout_4_nanoseconds_d 0 - #define controller_thread_exit_helper_timeout_seconds_d 0 - #define controller_thread_exit_helper_timeout_nanoseconds_d 100000000 // 0.1 seconds in nanoseconds. + #define controller_main_thread_exit_helper_timeout_seconds_d 0 + #define controller_main_thread_exit_helper_timeout_nanoseconds_d 100000000 // 0.1 seconds in nanoseconds. - #define controller_thread_exit_ready_timeout_seconds_d 0 - #define controller_thread_exit_ready_timeout_nanoseconds_d 500000000 // 0.5 seconds in nanoseconds. + #define controller_main_thread_exit_ready_timeout_seconds_d 0 + #define controller_main_thread_exit_ready_timeout_nanoseconds_d 500000000 // 0.5 seconds in nanoseconds. #endif // _di_controller_thread_d_ #ifdef __cplusplus diff --git a/sources/c/main/common/type/entry.h b/sources/c/main/common/type/entry.h index 46c2ab1..3219e70 100644 --- a/sources/c/main/common/type/entry.h +++ b/sources/c/main/common/type/entry.h @@ -169,7 +169,7 @@ extern "C" { 0, \ 0, \ 0, \ - controller_thread_exit_timeout_d, \ + controller_main_thread_exit_timeout_d, \ 0, \ 0, \ 0, \ diff --git a/sources/c/main/controller.h b/sources/c/main/controller.h index 443cc5c..45fe2ad 100644 --- a/sources/c/main/controller.h +++ b/sources/c/main/controller.h @@ -53,11 +53,19 @@ // FLL-1 includes. #include #include +#include +#include +#include #include #include // FLL-2 includes. #include +#include +#include +#include +#include +#include #include #include @@ -100,8 +108,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include diff --git a/sources/c/main/rule/action.c b/sources/c/main/rule/action.c index c1b9059..1e49195 100644 --- a/sources/c/main/rule/action.c +++ b/sources/c/main/rule/action.c @@ -39,7 +39,7 @@ extern "C" { f_status_t status = F_okay; controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_normal, global->thread); - f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0); + f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_main_thread_signal_state_fss, 0, (void *) &custom, 0); f_number_unsigned_t i = 0; @@ -118,7 +118,7 @@ extern "C" { if (actions->array[actions->used].parameters.array[0].used) { state.step_large = controller_common_allocation_iki_large_d; state.step_small = controller_common_allocation_iki_small_d; - state.interrupt = &controller_thread_signal_state_iki; + state.interrupt = &controller_main_thread_signal_state_iki; f_range_t range_iki = macro_f_range_t_initialize_2(actions->array[actions->used].parameters.array[0].used); @@ -359,7 +359,7 @@ extern "C" { if (actions->array[actions->used].parameters.array[0].used) { state.step_large = controller_common_allocation_iki_large_d; state.step_small = controller_common_allocation_iki_small_d; - state.interrupt = &controller_thread_signal_state_iki; + state.interrupt = &controller_main_thread_signal_state_iki; f_range_t range_iki = macro_f_range_t_initialize_2(actions->array[actions->used].parameters.array[0].used); diff --git a/sources/c/main/rule/instance.c b/sources/c/main/rule/instance.c index da398d0..06029a5 100644 --- a/sources/c/main/rule/instance.c +++ b/sources/c/main/rule/instance.c @@ -736,10 +736,10 @@ extern "C" { if (F_status_is_error_not(status)) { if (instance->action && (options_force & controller_instance_option_asynchronous_d)) { if (instance->type == controller_instance_type_exit_e) { - status = f_thread_create(0, &instance->id_thread, controller_thread_instance_other, (void *) instance); + status = f_thread_create(0, &instance->id_thread, controller_main_thread_instance_other, (void *) instance); } else { - status = f_thread_create(0, &instance->id_thread, controller_thread_instance_normal, (void *) instance); + status = f_thread_create(0, &instance->id_thread, controller_main_thread_instance_normal, (void *) instance); } if (F_status_is_error(status)) { diff --git a/sources/c/main/rule/item.c b/sources/c/main/rule/item.c index dbbbe18..7656c1a 100644 --- a/sources/c/main/rule/item.c +++ b/sources/c/main/rule/item.c @@ -11,7 +11,7 @@ extern "C" { f_status_t status = F_okay; controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_normal, global->thread); - f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0); + f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_main_thread_signal_state_fss, 0, (void *) &custom, 0); f_range_t range = macro_f_range_t_initialize_2(cache->buffer_item.used); f_number_unsigned_t last = 0; @@ -151,6 +151,7 @@ extern "C" { } status = F_status_set_error(F_support_not); + break; } diff --git a/sources/c/main/rule/read.c b/sources/c/main/rule/read.c index a233a8d..47e0f2f 100644 --- a/sources/c/main/rule/read.c +++ b/sources/c/main/rule/read.c @@ -179,7 +179,7 @@ extern "C" { if (cache->buffer_file.used) { controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_normal, global->thread); - f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0); + f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_main_thread_signal_state_fss, 0, (void *) &custom, 0); f_range_t range = macro_f_range_t_initialize_2(cache->buffer_file.used); fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments, &state); diff --git a/sources/c/main/rule/setting.c b/sources/c/main/rule/setting.c index a717c8d..25394e3 100644 --- a/sources/c/main/rule/setting.c +++ b/sources/c/main/rule/setting.c @@ -16,7 +16,7 @@ extern "C" { f_range_t range2 = f_range_t_initialize; controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_normal, global->thread); - f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0); + f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_main_thread_signal_state_fss, 0, (void *) &custom, 0); fll_fss_extended_read(cache->buffer_item, &range, &cache->object_actions, &cache->content_actions, 0, 0, &cache->delimits, 0, &state); @@ -441,6 +441,7 @@ extern "C" { if (F_status_is_error(status)) { controller_rule_print_error(global->thread, &global->main->program.error, cache->action, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true, F_false); + break; } @@ -1675,6 +1676,7 @@ extern "C" { if (F_status_set_fine(status) == F_memory_not) { status_return = status; + break; } diff --git a/sources/c/main/rule/wait.c b/sources/c/main/rule/wait.c index 2f8e675..36863a6 100644 --- a/sources/c/main/rule/wait.c +++ b/sources/c/main/rule/wait.c @@ -43,7 +43,7 @@ extern "C" { for (i = 0; i < instance_total; ++i) { - if (!controller_thread_is_enabled(is_normal, global->thread)) break; + if (!controller_main_thread_is_enabled(is_normal, global->thread)) break; // Re-establish global instance read lock to wait for or protect from the cleanup thread while checking the read instance. status_lock = controller_lock_read(is_normal, global->thread, &global->thread->lock.instance); @@ -199,7 +199,7 @@ extern "C" { return status_lock; } - if (!controller_thread_is_enabled(is_normal, global->thread)) return F_status_set_error(F_interrupt); + if (!controller_main_thread_is_enabled(is_normal, global->thread)) 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/main/thread.c b/sources/c/main/thread.c index 4a69cec..27c3339 100644 --- a/sources/c/main/thread.c +++ b/sources/c/main/thread.c @@ -17,7 +17,7 @@ extern "C" { while (controller_main_thread_is_enabled(is_normal, global->thread)) { - controller_time_now(controller_thread_exit_ready_timeout_seconds_d, controller_thread_exit_ready_timeout_nanoseconds_d, &time); + controller_time_now(controller_main_thread_exit_ready_timeout_seconds_d, controller_main_thread_exit_ready_timeout_nanoseconds_d, &time); memset((void *) &information, 0, sizeof(siginfo_t)); @@ -27,7 +27,7 @@ extern "C" { if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) { global->thread->signal = information.si_signo; - controller_thread_instance_cancel(global, is_normal, controller_thread_cancel_signal_e); + controller_main_thread_instance_cancel(global, is_normal, controller_thread_cancel_signal_e); break; } @@ -36,42 +36,38 @@ extern "C" { #endif // _di_controller_main_thread_signal_ #ifndef _di_controller_main_thread_signal_state_fss_ - f_status_t controller_main_thread_signal_state_fss(f_state_t * const state, void * const internal) { + void controller_main_thread_signal_state_fss(f_state_t * const state, void * const internal) { - if (!state || !state->custom || !internal) return F_interrupt_not; + if (!state || !state->custom) return; - controller_interrupt_t * const custom = (controller_interrupt_t *) state->custom; - controller_thread_t * const thread = custom->thread; + controller_global_t * const global = (controller_global_t *) state->custom; - if (!controller_main_thread_is_enabled(custom->is_normal, thread)) { - return F_status_set_error(F_interrupt); + if (!controller_thread_is_enabled(custom->is_normal, global->thread)) { + global->main->program.signal_received = F_signal_abort; + global->main->setting.state.status = F_status_set_error(F_interrupt); } - - if (thread->signal == F_signal_interrupt || thread->signal == F_signal_abort || thread->signal == F_signal_quit || thread->signal == F_signal_termination) { - return F_status_set_error(F_interrupt); + else if (global->thread->signal == F_signal_interrupt || global->thread->signal == F_signal_abort || global->thread->signal == F_signal_quit || global->thread->signal == F_signal_termination) { + global->main->program.signal_received = F_signal_abort; + global->main->setting.state.status = F_status_set_error(F_interrupt); } - - return F_interrupt_not; } #endif // _di_controller_main_thread_signal_state_fss_ #ifndef _di_controller_main_thread_signal_state_iki_ - f_status_t controller_main_thread_signal_state_iki(f_state_t * const state, void * const internal) { + void controller_main_thread_signal_state_iki(f_state_t * const state, void * const internal) { - if (!state || !state->custom || !internal) return F_interrupt_not; + if (!state || !state->custom) return; - controller_interrupt_t * const custom = (controller_interrupt_t *) state->custom; - controller_thread_t * const thread = custom->thread; + controller_global_t * const global = (controller_global_t *) state->custom; - if (!controller_main_thread_is_enabled(custom->is_normal, thread)) { - return F_status_set_error(F_interrupt); + if (!controller_thread_is_enabled(custom->is_normal, global->thread)) { + global->main->program.signal_received = F_signal_abort; + global->main->setting.state.status = F_status_set_error(F_interrupt); } - - if (thread->signal == F_signal_interrupt || thread->signal == F_signal_abort || thread->signal == F_signal_quit || thread->signal == F_signal_termination) { - return F_status_set_error(F_interrupt); + else if (global->thread->signal == F_signal_interrupt || global->thread->signal == F_signal_abort || global->thread->signal == F_signal_quit || global->thread->signal == F_signal_termination) { + global->main->program.signal_received = F_signal_abort; + global->main->setting.state.status = F_status_set_error(F_interrupt); } - - return F_interrupt_not; } #endif // _di_controller_main_thread_signal_state_iki_ @@ -80,7 +76,7 @@ extern "C" { f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); - controller_main_thread_signal((controller_global_t *) global, F_true); + controller_main_thread_signal((controller_global_t * const) global, F_true); return 0; } @@ -91,7 +87,7 @@ extern "C" { f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); - controller_main_thread_signal((controller_global_t *) global, F_false); + controller_main_thread_signal((controller_global_t * const) global, F_false); return 0; } diff --git a/sources/c/main/thread.h b/sources/c/main/thread.h index 5856483..b558856 100644 --- a/sources/c/main/thread.h +++ b/sources/c/main/thread.h @@ -32,16 +32,13 @@ * * @param state * The state data. + * + * Must not be NULL. * @param internal * Not used. - * - * @return - * F_interrupt_not if not interrupted. - * - * F_interrupt (with error bit) if interrupted. */ #ifndef _di_controller_main_thread_signal_state_fss_ - extern f_status_t controller_main_thread_signal_state_fss(f_state_t * const state, void * const internal); + extern void controller_main_thread_signal_state_fss(f_state_t * const state, void * const internal); #endif // _di_controller_main_thread_signal_state_fss_ /** @@ -49,16 +46,13 @@ * * @param state * The state data. + * + * Must not be NULL. * @param internal * Not used. - * - * @return - * F_interrupt_not if not interrupted. - * - * F_interrupt (with error bit) if interrupted. */ #ifndef _di_controller_main_thread_signal_state_iki_ - extern f_status_t controller_main_thread_signal_state_iki(f_state_t * const state, void * const internal); + extern void controller_main_thread_signal_state_iki(f_state_t * const state, void * const internal); #endif // _di_controller_main_thread_signal_state_iki_ /** @@ -68,6 +62,8 @@ * The global structure. * Must be of type controller_global_t. * + * Must not be NULL. + * * @return * 0, always. * @@ -84,6 +80,8 @@ * The global structure. * Must be of type controller_global_t. * + * Must not be NULL. + * * @return * 0, always. * diff --git a/sources/c/main/thread/control.c b/sources/c/main/thread/control.c new file mode 100644 index 0000000..39627fc --- /dev/null +++ b/sources/c/main/thread/control.c @@ -0,0 +1,35 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_main_thread_control_ + void * controller_main_thread_control(void * const arguments) { + + if (!arguments) return 0; + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_global_t * const global = (controller_global_t * const) arguments; + + if (global->thread->enabled != controller_thread_enabled_e) return 0; + + f_status_t status = F_okay; + + if (status == F_child) { + + // A forked child process should de-allocate memory on exit. + // It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below. + controller_thread_delete_simple(global->thread); + controller_process_delete(global->setting); + controller_main_delete(global->main); + } + + return 0; + } +#endif // _di_controller_main_thread_control_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/thread/control.h b/sources/c/main/thread/control.h new file mode 100644 index 0000000..207d761 --- /dev/null +++ b/sources/c/main/thread/control.h @@ -0,0 +1,38 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the thread "control" functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_thread_control_h +#define _controller_main_thread_control_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Thread for handling control requests and responses. + * + * @param arguments + * The global data. + * Must be of type controller_global_t. + * Must not be NULL. + * + * @return + * 0, always. + */ +#ifndef _di_controller_main_thread_control_ + extern void * controller_main_thread_control(void * const arguments); +#endif // _di_controller_main_thread_control_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_thread_control_h diff --git a/sources/c/main/thread/entry.c b/sources/c/main/thread/entry.c new file mode 100644 index 0000000..c970530 --- /dev/null +++ b/sources/c/main/thread/entry.c @@ -0,0 +1,272 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_main_thread_entry_ + void * controller_main_thread_entry(void * const arguments) { + + if (!arguments) return 0; + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_instance_t * const instance = (controller_instance_t * const ) arguments; + + if (!controller_main_thread_is_enabled(F_true, instance->thread)) return 0; + + controller_main_t * const main = instance->main; + controller_cache_t * const cache = &instance->thread->cache; + f_status_t * const status = &instance->thread->status; + + *status = controller_entry_read(*instance->global, F_true, cache); + + if (F_status_set_fine(*status) == F_interrupt) { + instance->setting->ready = controller_setting_ready_abort_e; + } + else if (F_status_is_error(*status)) { + instance->setting->ready = controller_setting_ready_fail_e; + } + else if (*status != F_child) { + *status = controller_entry_preprocess(*instance->global, F_true, cache); + + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { + controller_entry_setting_validate(*instance->global, F_true, cache); + } + } + + if (F_status_is_error_not(*status) && *status != F_child) { + if (!(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) || (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { + + if (instance->setting->instance.pid == controller_entry_pid_require_e && f_file_exists(instance->setting->path_pid, F_true) == F_true) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, instance->thread); + + fl_print_format("%r%[%QThe pid file '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, instance->setting->path_pid, main->program.error.notable); + fl_print_format("%[' must not already exist.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_unlock_print_flush(main->program.error.to, instance->thread); + } + + instance->setting->ready = controller_setting_ready_fail_e; + *status = F_status_set_error(F_available_not); + } + else { + *status = controller_entry_process(instance->global, cache, F_false, F_true); + + if (F_status_is_error(*status)) { + instance->setting->ready = controller_setting_ready_fail_e; + + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (instance->setting->flag & controller_setting_flag_failsafe_e)) { + const uint8_t original_enabled = instance->thread->enabled; + + // Restore operating mode so that the failsafe can execute. + *status = f_thread_mutex_lock(&instance->thread->lock.alert); + + if (F_status_is_error_not(*status)) { + instance->thread->enabled = controller_thread_enabled_e; + + f_thread_mutex_unlock(&instance->thread->lock.alert); + } + + // Restart the signal thread to allow for signals while operating the failsafe Items. + if (!instance->thread->id_signal) { + f_thread_create(0, &instance->thread->id_signal, &controller_main_thread_signal_normal, (void *) instance->global); + } + + const f_status_t status_failsafe = controller_entry_process(instance->global, cache, F_true, F_true); + + if (F_status_is_error(status_failsafe)) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, instance->thread); + + fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, instance->setting->instance.items.array[instance->setting->failsafe_item_id].name, main->program.error.notable); + fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_unlock_print_flush(main->program.error.to, instance->thread); + } + + *status = F_status_set_error(F_failure); + } + else { + + // Restore operating mode to value prior to failsafe mode. + *status = f_thread_mutex_lock(&instance->thread->lock.alert); + + if (F_status_is_error_not(*status)) { + instance->thread->enabled = original_enabled; + + f_thread_mutex_unlock(&instance->thread->lock.alert); + } + + *status = F_failure; + } + } + } + else if (F_status_set_fine(*status) == F_interrupt) { + instance->setting->ready = controller_setting_ready_abort_e; + } + else if (*status != F_child) { + instance->setting->ready = controller_setting_ready_done_e; + } + } + + if (F_status_is_error_not(*status) && *status != F_child && main->program.parameters.array[controller_parameter_validate_e].result == f_console_result_none_e && instance->setting->mode == controller_setting_mode_helper_e) { + f_time_spec_t time; + time.tv_sec = controller_main_thread_exit_helper_timeout_seconds_d; + time.tv_nsec = controller_main_thread_exit_helper_timeout_nanoseconds_d; + + nanosleep(&time, 0); + + controller_main_thread_process_cancel(*(instance->global), F_true, controller_thread_cancel_exit_e); + } + } + } + + if (*status == F_child) { + + // A forked child process should deallocate memory on exit. + // It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below. + controller_thread_delete_simple(instance->thread); + controller_process_delete(instance->setting); + controller_main_delete(main); + + // According to the manpages, pthread_exit() calls exit(0), which the value of main->program.child should be returned instead. + if (main->program.child) exit(main->program.child); + + return 0; + } + + f_thread_condition_signal_all(&instance->thread->lock.alert_condition); + + return 0; + } +#endif // _di_controller_main_thread_entry_ + +#ifndef _di_controller_main_thread_exit_ + void * controller_main_thread_exit(void * const arguments) { + + if (!arguments) return 0; + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_main_entry_t *instance = (controller_main_entry_t *) arguments; + + controller_main_t * const main = instance->main; + controller_cache_t * const cache = &instance->thread->cache; + f_status_t * const status = &instance->thread->status; + + *status = controller_entry_read(*instance->global, F_false, cache); + + if (F_status_set_fine(*status) == F_interrupt) { + instance->setting->ready = controller_setting_ready_abort_e; + } + else if (F_status_is_error(*status)) { + instance->setting->ready = controller_setting_ready_fail_e; + } + else if (*status == F_file_found_not) { + instance->setting->ready = controller_setting_ready_done_e; + } + else if (*status != F_child) { + *status = controller_entry_preprocess(*instance->global, F_false, cache); + + if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { + controller_entry_setting_validate(*instance->global, F_false, cache); + } + } + + if (F_status_is_error_not(*status) && *status != F_child && *status != F_file_found_not) { + if (!(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) || (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { + + *status = controller_entry_process(instance->global, cache, F_false, F_false); + + if (F_status_is_error(*status)) { + instance->setting->ready = controller_setting_ready_fail_e; + + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (instance->setting->flag & controller_setting_flag_failsafe_e)) { + + const uint8_t original_enabled = instance->thread->enabled; + + // Restore operating mode so that the failsafe can execute. + if (F_status_set_fine(*status) == F_execute) { + *status = f_thread_mutex_lock(&instance->thread->lock.alert); + + if (F_status_is_error_not(*status)) { + instance->thread->enabled = controller_thread_enabled_exit_e; + + f_thread_mutex_unlock(&instance->thread->lock.alert); + } + + // Restart the signal thread to allow for signals while operating the failsafe Items. + if (!instance->thread->id_signal) { + f_thread_create(0, &instance->thread->id_signal, &controller_main_thread_signal_other, (void *) instance->global); + } + } + + const f_status_t status_failsafe = controller_entry_process(instance->global, cache, F_true, F_false); + + if (F_status_is_error(status_failsafe)) { + if (main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_lock_print(main->program.error.to, instance->thread); + + fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context); + fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, instance->setting->instance.items.array[instance->setting->failsafe_item_id].name, main->program.error.notable); + fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s); + + controller_unlock_print_flush(main->program.error.to, instance->thread); + } + + *status = F_status_set_error(F_failure); + } + else { + + // Restore operating mode to value prior to failsafe mode. + *status = f_thread_mutex_lock(&instance->thread->lock.alert); + + if (F_status_is_error_not(*status)) { + instance->thread->enabled = original_enabled; + + f_thread_mutex_unlock(&instance->thread->lock.alert); + } + + *status = F_failure; + } + } + } + else if (F_status_set_fine(*status) == F_interrupt) { + instance->setting->ready = controller_setting_ready_abort_e; + } + else if (*status != F_child) { + instance->setting->ready = controller_setting_ready_done_e; + } + } + } + + if (*status == F_child) { + + // A forked child process should deallocate memory on exit. + // It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below. + controller_thread_delete_simple(instance->thread); + controller_process_delete(instance->setting); + controller_main_delete(main); + + return 0; + } + + if (F_status_is_error_not(f_thread_mutex_lock(&instance->thread->lock.alert))) { + instance->thread->enabled = controller_thread_enabled_not_e; + + f_thread_mutex_unlock(&instance->thread->lock.alert); + } + + f_thread_condition_signal_all(&instance->thread->lock.alert_condition); + + return 0; + } +#endif // _di_controller_main_thread_exit_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/thread/entry.h b/sources/c/main/thread/entry.h new file mode 100644 index 0000000..6c35f29 --- /dev/null +++ b/sources/c/main/thread/entry.h @@ -0,0 +1,62 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the thread "entry" functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_thread_entry_h +#define _controller_main_thread_entry_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Thread for handling entry processing. + * + * This acts as the main rule thread during entry processing. + * This runs all synchronous rules or spawns asynchronous rules. + * + * @param arguments + * The global data. + * Must be of type controller_instance_t. + * Must not be NULL. + * + * @return + * 0, always. + */ +#ifndef _di_controller_main_thread_entry_ + extern void * controller_main_thread_entry(void * const arguments); +#endif // _di_controller_main_thread_entry_ + +/** + * Thread for handling exit file processing. + * + * This acts as the main rule thread during exit processing. + * This runs all synchronous rules or spawns asynchronous rules. + * + * Do not confuse this with exiting a thread, this is the what process the exit files (similar to that of an entry file). + * Exit files process the "stop" action, whereas the Entry files process the "start" Action + * + * @param arguments + * The global data. + * Must be of type controller_instance_t. + * Must not be NULL. + * + * @return + * 0, always. + */ +#ifndef _di_controller_main_thread_exit_ + extern void * controller_main_thread_exit(void * const arguments); +#endif // _di_controller_main_thread_exit_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_thread_entry_h diff --git a/sources/c/main/thread/instance.c b/sources/c/main/thread/instance.c index 5ae10d8..54370a6 100644 --- a/sources/c/main/thread/instance.c +++ b/sources/c/main/thread/instance.c @@ -4,17 +4,16 @@ extern "C" { #endif -#ifndef _di_controller_thread_instance_ - void controller_thread_instance(const uint8_t is_normal, controller_instance_t * const instance) { +#ifndef _di_controller_main_thread_instance_ + void controller_main_thread_instance(const uint8_t is_normal, controller_instance_t * const instance) { if (!instance) return; - if (!controller_main_thread_is_enabled(is_normal, (controller_thread_t *) instance->thread)) return; + if (!controller_main_thread_is_enabled(is_normal, (controller_thread_t * const) instance->thread)) return; const f_status_t status = controller_rule_process_do(controller_process_option_asynchronous_d, instance); // A forked child instance should deallocate memory on exit. // It seems that this function doesn't return to the calling thread for a forked child instance, even with the "return 0;" below. - // Deallocate as much as possible. if (status == F_child) { controller_thread_delete_simple(instance->main_thread); controller_process_delete(instance->program); @@ -24,10 +23,10 @@ extern "C" { if (instance->main_data->program.child) exit(instance->main_data->program.child); } } -#endif // _di_controller_thread_instance_ +#endif // _di_controller_main_thread_instance_ -#ifndef _di_controller_thread_instance_cancel_ - void controller_thread_instance_cancel(controller_global_t * const global, const uint8_t is_normal, const uint8_t by) { +#ifndef _di_controller_main_thread_instance_cancel_ + void controller_main_thread_instance_cancel(controller_instance_t * const global, const uint8_t is_normal, const uint8_t by) { if (!global) return; @@ -236,7 +235,7 @@ extern "C" { f_signal_send(F_signal_kill, instance->childs.array[j]); time.tv_sec = 0; - time.tv_nsec = controller_thread_exit_process_cancel_wait_d; + time.tv_nsec = controller_main_thread_exit_process_cancel_wait_d; instance->childs.array[j] = 0; } @@ -310,10 +309,10 @@ extern "C" { f_thread_mutex_unlock(&global->thread->lock.cancel); } -#endif // _di_controller_thread_instance_cancel_ +#endif // _di_controller_main_thread_instance_cancel_ -#ifndef _di_controller_thread_instance_exit_ - void controller_thread_instance_exit(controller_global_t * const global) { +#ifndef _di_controller_main_thread_instance_exit_ + void controller_main_thread_instance_exit(controller_global_t * const global) { if (!global) return; @@ -331,12 +330,12 @@ extern "C" { // Restart the signal thread to allow for signals while operating the Exit. if (!global->thread->id_signal) { - f_thread_create(0, &global->thread->id_signal, &controller_thread_signal_other, (void *) global); + f_thread_create(0, &global->thread->id_signal, &controller_main_thread_signal_other, (void *) global); } const controller_main_entry_t entry = macro_controller_main_entry_t_initialize_1(global, global->setting); - f_status_t status = f_thread_create(0, &global->thread->id_entry, &controller_thread_exit, (void *) &entry); + f_status_t status = f_thread_create(0, &global->thread->id_entry, &controller_main_thread_exit, (void *) &entry); if (F_status_is_error(status)) { if (global->main->program.error.verbosity > f_console_verbosity_quiet_e) { @@ -364,7 +363,7 @@ extern "C" { break; } - controller_time(controller_thread_exit_ready_timeout_seconds_d, controller_thread_exit_ready_timeout_nanoseconds_d, &time); + controller_time(controller_main_thread_exit_ready_timeout_seconds_d, controller_main_thread_exit_ready_timeout_nanoseconds_d, &time); status = f_thread_condition_wait_timed(&time, &global->thread->lock.alert_condition, &global->thread->lock.alert); @@ -392,7 +391,7 @@ extern "C" { global->thread->id_signal = 0; } - controller_thread_instance_cancel(*global, F_false, controller_thread_cancel_exit_e); + controller_main_thread_instance_cancel(*global, F_false, controller_thread_cancel_exit_e); } else { if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) { @@ -405,29 +404,33 @@ extern "C" { } } } -#endif // _di_controller_thread_instance_exit_ +#endif // _di_controller_main_thread_instance_exit_ -#ifndef _di_controller_thread_instance_normal_ - void * controller_thread_instance_normal(void * const arguments) { +#ifndef _di_controller_main_thread_instance_normal_ + void * controller_main_thread_instance_normal(void * const arguments) { + + if (!arguments) return 0; f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); - controller_thread_instance(F_true, (controller_instance_t *) arguments); + controller_main_thread_instance(F_true, (controller_instance_t * const) arguments); return 0; } -#endif // _di_controller_thread_instance_normal_ +#endif // _di_controller_main_thread_instance_normal_ + +#ifndef _di_controller_main_thread_instance_other_ + void * controller_main_thread_instance_other(void * const arguments) { -#ifndef _di_controller_thread_instance_other_ - void * controller_thread_instance_other(void * const arguments) { + if (!arguments) return 0; f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); - controller_thread_instance(F_false, (controller_instance_t *) arguments); + controller_main_thread_instance(F_false, (controller_instance_t * const) arguments); return 0; } -#endif // _di_controller_thread_instance_other_ +#endif // _di_controller_main_thread_instance_other_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/main/thread/instance.h b/sources/c/main/thread/instance.h index ee13a82..571e074 100644 --- a/sources/c/main/thread/instance.h +++ b/sources/c/main/thread/instance.h @@ -22,20 +22,22 @@ extern "C" { * @param is_normal * If F_true, then process as if this operates during a normal operation (entry and control). * If F_false, then process as if this operates during a an exit operation. - * @param process - * The process data. + * @param instance + * The instance data. + * Must not be NULL. * * @see controller_rule_process_do() */ -#ifndef _di_controller_thread_instance_ - extern void controller_thread_instance(const uint8_t is_normal, controller_instance_t * const instance); -#endif // _di_controller_thread_instance_ +#ifndef _di_controller_main_thread_instance_ + extern void controller_main_thread_instance(const uint8_t is_normal, controller_instance_t * const instance); +#endif // _di_controller_main_thread_instance_ /** * Cancel all process threads. * * @param global - * The global thread data. + * The global data. + * Must not be NULL. * * This does not alter global.main.setting.state.status. * @param is_normal @@ -48,53 +50,56 @@ extern "C" { * If controller_thread_cancel_call_e, then this was not called from within the signal handling thread, so cancel the signal thread. * If controller_thread_cancel_execute_e, then this was called from within the Entry/Exit for executing a process, so cancel the signal thread but not the Entry thread. */ -#ifndef _di_controller_thread_instance_cancel_ - extern void controller_thread_instance_cancel(controller_global_t * const global, const uint8_t is_normal, const uint8_t by); -#endif // _di_controller_thread_instance_cancel_ +#ifndef _di_controller_main_thread_instance_cancel_ + extern void controller_main_thread_instance_cancel(controller_global_t * const global, const uint8_t is_normal, const uint8_t by); +#endif // _di_controller_main_thread_instance_cancel_ /** * Process the Exit file, if applicable. * * @param global - * The global thread data. + * The global data. + * Must not be NULL. * * This does not alter global.main.setting.state.status. */ -#ifndef _di_controller_thread_instance_exit_ - extern void controller_thread_instance_exit(controller_global_t * const global); -#endif // _di_controller_thread_instance_exit_ +#ifndef _di_controller_main_thread_instance_exit_ + extern void controller_main_thread_instance_exit(controller_global_t * const global); +#endif // _di_controller_main_thread_instance_exit_ /** * Asynchronously execute a Rule process during normal operations. * * @param arguments * The thread arguments. - * Must be of type controller_data_t. + * Must be of type controller_global_t. + * Must not be NULL. * * @return * 0, always. * - * @see controller_thread_instance() + * @see controller_main_thread_instance() */ -#ifndef _di_controller_thread_instance_normal_ - extern void * controller_thread_instance_normal(void * const arguments); -#endif // _di_controller_thread_instance_normal_ +#ifndef _di_controller_main_thread_instance_normal_ + extern void * controller_main_thread_instance_normal(void * const global); +#endif // _di_controller_main_thread_instance_normal_ /** * Asynchronously execute a Rule process during other operations. * * @param arguments * The thread arguments. - * Must be of type controller_data_t. + * Must not be NULL. + * Must be of type controller_instance_t. * * @return * 0, always. * - * @see controller_thread_instance() + * @see controller_main_thread_instance() */ -#ifndef _di_controller_thread_instance_other_ - extern void * controller_thread_instance_other(void * const arguments); -#endif // _di_controller_thread_instance_other_ +#ifndef _di_controller_main_thread_instance_other_ + extern void * controller_main_thread_instance_other(void * const arguments); +#endif // _di_controller_main_thread_instance_other_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/main/thread/rule.c b/sources/c/main/thread/rule.c new file mode 100644 index 0000000..6845ae5 --- /dev/null +++ b/sources/c/main/thread/rule.c @@ -0,0 +1,24 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_main_thread_rule_ + void * controller_main_thread_rule(void * const arguments) { + + if (!arguments) return 0; + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_global_t * const global = (controller_global_t * const) arguments; + + if (!controller_main_thread_is_enabled(F_true, global->thread)) return 0; + + return 0; + } +#endif // _di_controller_main_thread_rule_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/thread/rule.h b/sources/c/main/thread/rule.h new file mode 100644 index 0000000..262397d --- /dev/null +++ b/sources/c/main/thread/rule.h @@ -0,0 +1,43 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the thread "rule" functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_thread_rule_h +#define _controller_main_thread_rule_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Thread for handling rule processing. + * + * This acts as the main rule thread after entry processing. + * This runs all synchronous rules or spawns asynchronous rules. + * + * @todo the control thread should send commands to this thread, somehow. + * + * @param arguments + * The global data. + * Must be of type controller_global_t. + * Must not be NULL. + * + * @return + * 0, always. + */ +#ifndef _di_controller_main_thread_rule_ + extern void * controller_main_thread_rule(void * const arguments); +#endif // _di_controller_main_thread_rule_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_thread_rule_h -- 1.8.3.1