From: Kevin Day Date: Sat, 1 Jun 2024 05:50:46 +0000 (-0500) Subject: Progress: Continue migrating the project. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=433af5bfc865863005c9f6565df0ac93eba97309;p=controller Progress: Continue migrating the project. --- diff --git a/data/build/settings b/data/build/settings index 30b25a6..64cb847 100644 --- a/data/build/settings +++ b/data/build/settings @@ -43,7 +43,7 @@ build_libraries-monolithic -lfll build_sources_library main/common.c main/common/define.c main/common/enumeration.c main/common/print.c main/common/string.c main/common/type.c build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.c main/common/type/execute.c main/common/type/global.c main/common/type/lock.c main/common/type/instance.c main/common/type/program.c main/common/type/rule.c main/common/type/thread.c 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/instance.c main/path.c main/process.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/action.c 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/print/rule/action.c main/print/rule/item.c main/print/rule/setting.c @@ -55,7 +55,7 @@ build_sources_headers main/common/define/control.h main/common/define/entry.h ma build_sources_headers main/common/enumeration/control.h main/common/enumeration/entry.h main/common/enumeration/instance.h main/common/enumeration/program.h main/common/enumeration/rule.h main/common/enumeration/thread.h build_sources_headers main/common/string/general.h main/common/string/rule.h build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/entry.h main/common/type/execute.h main/common/type/global.h main/common/type/lock.h main/common/type/instance.h main/common/type/program.h main/common/type/rule.h main/common/type/thread.h -build_sources_headers main/instance.h main/path.h +build_sources_headers main/instance.h main/path.h main/process.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/action.h 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/print/rule/action.h main/print/rule/item.h main/print/rule/setting.h diff --git a/sources/c/controller/controller.c b/sources/c/controller/controller.c index f81b2bd..d6b466c 100644 --- a/sources/c/controller/controller.c +++ b/sources/c/controller/controller.c @@ -25,7 +25,7 @@ extern "C" { return; } - // @todo controller_main(&data, &program); (also needs to include things like controller_main_thread()) + controller_main_process(data, program); if (main->setting.state.status == F_status_set_error(F_child)) return; if (main->setting.state.status == F_status_set_error(F_interrupt)) { diff --git a/sources/c/controller/controller.h b/sources/c/controller/controller.h index e7184c8..1d3fb9a 100644 --- a/sources/c/controller/controller.h +++ b/sources/c/controller/controller.h @@ -47,6 +47,8 @@ extern "C" { * A pointer to the current program settings. * * Must not be NULL. + * + * @see controller_main_process() */ #ifndef _di_controller_controller_main_ extern void controller_controller_main(controller_main_t * const main, controller_program_t * const program); diff --git a/sources/c/controller/main.c b/sources/c/controller/main.c index 1e4ae6b..6dd82da 100644 --- a/sources/c/controller/main.c +++ b/sources/c/controller/main.c @@ -38,7 +38,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { controller_main_setting_load(arguments, &data, &program); } - controller_controller_main(&data, &program); + controller_main_process(&data, &program); controller_main_delete(&data); diff --git a/sources/c/init/init.c b/sources/c/init/init.c index 8c594c3..14255cd 100644 --- a/sources/c/init/init.c +++ b/sources/c/init/init.c @@ -25,7 +25,7 @@ extern "C" { return; } - // @todo controller_main(&data, &program); + controller_main_process(data, program); if (main->setting.state.status == F_status_set_error(F_child)) return; if (main->setting.state.status == F_status_set_error(F_interrupt)) { diff --git a/sources/c/init/init.h b/sources/c/init/init.h index 5281b47..244a568 100644 --- a/sources/c/init/init.h +++ b/sources/c/init/init.h @@ -23,6 +23,8 @@ extern "C" { /** * Execute main program. * + * @todo this may or may not be needed. For now controller_main_process() is being written as a complete replacement to this. + * * If main.signal is non-zero, then this blocks and handles the following signals: * - F_signal_abort * - F_signal_broken_pipe @@ -45,6 +47,8 @@ extern "C" { * A pointer to the current program settings. * * Must not be NULL. + * + * @see controller_main_process() */ #ifndef _di_controller_init_main_ extern void controller_init_main(controller_main_t * const main, controller_program_t * const program); diff --git a/sources/c/init/main.c b/sources/c/init/main.c index 64c3bf5..fde1ef2 100644 --- a/sources/c/init/main.c +++ b/sources/c/init/main.c @@ -41,7 +41,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { controller_main_setting_load(arguments, &data, &program); } - controller_init_main(&data, &program); + controller_main_process(&data, &program); fll_program_standard_set_down(&data.program); diff --git a/sources/c/main/common.c b/sources/c/main/common.c index c621ae6..7a114ac 100644 --- a/sources/c/main/common.c +++ b/sources/c/main/common.c @@ -176,20 +176,21 @@ extern "C" { index = main->program.parameters.array[controller_parameter_settings_e].values.array[main->program.parameters.array[controller_parameter_settings_e].values.used - 1]; controller_path_canonical_relative(main, program->path_current, args[index], &program->path_setting); + + if (F_status_is_error(main->setting.state.status)) { + controller_main_print_error_file(&main->program.error, macro_controller_f(controller_path_canonical_relative), args[index], f_file_operation_verify_s, fll_error_file_type_path_e); + + return; + } } else { main->setting.state.status = f_string_dynamic_append(controller_default_path_settings_s, &program->path_setting); - } - if (F_status_is_error(main->setting.state.status)) { - if (main->program.parameters.array[controller_parameter_settings_e].locations.used) { - controller_main_print_error_file(&main->program.error, macro_controller_f(controller_path_canonical_relative), args[index], f_file_operation_verify_s, fll_error_file_type_path_e); - } - else { + if (F_status_is_error(main->setting.state.status)) { controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append)); - } - return; + return; + } } if (!program->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) { @@ -242,6 +243,27 @@ extern "C" { controller_main_print_debug_directory_path_empty(&main->program.warning, f_console_symbol_long_normal_s, controller_long_cgroup_s); } } + else { + main->setting.state.status = f_string_dynamic_append_nulless(f_control_group_path_system_prefix_s, &program->path_cgroup); + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_string_dynamic_append_nulless(f_control_group_path_system_default_s, &program->path_cgroup); + } + + if (F_status_is_error(main->setting.state.status)) { + controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append_nulless)); + + return; + } + + main->setting.state.status = f_string_dynamic_append_assure(f_path_separator_s, &program->path_cgroup); + + if (F_status_is_error(main->setting.state.status)) { + controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append_assure)); + + return; + } + } if (main->program.parameters.array[controller_parameter_interruptible_e].result & f_console_result_found_e) { if (main->program.parameters.array[controller_parameter_uninterruptible_e].result & f_console_result_found_e) { @@ -259,6 +281,14 @@ extern "C" { else if (main->program.parameters.array[controller_parameter_uninterruptible_e].result & f_console_result_found_e) { main->setting.flag &= ~controller_main_flag_interruptible_e; } + + if (main->program.parameters.array[f_console_standard_parameter_daemon_e].result & f_console_result_found_e) { + main->setting.flag |= controller_main_flag_daemon_e; + } + + if (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) { + main->setting.flag |= controller_main_flag_validate_e; + } } #endif // _di_controller_main_setting_load_ diff --git a/sources/c/main/common/enumeration.h b/sources/c/main/common/enumeration.h index 345558f..283b565 100644 --- a/sources/c/main/common/enumeration.h +++ b/sources/c/main/common/enumeration.h @@ -24,11 +24,13 @@ extern "C" { * controller_main_flag_*_e: * - none: No flags set. * - copyright: Print copyright. + * - daemon: Run the process in the background and create a PID file. * - error: Check if status is "error". * - fine: Check if status is "fine". * - help: Print help. * - interruptible: The process is interruptible. * - pipe: Use the input pipe. + * - validate: Perform validation of rules rather than execution. * - version: Print version. * - version_copyright_help: A helper flag representing version, copyright, and help flag bits being set. * - warning: Check if status is "warning". @@ -37,14 +39,16 @@ extern "C" { enum { controller_main_flag_none_e = 0x0, controller_main_flag_copyright_e = 0x1, - controller_main_flag_error_e = 0x2, - controller_main_flag_fine_e = 0x4, - controller_main_flag_help_e = 0x8, - controller_main_flag_interruptible_e = 0x10, - controller_main_flag_pipe_e = 0x20, - controller_main_flag_version_e = 0x40, - controller_main_flag_version_copyright_help_e = 0x49, - controller_main_flag_warning_e = 0x80, + controller_main_flag_daemon_e = 0x2, + controller_main_flag_error_e = 0x4, + controller_main_flag_fine_e = 0x8, + controller_main_flag_help_e = 0x10, + controller_main_flag_interruptible_e = 0x20, + controller_main_flag_pipe_e = 0x40, + controller_main_flag_validate_e = 0x80, + controller_main_flag_version_e = 0x100, + controller_main_flag_version_copyright_help_e = 0x111, + controller_main_flag_warning_e = 0x200, }; // enum #endif // _di_controller_main_flag_e_ diff --git a/sources/c/main/common/print.c b/sources/c/main/common/print.c index 4dd7aba..6d597f4 100644 --- a/sources/c/main/common/print.c +++ b/sources/c/main/common/print.c @@ -21,6 +21,7 @@ extern "C" { "f_rip_dynamic_partial_nulless", "f_string_append_assure", "f_string_dynamic_append", + "f_string_dynamic_append_assure", "f_string_dynamic_append_nulless", "f_string_dynamic_partial_append", "f_string_dynamic_partial_append_nulless", diff --git a/sources/c/main/common/print.h b/sources/c/main/common/print.h index 7517992..dc436ad 100644 --- a/sources/c/main/common/print.h +++ b/sources/c/main/common/print.h @@ -54,6 +54,7 @@ extern "C" { controller_f_f_rip_dynamic_partial_nulless_e, controller_f_f_string_append_assure_e, controller_f_f_string_dynamic_append_e, + controller_f_f_string_dynamic_append_assure_e, controller_f_f_string_dynamic_append_nulless_e, controller_f_f_string_dynamic_partial_append_e, controller_f_f_string_dynamic_partial_append_nulless_e, diff --git a/sources/c/main/common/type/global.h b/sources/c/main/common/type/global.h index 77c8614..4e3a7aa 100644 --- a/sources/c/main/common/type/global.h +++ b/sources/c/main/common/type/global.h @@ -19,15 +19,16 @@ extern "C" { /** * A wrapper used for passing a common set of all data, particularly for sharing between threads. * - * main: The main program data. - * program: The program data. - * thread: The thread data for a specific thread. + * Properties: + * - main: The main program data. + * - program: The program data. + * - thread: The thread data for a specific thread. * - * message: A message printer, with custom set to this structure. - * output: An output printer, with custom set to this structure. - * error: An error printer, with custom set to this structure. - * warning: A warning printer, with custom set to this structure. - * debug: A debug printer, with custom set to this structure. + * - message: The output file for normal output messages (often stdout), but with custom set to (controller_global_t *). + * - output: The output file for normal/non-message output, aka data output (often stdout or a file), but with custom set to (controller_global_t *). + * - error: The output file for error output messages, but with custom set to (controller_global_t *). + * - warning: The output file for warning output messages, but with custom set to (controller_global_t *). + * - debug: The output file for debug output messages, but with custom set to (controller_global_t *). */ #ifndef _di_controller_global_t_ typedef struct { @@ -35,24 +36,24 @@ extern "C" { controller_program_t *program; controller_thread_t *thread; - fl_print_t message; - fl_print_t output; - fl_print_t error; - fl_print_t warning; - fl_print_t debug; + fl_print_t *message; + fl_print_t *output; + fl_print_t *error; + fl_print_t *warning; + fl_print_t *debug; } controller_global_t; - #define controller_global_t_initialize { 0, 0, 0 } + #define controller_global_t_initialize { 0, 0, 0, 0, 0, 0, 0, 0 } - #define macro_controller_global_t_initialize(main, program, thread) { \ + #define macro_controller_global_t_initialize_1(main, program, thread, message, output, error, warning, debug) { \ main, \ program, \ thread, \ - fl_print_t_initialize, \ - fl_print_t_initialize, \ - macro_fl_print_t_initialize_error(), \ - macro_fl_print_t_initialize_warning(), \ - macro_fl_print_t_initialize_debug(), \ + message, \ + output, \ + error, \ + warning, \ + debug, \ } #endif // _di_controller_global_t_ diff --git a/sources/c/main/common/type/instance.h b/sources/c/main/common/type/instance.h index fa02e53..f0ef03c 100644 --- a/sources/c/main/common/type/instance.h +++ b/sources/c/main/common/type/instance.h @@ -42,12 +42,9 @@ extern "C" { * path_pids: An array of paths representing PID files. * stack: A stack used to represent dependencies as Rule ID's to avoid circular Rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A). * - * rule: A copy of the rule actively being executed. - * cache: The cache used by this Instance. - * - * main: The associated main program data (of type controller_main_t). - * program: The associated program data. - * thread: The associated thread data (of type f_thread_t). + * rule: A copy of the rule actively being executed. + * cache: The cache used by this Instance. + * global: The global data. */ #ifndef _di_controller_instance_t_ typedef struct { @@ -71,13 +68,7 @@ extern "C" { controller_rule_t rule; controller_cache_t cache; - - // @fixme change this to void *global where global is controller_global_t?? - // @fixme each instance probably needs its own thread data and this likely needs to be backported if it do-able in a non-breaking-change manner! - // @fixme I may want to instead replace the controller_global_t with controller_instance_t during printing calls (maybe more??). - void *main; - controller_program_t *program; - void *thread; + controller_global_t global; } controller_instance_t; #define controller_instance_t_initialize { \ @@ -97,9 +88,7 @@ extern "C" { f_number_unsigneds_t_initialize, \ controller_rule_t_initialize, \ controller_cache_t_initialize, \ - 0, \ - 0, \ - 0, \ + controller_global_t_initialize, \ } #endif // _di_controller_instance_t_ diff --git a/sources/c/main/common/type/thread.h b/sources/c/main/common/type/thread.h index 2970a3c..918e668 100644 --- a/sources/c/main/common/type/thread.h +++ b/sources/c/main/common/type/thread.h @@ -38,7 +38,7 @@ extern "C" { * cache: A cache used by the main entry/rule processing thread for synchronous operations. */ #ifndef _di_controller_thread_t_ - typedef struct controller_thread_t_ { + typedef struct { uint8_t enabled; int signal; f_status_t status; diff --git a/sources/c/main/controller.h b/sources/c/main/controller.h index b6a8ac2..7dce5c6 100644 --- a/sources/c/main/controller.h +++ b/sources/c/main/controller.h @@ -97,10 +97,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include @@ -136,6 +136,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/sources/c/main/print/error.c b/sources/c/main/print/error.c index f23c975..8e69031 100644 --- a/sources/c/main/print/error.c +++ b/sources/c/main/print/error.c @@ -18,6 +18,24 @@ extern "C" { } #endif // _di_controller_main_print_error_ +#ifndef _di_controller_main_print_error_failsafe_item_ + f_status_t controller_main_print_error_failsafe_item(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const name) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_lock_print(print->to, thread); + + fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, name, print->set->notable); + fl_print_format(f_string_format_sentence_end_quote_s.string, print->to, print->context, print->context, f_string_eol_s); + + controller_unlock_print_flush(print->to, thread); + + return F_okay; + } +#endif // _di_controller_main_print_error_failsafe_item_ + #ifndef _di_controller_main_print_error_file_ f_status_t controller_main_print_error_file(fl_print_t * const print, const f_string_t function, const f_string_static_t name, const f_string_static_t operation, const uint8_t type) { @@ -44,6 +62,24 @@ extern "C" { } #endif // _di_controller_main_print_error_file_status_ +#ifndef _di_controller_main_print_error_file_pid_exists_ + f_status_t controller_main_print_error_file_pid_exists(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const path) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + controller_lock_print(print->to, 0); + + fl_print_format("%r%[%QThe pid file '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, path, print->set->notable); + fl_print_format("%[' must not already exist.%]%r", print->to, print->context, print->context, f_string_eol_s); + + controller_unlock_print_flush(print->to, 0); + + return F_okay; + } +#endif // _di_controller_main_print_error_file_pid_exists_ + #ifndef _di_controller_main_print_error_status_ f_status_t controller_main_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status) { diff --git a/sources/c/main/print/error.h b/sources/c/main/print/error.h index 61fe780..46282b9 100644 --- a/sources/c/main/print/error.h +++ b/sources/c/main/print/error.h @@ -40,6 +40,36 @@ extern "C" { #endif // _di_controller_main_print_error_ /** + * Print error message regarding the failsafe item failing. + * + * @param print + * The output structure to print to. + * + * Must not be NULL. + * + * This does not alter print.custom.setting.state.status. + * @param thread + * The name of the function associated with the error. + * + * Must not be NULL. + * @param name + * The name of the item. + * + * Must not be NULL. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_print() + */ +#ifndef _di_controller_main_print_error_failsafe_item_ + extern f_status_t controller_main_print_error_failsafe_item(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const name); +#endif // _di_controller_main_print_error_failsafe_item_ + +/** * Print file related error or warning messages. * * @param print @@ -185,6 +215,36 @@ extern "C" { extern void controller_main_print_rule_error_cache(fl_print_t * const print, const controller_cache_action_t cache, const bool item); #endif // _di_controller_main_print_rule_error_cache_ +/** + * Print error message regarding the pid file already existing. + * + * @param print + * The output structure to print to. + * + * Must not be NULL. + * + * This does not alter print.custom.setting.state.status. + * @param thread + * The name of the function associated with the error. + * + * Must not be NULL. + * @param path + * The path to the PID file. + * + * Must not be NULL. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_print() + */ +#ifndef _di_controller_main_print_error_file_pid_exists_ + extern f_status_t controller_main_print_error_file_pid_exists(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const path); +#endif // _di_controller_main_print_error_file_pid_exists_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/main/process.c b/sources/c/main/process.c new file mode 100644 index 0000000..5c5bddd --- /dev/null +++ b/sources/c/main/process.c @@ -0,0 +1,169 @@ +#include "controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_main_process_ + void controller_main_process(controller_main_t * const main, controller_program_t * const program) { + + if (!main || !program || F_status_is_error(main->setting.state.status)) return; + + main->setting.state.status = F_okay; + + if (main->setting.flag & controller_main_flag_version_copyright_help_e) { + if (main->setting.flag & controller_main_flag_help_e) { + controller_main_print_message_help(&main->program.message, F_false); + } + else if (main->setting.flag & controller_main_flag_version_e) { + fll_program_print_version(&main->program.message, controller_program_version_s); + } + else if (main->setting.flag & controller_main_flag_copyright_e) { + fll_program_print_copyright(&main->program.message, fll_program_copyright_year_author_s); + } + + return; + } + + // A custom status at this scope is used to prevent the status from being changed by any child process or sub-function. + f_status_t status = F_okay; + + fl_print_t message = main->program.message; + fl_print_t output = main->program.output; + fl_print_t error = main->program.error; + fl_print_t warning = main->program.warning; + fl_print_t debug = main->program.debug; + + controller_thread_t thread = controller_thread_t_initialize; + controller_global_t global = macro_controller_global_t_initialize_1(main, program, &thread, &message, &output, &error, &warning, &debug); + + message.custom = output.custom = error.custom = warning.custom = debug.custom = (void *) &global; + + // The global locks must be initialized, but only once, so initialize immediately upon allocation. + status = controller_main_lock_create(&thread.lock); + + if (F_status_is_error(status)) { + controller_main_print_error_status(&main->program.error, macro_controller_f(controller_main_lock_create), status); + } else { + status = f_memory_array_increase(controller_allocation_small_d, sizeof(controller_instance_t), (void **) &thread.instances.array, &thread.instances.used, &thread.instances.size); + + if (F_status_is_error(status)) { + controller_main_print_error_status(&main->program.error, macro_controller_f(f_memory_array_increase), status); + } + } + + if (F_status_is_error_not(status)) { + status = f_thread_create(0, &thread.id_signal, &controller_thread_signal_normal, (void *) &global); + } + + if (F_status_is_error(status)) { + thread.id_signal = 0; + + controller_main_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status); + } + else { + if (main->setting.flag & controller_main_flag_daemon_e) { + program->ready = controller_setting_ready_done_e; + + if (f_file_exists(program->path_pid, F_true) == F_true) { + status = F_status_set_error(F_available_not); + program->ready = controller_setting_ready_abort_e; + + controller_main_print_error_file_pid_exists(&main->program.error, &thread, program->path_pid); + } + } + else if (program->name_entry.used) { + status = f_thread_create(0, &thread.id_entry, &controller_main_thread_entry, (void *) &global); + + if (F_status_is_error(status)) { + controller_main_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status); + } + else { + controller_thread_join(&thread.id_entry); + + status = thread.status; + thread.id_entry = 0; + } + } + } + + // Only make the rule and control threads available once any/all pre-processing are complete. + if (F_status_is_error_not(status) && status != F_failure && status != F_child && thread.enabled == controller_thread_enabled_e) { + if (!(main->setting.flag & controller_main_flag_validate_e)) { + + // Wait for the entry thread to complete before starting the rule thread. + controller_main_thread_join(&thread.id_rule); + + if (thread.enabled && program->mode == controller_setting_mode_service_e) { + status = f_thread_create(0, &thread.id_rule, &controller_main_thread_rule, (void *) &global); + + if (F_status_is_error(status)) { + thread.id_rule = 0; + } + else { + status = f_thread_create(0, &thread.id_cleanup, &controller_main_thread_cleanup, (void *) &global); + } + + if (F_status_is_error(status)) { + thread.id_cleanup = 0; + + controller_main_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status); + } + } + } + } + + if (status == F_child) { + main->setting.state.status = F_child; + + controller_main_thread_delete(&thread); + + return; + } + + if (F_status_is_error_not(status) && status != F_failure && !(main->setting.flag & controller_main_flag_validate_e) && controller_thread_is_enabled(F_true, &thread)) { + if (program->mode == controller_setting_mode_service_e) { + controller_main_thread_join(&thread.id_signal); + } + else if (program->mode == controller_setting_mode_helper_e || program->mode == controller_setting_mode_program_e) { + status = controller_main_rule_wait_all(global, F_true, F_false); + } + } + + controller_main_thread_process_cancel(global, F_true, controller_thread_cancel_call_e); + + controller_main_thread_process_exit(&global); + + if (thread.id_signal) f_thread_join(thread.id_signal, 0); + if (thread.id_cleanup) f_thread_join(thread.id_cleanup, 0); + if (thread.id_control) f_thread_join(thread.id_control, 0); + if (thread.id_entry) f_thread_join(thread.id_entry, 0); + if (thread.id_rule) f_thread_join(thread.id_rule, 0); + + thread.id_cleanup = 0; + thread.id_control = 0; + thread.id_entry = 0; + thread.id_rule = 0; + thread.id_signal = 0; + + controller_main_thread_delete(&thread); + + if (F_status_set_fine(status) == F_interrupt) { + fll_program_print_signal_received(&main->program.warning, thread.signal); + + if (main->program.output.verbosity > f_console_verbosity_quiet_e) { + fll_print_dynamic_raw(f_string_eol_s, main->program.output.to); + } + + fll_program_print_signal_received(&main->program.warning, main->program.signal_received); + + return F_status_set_error(F_interrupt); + } + + return F_status_is_error(status) ? F_status_set_error(F_failure) : F_okay; + } +#endif // _di_controller_main_process_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/process.h b/sources/c/main/process.h new file mode 100644 index 0000000..e800d40 --- /dev/null +++ b/sources/c/main/process.h @@ -0,0 +1,55 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the main process functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_process_h +#define _controller_main_process_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Execute main program process. + * + * If main.signal is non-zero, then this blocks and handles the following signals: + * - F_signal_abort + * - F_signal_broken_pipe + * - F_signal_hangup + * - F_signal_interrupt + * - F_signal_quit + * - F_signal_termination + * + * @param main + * The main program data and settings. + * + * Must not be NULL. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_true on success when performing verification and verify passed. + * F_false on success when performing verification and verify failed. + * F_interrupt on (exit) signal received. + * + * F_parameter (with error bit) if main is NULL or setting is NULL. + * @param program + * A pointer to the current program settings. + * + * Must not be NULL. + */ +#ifndef controller_main_process + extern void controller_main_process(controller_main_t * const main, controller_program_t * const program); +#endif // controller_main_process + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_process_h diff --git a/sources/c/main/thread/entry.c b/sources/c/main/thread/entry.c index c970530..4fcd809 100644 --- a/sources/c/main/thread/entry.c +++ b/sources/c/main/thread/entry.c @@ -11,94 +11,76 @@ extern "C" { f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); - controller_instance_t * const instance = (controller_instance_t * const ) arguments; + controller_global_t * const global = (controller_global_t * const) arguments; - if (!controller_main_thread_is_enabled(F_true, instance->thread)) return 0; + if (!controller_main_thread_is_enabled(F_true, global->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; + f_status_t * const status = &global->thread->status; - *status = controller_entry_read(*instance->global, F_true, cache); + *status = controller_main_entry_read(global, F_true); if (F_status_set_fine(*status) == F_interrupt) { - instance->setting->ready = controller_setting_ready_abort_e; + global->program->ready = controller_setting_ready_abort_e; } else if (F_status_is_error(*status)) { - instance->setting->ready = controller_setting_ready_fail_e; + global->program->ready = controller_setting_ready_fail_e; } else if (*status != F_child) { - *status = controller_entry_preprocess(*instance->global, F_true, cache); + *status = controller_main_entry_preprocess(global, F_true); - 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 ((global->main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (global->main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) { + controller_main_entry_setting_validate(global, F_true); } } 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); - } + if (!(global->main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) || (global->main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) { - instance->setting->ready = controller_setting_ready_fail_e; + if (global->program->entry.pid == controller_entry_pid_require_e && f_file_exists(global->program->path_pid, F_true) == F_true) { *status = F_status_set_error(F_available_not); + global->program->ready = controller_setting_ready_fail_e; + + controller_main_print_error_file_pid_exists(&global->main->program.error, global->thread, global->program->path_pid); } else { - *status = controller_entry_process(instance->global, cache, F_false, F_true); + *status = controller_main_entry_process(global, F_false, F_true); if (F_status_is_error(*status)) { - instance->setting->ready = controller_setting_ready_fail_e; + global->program->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; + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (program->flag & controller_setting_flag_failsafe_e)) { + const uint8_t original_enabled = global->thread->enabled; // Restore operating mode so that the failsafe can execute. - *status = f_thread_mutex_lock(&instance->thread->lock.alert); + *status = f_thread_mutex_lock(&global->thread->lock.alert); if (F_status_is_error_not(*status)) { - instance->thread->enabled = controller_thread_enabled_e; + global->thread->enabled = controller_thread_enabled_e; - f_thread_mutex_unlock(&instance->thread->lock.alert); + f_thread_mutex_unlock(&global->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); + // Restart the signal global->thread to allow for signals while operating the failsafe Items. + if (!global->thread->id_signal) { + f_thread_create(0, &global->thread->id_signal, &controller_main_thread_signal_normal, (void *) global); } - const f_status_t status_failsafe = controller_entry_process(instance->global, cache, F_true, F_true); + const f_status_t status_failsafe = controller_main_entry_process(global, 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); + + controller_main_print_error_failsafe_item(&global->main->program.error, global->thread, global->program->entry.items.array[program->failsafe_item_id].name); } else { // Restore operating mode to value prior to failsafe mode. - *status = f_thread_mutex_lock(&instance->thread->lock.alert); + *status = f_thread_mutex_lock(&global->thread->lock.alert); if (F_status_is_error_not(*status)) { - instance->thread->enabled = original_enabled; + global->thread->enabled = original_enabled; - f_thread_mutex_unlock(&instance->thread->lock.alert); + f_thread_mutex_unlock(&global->thread->lock.alert); } *status = F_failure; @@ -106,21 +88,21 @@ extern "C" { } } else if (F_status_set_fine(*status) == F_interrupt) { - instance->setting->ready = controller_setting_ready_abort_e; + global->program->ready = controller_setting_ready_abort_e; } else if (*status != F_child) { - instance->setting->ready = controller_setting_ready_done_e; + global->program->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) { + if (F_status_is_error_not(*status) && *status != F_child && global->main->program.parameters.array[controller_parameter_validate_e].result == f_console_result_none_e && global->program->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); + controller_main_thread_process_cancel(global, F_true, controller_thread_cancel_exit_e); } } } @@ -129,17 +111,17 @@ extern "C" { // 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); + controller_main_thread_delete(global->thread); + controller_main_program_delete(global->program); + controller_main_delete(global->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); + // According to the manpages, pthread_exit() calls exit(0), which the value of global->main->program.child should be returned instead. + if (global->main->program.child) exit(global->main->program.child); return 0; } - f_thread_condition_signal_all(&instance->thread->lock.alert_condition); + f_thread_condition_signal_all(&global->thread->lock.alert_condition); return 0; } @@ -152,83 +134,75 @@ extern "C" { f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); - controller_main_entry_t *instance = (controller_main_entry_t *) arguments; + controller_global_t * const global = (controller_global_t * const) arguments; - controller_main_t * const main = instance->main; - controller_cache_t * const cache = &instance->thread->cache; - f_status_t * const status = &instance->thread->status; + controller_main_t * const main = global->main; + controller_cache_t * const cache = &global->thread->cache; + f_status_t * const status = &global->thread->status; - *status = controller_entry_read(*instance->global, F_false, cache); + *status = controller_entry_read(global, F_false); if (F_status_set_fine(*status) == F_interrupt) { - instance->setting->ready = controller_setting_ready_abort_e; + global->program->ready = controller_setting_ready_abort_e; } else if (F_status_is_error(*status)) { - instance->setting->ready = controller_setting_ready_fail_e; + global->program->ready = controller_setting_ready_fail_e; } else if (*status == F_file_found_not) { - instance->setting->ready = controller_setting_ready_done_e; + global->program->ready = controller_setting_ready_done_e; } else if (*status != F_child) { - *status = controller_entry_preprocess(*instance->global, F_false, cache); + *status = controller_entry_preprocess(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); + controller_entry_setting_validate(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); + *status = controller_entry_process(global, F_false, F_false); if (F_status_is_error(*status)) { - instance->setting->ready = controller_setting_ready_fail_e; + global->program->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)) { + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (global->program->flag & controller_setting_flag_failsafe_e)) { - const uint8_t original_enabled = instance->thread->enabled; + const uint8_t original_enabled = global->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); + *status = f_thread_mutex_lock(&global->thread->lock.alert); if (F_status_is_error_not(*status)) { - instance->thread->enabled = controller_thread_enabled_exit_e; + global->thread->enabled = controller_thread_enabled_exit_e; - f_thread_mutex_unlock(&instance->thread->lock.alert); + f_thread_mutex_unlock(&global->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); + if (!global->thread->id_signal) { + f_thread_create(0, &global->thread->id_signal, &controller_main_thread_signal_other, (void *) global); } } - const f_status_t status_failsafe = controller_entry_process(instance->global, cache, F_true, F_false); + const f_status_t status_failsafe = controller_entry_process(global, 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); + + controller_main_print_error_failsafe_item(&global->main->program.error, global->thread, global->program->entry.items.array[program->failsafe_item_id].name); } else { // Restore operating mode to value prior to failsafe mode. - *status = f_thread_mutex_lock(&instance->thread->lock.alert); + *status = f_thread_mutex_lock(&global->thread->lock.alert); if (F_status_is_error_not(*status)) { - instance->thread->enabled = original_enabled; + global->thread->enabled = original_enabled; - f_thread_mutex_unlock(&instance->thread->lock.alert); + f_thread_mutex_unlock(&global->thread->lock.alert); } *status = F_failure; @@ -236,10 +210,10 @@ extern "C" { } } else if (F_status_set_fine(*status) == F_interrupt) { - instance->setting->ready = controller_setting_ready_abort_e; + global->program->ready = controller_setting_ready_abort_e; } else if (*status != F_child) { - instance->setting->ready = controller_setting_ready_done_e; + global->program->ready = controller_setting_ready_done_e; } } } @@ -248,20 +222,20 @@ extern "C" { // 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_thread_delete_simple(global->thread); + controller_process_delete(global->program); 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; + if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) { + global->thread->enabled = controller_thread_enabled_not_e; - f_thread_mutex_unlock(&instance->thread->lock.alert); + f_thread_mutex_unlock(&global->thread->lock.alert); } - f_thread_condition_signal_all(&instance->thread->lock.alert_condition); + f_thread_condition_signal_all(&global->thread->lock.alert_condition); return 0; }