From 7ec9977f1e720fba5bfd1e14fc7266bc5e240440 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sat, 27 Apr 2024 01:01:38 -0500 Subject: [PATCH] Progress: Continue migrating the project. --- data/build/defines | 16 +- data/build/settings | 12 +- sources/c/controller/controller.c | 7 +- sources/c/controller/controller.h | 88 +---- sources/c/controller/main.c | 40 +- sources/c/init/init.c | 7 +- sources/c/init/init.h | 88 +---- sources/c/init/main.c | 47 +-- sources/c/main/common.c | 38 +- sources/c/main/common.h | 10 +- sources/c/main/common/enumeration/instance.h | 77 ++++ .../common/enumeration/{process.h => program.h} | 50 +-- sources/c/main/common/type/control.c | 6 +- sources/c/main/common/type/control.h | 7 +- sources/c/main/common/type/entry.c | 24 +- sources/c/main/common/type/entry.h | 28 +- sources/c/main/common/type/global.c | 9 + sources/c/main/common/type/global.h | 70 ++++ sources/c/main/common/type/instance.c | 33 ++ sources/c/main/common/type/instance.h | 171 ++++++++ sources/c/main/common/type/lock.c | 55 +-- sources/c/main/common/type/lock.h | 30 -- sources/c/main/common/type/process.c | 36 -- sources/c/main/common/type/program.c | 33 ++ .../c/main/common/type/{process.h => program.h} | 35 +- sources/c/main/common/type/rule.h | 4 +- sources/c/main/common/type/thread.c | 3 +- sources/c/main/common/type/thread.h | 14 +- sources/c/main/controller.h | 7 +- sources/c/main/print/error.c | 12 + sources/c/main/print/error.h | 27 +- sources/c/main/thread.c | 92 ++++- sources/c/main/thread.h | 84 +++- sources/c/main/thread/instance.c | 434 +++++++++++++++++++++ sources/c/main/thread/instance.h | 103 +++++ sources/c/main/thread/is.c | 34 ++ sources/c/main/thread/is.h | 58 +++ sources/c/main/time.c | 79 ++++ sources/c/main/time.h | 59 +++ 39 files changed, 1510 insertions(+), 517 deletions(-) create mode 100644 sources/c/main/common/enumeration/instance.h rename sources/c/main/common/enumeration/{process.h => program.h} (58%) create mode 100644 sources/c/main/common/type/global.c create mode 100644 sources/c/main/common/type/global.h create mode 100644 sources/c/main/common/type/instance.c create mode 100644 sources/c/main/common/type/instance.h delete mode 100644 sources/c/main/common/type/process.c create mode 100644 sources/c/main/common/type/program.c rename sources/c/main/common/type/{process.h => program.h} (72%) create mode 100644 sources/c/main/thread/instance.c create mode 100644 sources/c/main/thread/instance.h create mode 100644 sources/c/main/thread/is.c create mode 100644 sources/c/main/thread/is.h create mode 100644 sources/c/main/time.c create mode 100644 sources/c/main/time.h diff --git a/data/build/defines b/data/build/defines index 345bd45..f282d0f 100644 --- a/data/build/defines +++ b/data/build/defines @@ -5,14 +5,14 @@ _di_thread_support_ Disables thread support. _libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later). -_override_controller_default_engine_ Provide a custom scripting engine name string to execute (such as php). -_override_controller_path_pid_ Use this as the default custom directory path representing the location of the controller program pid. -_override_controller_path_pid_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid. -_override_controller_path_pid_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid. -_override_controller_path_settings_ Use this as the default custom settings path, such as /etc/settings. -_override_controller_path_socket_ Use this as the default custom directory path representing the location of the controller program socket. -_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket. -_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket. +_override_controller_default_engine_ Provide a custom scripting engine name string to execute (such as php). +_override_controller_path_pid_ Use this as the default custom directory path representing the location of the controller program pid. +_override_controller_path_pid_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid. +_override_controller_path_pid_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid. +_override_controller_path_settings_ Use this as the default custom settings path, such as /etc/settings. +_override_controller_path_socket_ Use this as the default custom directory path representing the location of the controller program socket. +_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket. +_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket. _override_controller_default_engine_length_ The number of bytes representing the string in _override_controller_default_engine_ (not including the terminating NULL). _override_controller_path_pid_length_ The number of bytes representing the string in _override_controller_path_pid_ (not including the terminating NULL). diff --git a/data/build/settings b/data/build/settings index bbaed75..bed0aab 100644 --- a/data/build/settings +++ b/data/build/settings @@ -41,20 +41,20 @@ build_libraries-level -lfll_2 -lfll_1 -lfll_0 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/lock.c main/common/type/process.c main/common/type/rule.c main/common/type/thread.c +build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.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/path.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/verbose.c main/print/warning.c -build_sources_library main/signal.c main/thread.c +build_sources_library main/signal.c main/thread.c main/thread/instance.c main/thread/is.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/type.h +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 -build_sources_headers main/common/enumeration/control.h main/common/enumeration/entry.h main/common/enumeration/process.h main/common/enumeration/rule.h main/common/enumeration/thread.h +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/lock.h main/common/type/process.h main/common/type/rule.h main/common/type/thread.h +build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/entry.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/path.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/verbose.h main/print/warning.h -build_sources_headers main/signal.h main/thread.h +build_sources_headers main/signal.h main/thread.h main/thread/instance.h main/thread/is.h build_sources_documentation man diff --git a/sources/c/controller/controller.c b/sources/c/controller/controller.c index 579f58b..13aa16f 100644 --- a/sources/c/controller/controller.c +++ b/sources/c/controller/controller.c @@ -5,9 +5,9 @@ extern "C" { #endif #ifndef _di_controller_controller_main_ - void controller_controller_main(controller_main_t * const main, controller_process_t * const process) { + void controller_controller_main(controller_main_t * const main, controller_program_t * const program) { - if (!main || !process) return; + if (!main || !program) return; if (F_status_is_error(main->setting.state.status)) { if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) { @@ -41,6 +41,9 @@ extern "C" { return; } + // @todo controller_main(&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)) { fll_program_print_signal_received(&main->program.warning, main->program.signal_received); } diff --git a/sources/c/controller/controller.h b/sources/c/controller/controller.h index 94832c5..e7184c8 100644 --- a/sources/c/controller/controller.h +++ b/sources/c/controller/controller.h @@ -12,88 +12,8 @@ #ifndef _controller_controller_h #define _controller_controller_h -// Include pre-requirements. -#ifndef _GNU_SOURCE - #define _GNU_SOURCE -#endif // _GNU_SOURCE - -// Libc includes. -#include -#include -#include -#include - -// FLL-0 includes. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _di_thread_support_ - #include -#endif // _di_thread_support_ - -// FLL-1 includes. -#include -#include -#include - -// FLL-2 includes. -#include -#include -#include - // Controller includes. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #ifdef __cplusplus @@ -123,13 +43,13 @@ extern "C" { * F_interrupt on (exit) signal received. * * F_parameter (with error bit) if main is NULL or setting is NULL. - * @param process - * A pointer to the current process settings. + * @param program + * A pointer to the current program settings. * * Must not be NULL. */ #ifndef _di_controller_controller_main_ - extern void controller_controller_main(controller_main_t * const main, controller_process_t * const process); + extern void controller_controller_main(controller_main_t * const main, controller_program_t * const program); #endif // _di_controller_controller_main_ #ifdef __cplusplus diff --git a/sources/c/controller/main.c b/sources/c/controller/main.c index b424ea8..1e4ae6b 100644 --- a/sources/c/controller/main.c +++ b/sources/c/controller/main.c @@ -3,7 +3,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { controller_main_t data = controller_main_t_initialize; - controller_process_t process = controller_process_t_initialize; + controller_program_t program = controller_program_t_initialize; data.program.debug.flag |= controller_print_flag_debug_e | controller_print_flag_out_e; data.program.error.flag |= controller_print_flag_error_e | controller_print_flag_out_e; @@ -32,41 +32,13 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { f_file_umask_get(&data.program.umask); - #ifdef _di_thread_support_ - { - const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); + { + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); - controller_main_setting_load(arguments, &data, &process); - } - - controller_controller_main(&data, &process); - #else - { - f_thread_id_t id_signal; - - memset(&id_signal, 0, sizeof(f_thread_id_t)); - - data.setting.state.status = f_thread_create(0, &id_signal, &controller_main_thread_signal, (void *) &data); - - if (F_status_is_error(data.setting.state.status)) { - controller_main_print_error(&data.program.error, macro_controller_f(f_thread_create)); - } - else { - { - const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); - - controller_main_setting_load(arguments, &data, &process); - } - - if (!controller_main_signal_check(&data)) { - controller_controller_main(&data, &process); - } + controller_main_setting_load(arguments, &data, &program); + } - f_thread_cancel(id_signal); - f_thread_join(id_signal, 0); - } - } - #endif // _di_thread_support_ + controller_controller_main(&data, &program); controller_main_delete(&data); diff --git a/sources/c/init/init.c b/sources/c/init/init.c index 55e3b73..ee22aca 100644 --- a/sources/c/init/init.c +++ b/sources/c/init/init.c @@ -5,9 +5,9 @@ extern "C" { #endif #ifndef _di_controller_init_main_ - void controller_init_main(controller_main_t * const main) { + void controller_init_main(controller_main_t * const main, controller_program_t * const program) { - if (!main) return; + if (!main || !program) return; if (F_status_is_error(main->setting.state.status)) { if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) { @@ -41,6 +41,9 @@ extern "C" { return; } + // @todo controller_main(&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)) { fll_program_print_signal_received(&main->program.warning, main->program.signal_received); } diff --git a/sources/c/init/init.h b/sources/c/init/init.h index 1e639bf..5281b47 100644 --- a/sources/c/init/init.h +++ b/sources/c/init/init.h @@ -12,88 +12,8 @@ #ifndef _controller_init_h #define _controller_init_h -// Include pre-requirements. -#ifndef _GNU_SOURCE - #define _GNU_SOURCE -#endif // _GNU_SOURCE - -// Libc includes. -#include -#include -#include -#include - -// FLL-0 includes. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _di_thread_support_ - #include -#endif // _di_thread_support_ - -// FLL-1 includes. -#include -#include -#include - -// FLL-2 includes. -#include -#include -#include - // Controller includes. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #ifdef __cplusplus @@ -121,9 +41,13 @@ extern "C" { * 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 _di_controller_init_main_ - extern void controller_init_main(controller_main_t * const main); + extern void controller_init_main(controller_main_t * const main, controller_program_t * const program); #endif // _di_controller_init_main_ #ifdef __cplusplus diff --git a/sources/c/init/main.c b/sources/c/init/main.c index deb3e07..64c3bf5 100644 --- a/sources/c/init/main.c +++ b/sources/c/init/main.c @@ -3,7 +3,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { controller_main_t data = controller_main_t_initialize; - controller_process_t process = controller_process_t_initialize; + controller_program_t program = controller_program_t_initialize; data.program.debug.flag |= controller_print_flag_debug_e | controller_print_flag_out_e; data.program.error.flag |= controller_print_flag_error_e | controller_print_flag_out_e; @@ -27,50 +27,21 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { } data.setting.flag &= ~controller_main_flag_interruptible_e; - process.entry.pid = controller_entry_pid_disable_e; - process.entry.show = controller_entry_show_init_e; + program.entry.pid = controller_entry_pid_disable_e; + program.entry.show = controller_entry_show_init_e; + program.mode = controller_program_mode_service_e; fll_program_standard_set_up(&data.program); f_file_umask_get(&data.program.umask); - #ifdef _di_thread_support_ - { - const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); + { + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); - controller_main_setting_load(arguments, &data, &process); - } - - controller_init_main(&data); - #else - { - f_thread_id_t id_signal; - - memset(&id_signal, 0, sizeof(f_thread_id_t)); - - data.setting.state.status = f_thread_create(0, &id_signal, &controller_main_thread_signal, (void *) &data); - - if (F_status_is_error(data.setting.state.status)) { - controller_main_print_error(&data.program.error, macro_controller_f(f_thread_create)); - } - else { - { - const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); - - controller_main_setting_load(arguments, &data, &process); - } - - if (!controller_main_signal_check(&data)) { - controller_init_main(&data); - } - - f_thread_cancel(id_signal); - f_thread_join(id_signal, 0); - } - } - #endif // _di_thread_support_ + controller_main_setting_load(arguments, &data, &program); + } - controller_main_delete(&data); + controller_init_main(&data, &program); fll_program_standard_set_down(&data.program); diff --git a/sources/c/main/common.c b/sources/c/main/common.c index 89ba734..8d81a11 100644 --- a/sources/c/main/common.c +++ b/sources/c/main/common.c @@ -5,9 +5,9 @@ extern "C" { #endif #ifndef _di_controller_main_setting_load_ - void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_process_t * const process) { + void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_program_t * const program) { - if (!main || !process) return; + if (!main || !program) return; main->setting.state.step_small = controller_allocation_console_d; @@ -91,11 +91,11 @@ extern "C" { f_string_static_t * const args = main->program.parameters.arguments.array; f_number_unsigned_t index = 0; - process->control.server.domain = f_socket_protocol_family_local_e; - process->control.server.type = f_socket_type_stream_e; - process->control.server.form = f_socket_address_form_local_e; + program->control.server.domain = f_socket_protocol_family_local_e; + program->control.server.type = f_socket_type_stream_e; + program->control.server.form = f_socket_address_form_local_e; - memset(&process->control.server.address, 0, sizeof(f_socket_address_t)); + memset(&program->control.server.address, 0, sizeof(f_socket_address_t)); { const uint8_t codes[] = { @@ -129,7 +129,7 @@ extern "C" { } // The first remaining argument represents the entry name. - main->setting.state.status = f_string_dynamic_append(main->program.parameters.remaining.used ? args[main->program.parameters.remaining.array[0]] : controller_default_s, &process->name_entry); + main->setting.state.status = f_string_dynamic_append(main->program.parameters.remaining.used ? args[main->program.parameters.remaining.array[0]] : controller_default_s, &program->name_entry); if (F_status_is_error(main->setting.state.status)) { if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) { @@ -141,7 +141,7 @@ extern "C" { return; } - main->setting.state.status = f_path_current(F_false, &process->path_current); + main->setting.state.status = f_path_current(F_false, &program->path_current); if (F_status_is_error(main->setting.state.status)) { if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) { @@ -153,15 +153,15 @@ extern "C" { return; } - process->path_setting.used = 0; + program->path_setting.used = 0; if (main->program.parameters.array[controller_parameter_settings_e].locations.used) { 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, process->path_current, args[index], &process->path_setting); + controller_path_canonical_relative(main, program->path_current, args[index], &program->path_setting); } else { - main->setting.state.status = f_string_dynamic_append(controller_default_path_settings_s, &process->path_setting); + 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)) { @@ -179,23 +179,23 @@ extern "C" { return; } - if (!process->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) { - main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_s, &process->path_pid); + if (!program->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) { + main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_s, &program->path_pid); if (F_status_is_error_not(main->setting.state.status)) { - main->setting.state.status = f_string_dynamic_append(f_path_separator_s, &process->path_pid); + main->setting.state.status = f_string_dynamic_append(f_path_separator_s, &program->path_pid); } if (F_status_is_error_not(main->setting.state.status)) { - main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_prefix_s, &process->path_pid); + main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_prefix_s, &program->path_pid); } if (F_status_is_error_not(main->setting.state.status)) { - main->setting.state.status = f_string_dynamic_append(process->name_entry, &process->path_pid); + main->setting.state.status = f_string_dynamic_append(program->name_entry, &program->path_pid); } if (F_status_is_error_not(main->setting.state.status)) { - main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_suffix_s, &process->path_pid); + main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_suffix_s, &program->path_pid); } if (F_status_is_error(main->setting.state.status)) { @@ -213,7 +213,7 @@ extern "C" { index = main->program.parameters.array[controller_parameter_cgroup_e].values.array[main->program.parameters.array[controller_parameter_cgroup_e].values.used - 1]; if (args[index].used) { - controller_path_canonical_relative(main, process->path_current, args[index], &process->path_cgroup); + controller_path_canonical_relative(main, program->path_current, args[index], &program->path_cgroup); if (F_status_is_error(main->setting.state.status)) { if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) { @@ -225,7 +225,7 @@ extern "C" { return; } - main->setting.state.status = f_string_append_assure(F_path_separator_s, 1, &process->path_cgroup); + main->setting.state.status = f_string_append_assure(F_path_separator_s, 1, &program->path_cgroup); if (F_status_is_error(main->setting.state.status)) { if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) { diff --git a/sources/c/main/common.h b/sources/c/main/common.h index e320498..62f5c17 100644 --- a/sources/c/main/common.h +++ b/sources/c/main/common.h @@ -17,14 +17,14 @@ extern "C" { #endif /** - * Perform the standard program setting load process. + * Perform the standard program setting load settings. * * This prints error messages as appropriate. * * If either main or setting is NULL, then this immediately returns without doing anything. * * @param arguments - * The parameters passed to the process (often referred to as command line arguments). + * The parameters passed to the program (often referred to as command line arguments). * @param main * The program and settings data. * @@ -35,8 +35,8 @@ extern "C" { * * Errors (with error bit) from: f_console_parameter_process(). * Errors (with error bit) from: fll_program_parameter_process_context(). - * @param process - * A pointer to the current process settings. + * @param program + * A pointer to the current program settings. * * Must not be NULL. * @@ -44,7 +44,7 @@ extern "C" { * @see fll_program_parameter_process_context() */ #ifndef _di_controller_main_setting_load_ - extern void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_process_t * const process); + extern void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_program_t * const program); #endif // _di_controller_main_setting_load_ #ifdef __cplusplus diff --git a/sources/c/main/common/enumeration/instance.h b/sources/c/main/common/enumeration/instance.h new file mode 100644 index 0000000..a54d954 --- /dev/null +++ b/sources/c/main/common/enumeration/instance.h @@ -0,0 +1,77 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common instance enumerations. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_common_enumeration_instance_h +#define _controller_main_common_enumeration_instance_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Instance options. + * + * controller_instance_option_*_e: + * - asynchronous: The Instance runs asynchronously. + * - require: The Instance is required. + * - simulate: The Instance is being simulated. + * - validate: The Instance is being validated. + * - wait: The Instance is blocking (waiting) for all asynchronous Instances before it to complete before running. + */ +#ifndef _di_controller_instance_option_e_ + enum { + controller_instance_option_asynchronous_e = 0x1, + controller_instance_option_require_e = 0x2, + controller_instance_option_simulate_e = 0x4, + controller_instance_option_validate_e = 0x8, + controller_instance_option_wait_e = 0x10, + }; // enum +#endif // _di_controller_instance_option_e_ + +/** + * Instance states. + * + * controller_instance_state_*_e: + * - idle: No instance is running for this rule. + * - busy: A instance is actively using this, and is running synchronously. + * - active: A instance is actively using this, and is running asynchronously. + * - done: A instance has finished running on this and there is a thread that needs to be cleaned up. + */ +#ifndef _di_controller_instance_state_e_ + enum { + controller_instance_state_idle_e = 1, + controller_instance_state_busy_e, + controller_instance_state_active_e, + controller_instance_state_done_e, + }; // enum +#endif // _di_controller_instance_state_e_ + +/** + * Instance types. + * + * controller_instance_type_*_e: + * - entry: The instance is started from an entry. + * - exit: The instance is started from an exit. + * - control: The instance is started from a control operation. + */ +#ifndef _di_controller_instance_type_e_ + enum { + controller_instance_type_entry_e = 1, + controller_instance_type_exit_e, + controller_instance_type_control_e, + }; // enum +#endif // _di_controller_instance_type_e_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_common_enumeration_instance_h diff --git a/sources/c/main/common/enumeration/process.h b/sources/c/main/common/enumeration/program.h similarity index 58% rename from sources/c/main/common/enumeration/process.h rename to sources/c/main/common/enumeration/program.h index 7f1f98f..1059980 100644 --- a/sources/c/main/common/enumeration/process.h +++ b/sources/c/main/common/enumeration/program.h @@ -5,53 +5,53 @@ * API Version: 0.7 * Licenses: lgpl-2.1-or-later * - * Provides the common process enumerations. + * Provides the common program enumerations. * * This is auto-included and should not need to be explicitly included. */ -#ifndef _controller_main_common_enumeration_process_h -#define _controller_main_common_enumeration_process_h +#ifndef _controller_main_common_enumeration_program_h +#define _controller_main_common_enumeration_program_h #ifdef __cplusplus extern "C" { #endif /** - * Controller process flags. + * Controller program flags. * * controller_setting_flag_*_e: * - interruptible: When specified, program responds to interrupt signals, otherwise block/ignore interrupt signals. * - pid_created: When specified, the program responds to interrupt signals, otherwise block/ignore interrupt signals. * - failsafe: When specified, failsafe mode is enabled, otherwise failsafe mode is disabled. */ -#ifndef _di_controller_process_flag_e_ +#ifndef _di_controller_program_flag_e_ enum { - controller_process_flag_interruptible_e = 0x1, - controller_process_flag_pid_created_e = 0x2, - controller_process_flag_failsafe_e = 0x4, + controller_program_flag_interruptible_e = 0x1, + controller_program_flag_pid_created_e = 0x2, + controller_program_flag_failsafe_e = 0x4, }; // enum -#endif // _di_controller_process_flag_e_ +#endif // _di_controller_program_flag_e_ /** - * Controller process mode enumeration. + * Controller program mode enumeration. * * controller_setting_mode_*: * - helper: Run as a helper, exiting when finished prrocess entry (and any respective exit). * - program: Run as a program, exiting when finished prrocess entry (and any respective exit). * - service: Run as a service, listening for requests after processing entry. */ -#ifndef _di_controller_process_mode_e_ +#ifndef _di_controller_program_mode_e_ enum { - controller_process_mode_service_e = 0, - controller_process_mode_helper_e, - controller_process_mode_program_e, + controller_program_mode_service_e = 0, + controller_program_mode_helper_e, + controller_program_mode_program_e, }; // enum -#endif // _di_controller_process_mode_e_ +#endif // _di_controller_program_mode_e_ /** * Controller Process ready enumeration. * - * controller_process_ready_*_e: + * controller_program_ready_*_e: * - no: Entry/Exit is not ready. * - wait: Entry/Exit has "ready" somewhere in the file but is not yet ready. * - yes: Entry/Exit is now ready (Entry/Exit is still being processed). @@ -59,19 +59,19 @@ extern "C" { * - fail: Entry/Exit processing failed. * - abort: Abort received before finished processing Entry/Exit. */ -#ifndef _di_controller_process_ready_e_ +#ifndef _di_controller_program_ready_e_ enum { - controller_process_ready_no_e = 0, - controller_process_ready_wait_e, - controller_process_ready_yes_e, - controller_process_ready_done_e, - controller_process_ready_fail_e, - controller_process_ready_abort_e, + controller_program_ready_no_e = 0, + controller_program_ready_wait_e, + controller_program_ready_yes_e, + controller_program_ready_done_e, + controller_program_ready_fail_e, + controller_program_ready_abort_e, }; // enum -#endif // _di_controller_process_ready_e_ +#endif // _di_controller_program_ready_e_ #ifdef __cplusplus } // extern "C" #endif -#endif // _controller_main_common_enumeration_process_h +#endif // _controller_main_common_enumeration_program_h diff --git a/sources/c/main/common/type/control.c b/sources/c/main/common/type/control.c index aac9a39..6e289c9 100644 --- a/sources/c/main/common/type/control.c +++ b/sources/c/main/common/type/control.c @@ -5,17 +5,15 @@ extern "C" { #endif #ifndef _di_controller_control_delete_ - f_status_t controller_control_delete(controller_control_t * const control) { + void controller_control_delete(controller_control_t * const control) { - if (!control) return F_status_set_error(F_parameter); + if (!control) return; f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->cache_1.string, &control->cache_1.used, &control->cache_1.size); f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->cache_2.string, &control->cache_2.used, &control->cache_2.size); f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->cache_3.string, &control->cache_3.used, &control->cache_3.size); f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->input.string, &control->input.used, &control->input.size); f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->output.string, &control->output.used, &control->output.size); - - return F_okay; } #endif // _di_controller_control_delete_ diff --git a/sources/c/main/common/type/control.h b/sources/c/main/common/type/control.h index 17fbf40..23d1f58 100644 --- a/sources/c/main/common/type/control.h +++ b/sources/c/main/common/type/control.h @@ -72,14 +72,9 @@ extern "C" { * * @param control * The controller control data. - * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. */ #ifndef _di_controller_control_delete_ - extern f_status_t controller_control_delete(controller_control_t * const control); + extern void controller_control_delete(controller_control_t * const control); #endif // _di_controller_control_delete_ #ifdef __cplusplus diff --git a/sources/c/main/common/type/entry.c b/sources/c/main/common/type/entry.c index af4b6a3..dc253ae 100644 --- a/sources/c/main/common/type/entry.c +++ b/sources/c/main/common/type/entry.c @@ -5,20 +5,18 @@ extern "C" { #endif #ifndef _di_controller_entry_action_delete_ - f_status_t controller_entry_action_delete(controller_entry_action_t * const action) { + void controller_entry_action_delete(controller_entry_action_t * const action) { - if (!action) return F_status_set_error(F_parameter); + if (!action) return; f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &action->parameters.array, &action->parameters.used, &action->parameters.size, &f_string_dynamics_delete_callback); - - return F_okay; } #endif // _di_controller_entry_action_delete_ #ifndef _di_controller_entry_actions_delete_ - f_status_t controller_entry_actions_delete(controller_entry_actions_t * const actions) { + void controller_entry_actions_delete(controller_entry_actions_t * const actions) { - if (!actions) return F_status_set_error(F_parameter); + if (!actions) return; actions->used = actions->size; @@ -27,28 +25,24 @@ extern "C" { } // while f_memory_array_resize(0, sizeof(controller_entry_action_t), (void **) &actions->array, &actions->used, &actions->size); - - return F_okay; } #endif // _di_controller_entry_actions_delete_ #ifndef _di_controller_entry_item_delete_ - f_status_t controller_entry_item_delete(controller_entry_item_t * const item) { + void controller_entry_item_delete(controller_entry_item_t * const item) { - if (!item) return F_status_set_error(F_parameter); + if (!item) return; f_memory_array_resize(0, sizeof(f_char_t), (void **) &item->name.string, &item->name.used, &item->name.size); controller_entry_actions_delete(&item->actions); - - return F_okay; } #endif // _di_controller_entry_item_delete_ #ifndef _di_controller_entry_items_delete_ - f_status_t controller_entry_items_delete(controller_entry_items_t * const items) { + void controller_entry_items_delete(controller_entry_items_t * const items) { - if (!items) return F_status_set_error(F_parameter); + if (!items) return; items->used = items->size; @@ -57,8 +51,6 @@ extern "C" { } // while f_memory_array_resize(0, sizeof(controller_entry_item_t), (void **) &items->array, &items->used, &items->size); - - return F_okay; } #endif // _di_controller_entry_items_delete_ diff --git a/sources/c/main/common/type/entry.h b/sources/c/main/common/type/entry.h index e4874da..46c2ab1 100644 --- a/sources/c/main/common/type/entry.h +++ b/sources/c/main/common/type/entry.h @@ -185,15 +185,10 @@ extern "C" { * @param actions * The Controller Entry Action. * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * * @see f_memory_arrays_resize() */ #ifndef _di_controller_entry_action_delete_ - extern f_status_t controller_entry_action_delete(controller_entry_action_t * const action); + extern void controller_entry_action_delete(controller_entry_action_t * const action); #endif // _di_controller_entry_action_delete_ /** @@ -202,17 +197,12 @@ extern "C" { * @param actions * The Controller Entry Actions. * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * * @see controller_entry_action_delete() * * @see f_memory_array_resize() */ #ifndef _di_controller_entry_actions_delete_ - extern f_status_t controller_entry_actions_delete(controller_entry_actions_t * const actions); + extern void controller_entry_actions_delete(controller_entry_actions_t * const actions); #endif // _di_controller_entry_actions_delete_ /** @@ -221,15 +211,10 @@ extern "C" { * @param item * The Controller Entry Item. * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * * @see f_memory_array_resize() */ #ifndef _di_controller_entry_item_delete_ - extern f_status_t controller_entry_item_delete(controller_entry_item_t * const item); + extern void controller_entry_item_delete(controller_entry_item_t * const item); #endif // _di_controller_entry_item_delete_ /** @@ -238,16 +223,11 @@ extern "C" { * @param items * The Controller Entry Items. * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. - * * @see controller_entry_item_delete() * @see f_memory_delete() */ #ifndef _di_controller_entry_items_delete_ - extern f_status_t controller_entry_items_delete(controller_entry_items_t * const items); + extern void controller_entry_items_delete(controller_entry_items_t * const items); #endif // _di_controller_entry_items_delete_ #ifdef __cplusplus diff --git a/sources/c/main/common/type/global.c b/sources/c/main/common/type/global.c new file mode 100644 index 0000000..1362473 --- /dev/null +++ b/sources/c/main/common/type/global.c @@ -0,0 +1,9 @@ +#include "../../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/type/global.h b/sources/c/main/common/type/global.h new file mode 100644 index 0000000..ad98ec2 --- /dev/null +++ b/sources/c/main/common/type/global.h @@ -0,0 +1,70 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common global type structures. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_common_type_global_h +#define _controller_main_common_type_global_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * 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. + */ +#ifndef _di_controller_global_t_ + typedef struct { + controller_main_t *main; + controller_program_t *program; + controller_thread_t *thread; + } controller_global_t; + + #define controller_global_t_initialize { 0, 0, 0 } + + #define macro_controller_global_t_initialize(main, program, thread) { \ + main, \ + program, \ + thread, \ + } +#endif // _di_controller_global_t_ + +/** + * A structure for passing data to the interrupt state function. + * + * is_normal: Boolean designating if this is operating in a normal state. + * thread: The thread data. + */ +#ifndef _di_controller_interrupt_t_ + typedef struct { + bool is_normal; + + controller_thread_t *thread; + } controller_interrupt_t; + + #define controller_interrupt_t_initialize { \ + F_true, \ + 0, \ + } + + #define macro_controller_interrupt_t_initialize_1(is_normal, thread) { \ + is_normal, \ + thread, \ + } +#endif // _di_controller_interrupt_t_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_common_type_global_h diff --git a/sources/c/main/common/type/instance.c b/sources/c/main/common/type/instance.c new file mode 100644 index 0000000..1a837a3 --- /dev/null +++ b/sources/c/main/common/type/instance.c @@ -0,0 +1,33 @@ +#include "../../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_instance_delete_ + void controller_instance_delete(controller_instance_t * const instance) { + + if (!instance) return; + + controller_cache_delete(&instance->cache); + } +#endif // _di_controller_instance_delete_ + +#ifndef _di_f_instances_delete_callback_ + f_status_t f_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const void_array) { + + { + controller_instance_t * const instances = (controller_instance_t *) void_array; + + for (f_number_unsigned_t i = start; i < stop; ++i) { + controller_instance_delete(&instances[i]); + } // for + } + + return F_okay; + } +#endif // _di_f_instances_delete_callback_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/type/instance.h b/sources/c/main/common/type/instance.h new file mode 100644 index 0000000..858dc8a --- /dev/null +++ b/sources/c/main/common/type/instance.h @@ -0,0 +1,171 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common instance type structures. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_common_type_instance_h +#define _controller_main_common_type_instance_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Controller Instance. + * + * A Controller Instance represents the processing of a single Rule for some given Rule ID. + * + * The "cache" should only be used by the function processing/executing the process and as such should not require a write lock normally needed for thread-safety. + * There must only be a single thread running any given Instance at a time, guaranteeing that the cache does not need read/write locks. + * + * 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". + * + * action: The action being performed. + * options: Configuration options for this thread. + * state: The state of the process. + * type: The currently active process type (from the controller_data_type_*_e). + * result: The last return code from an execution of a process. + * + * active: A read/write lock representing that something is currently using this (read locks = in use, write lock = begin deleting). + * lock: A read/write lock on the structure. + * wait: A thread condition to tell a process waiting process that the rule has is done being processed. + * wait_lock: A mutex lock for working with "wait". + * + * child: The process id of a child process, if one is running (when forking to execute a child process). + * 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). + */ +#ifndef _di_controller_instance_t_ + typedef struct { + f_number_unsigned_t id; + f_thread_id_t id_thread; + + uint8_t action; + uint8_t options; + uint8_t state; + uint8_t type; + int result; + + f_thread_lock_t active; + f_thread_lock_t lock; + f_thread_condition_t wait; + f_thread_mutex_t wait_lock; + + f_pids_t childs; + f_string_dynamics_t path_pids; + f_number_unsigneds_t stack; + + controller_rule_t rule; + controller_cache_t cache; + + void *main; + controller_program_t *program; + void *thread; + } controller_instance_t; + + #define controller_instance_t_initialize { \ + 0, \ + f_thread_id_t_initialize, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + f_thread_lock_t_initialize, \ + f_thread_lock_t_initialize, \ + f_thread_condition_t_initialize, \ + f_thread_mutex_t_initialize, \ + f_pids_t_initialize, \ + f_string_dynamics_t_initialize, \ + f_number_unsigneds_t_initialize, \ + controller_rule_t_initialize, \ + controller_cache_t_initialize, \ + 0, \ + 0, \ + 0, \ + } +#endif // _di_controller_instance_t_ + +/** + * An array of Controller Instances. + * + * This has a circular dependency with controller_thread_t. + * + * array: An array of Instances. + * size: Total amount of allocated space. + * used: Total number of allocated spaces used. + */ +#ifndef _di_controller_instances_t_ + typedef struct { + controller_instance_t **array; + + f_number_unsigned_t size; + f_number_unsigned_t used; + } controller_instances_t; + + #define controller_instances_t_initialize { \ + 0, \ + 0, \ + 0, \ + } +#endif // _di_controller_instances_t_ + +/** + * Delete the Controller Instance. + * + * @param instance + * The Controller Instance. + * + * Must not be NULL. + * + * @see controller_cache_delete() + */ +#ifndef _di_controller_instance_delete_ + extern void controller_instance_delete(controller_instance_t * const instance); +#endif // _di_controller_instance_delete_ + +/** + * A callback intended to be passed to f_memory_arrays_resize() for an f_instances_t structure. + * + * This is only called when shrinking the array and generally should perform de-allocations. + * + * This does not do parameter checking. + * + * @param start + * The inclusive start position in the array to start deleting. + * @param stop + * The exclusive stop position in the array to stop deleting. + * @param array + * The array structure to delete all values of. + * Must not be NULL. + * + * @return + * F_okay on success. + * + * F_parameter (with error bit) if a parameter is invalid. + * + * @see controller_instance_delete() + */ +#ifndef _di_f_instances_delete_callback_ + extern f_status_t f_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const array); +#endif // _di_f_instances_delete_callback_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_common_type_process_h diff --git a/sources/c/main/common/type/lock.c b/sources/c/main/common/type/lock.c index 563cf6e..40a868c 100644 --- a/sources/c/main/common/type/lock.c +++ b/sources/c/main/common/type/lock.c @@ -4,53 +4,26 @@ extern "C" { #endif -#ifndef _di_controller_lock_delete_mutex_ - void controller_lock_delete_mutex(f_thread_mutex_t *mutex) { - - const f_status_t status = f_thread_mutex_delete(mutex); - - if (F_status_is_error(status)) { - if (F_status_set_fine(status) == F_busy) { - if (f_thread_mutex_delete(mutex) == F_okay) { - mutex = 0; - } - } - } - else { - mutex = 0; - } - } -#endif // _di_controller_lock_delete_mutex_ - -#ifndef _di_controller_lock_delete_rw_ - void controller_lock_delete_rw(f_thread_lock_t *lock) { - - const f_status_t status = f_thread_lock_delete(lock); - - if (F_status_is_error(status)) { - if (F_status_set_fine(status) == F_busy) { - if (f_thread_lock_delete(lock) == F_okay) { - lock = 0; - } - } - } - else { - lock = 0; - } - } -#endif // _di_controller_lock_delete_rw_ - #ifndef _di_controller_lock_delete_ void controller_lock_delete(controller_lock_t * const lock) { - controller_lock_delete_mutex(&lock->alert); - controller_lock_delete_mutex(&lock->cancel); - controller_lock_delete_mutex(&lock->print); + f_thread_mutex_delete(&lock->alert); + f_thread_mutex_delete(&lock->cancel); + f_thread_mutex_delete(&lock->print); - controller_lock_delete_rw(&lock->process); - controller_lock_delete_rw(&lock->rule); + f_thread_lock_delete(&lock->process); + f_thread_lock_delete(&lock->rule); f_thread_condition_delete(&lock->alert_condition); + + memset(&lock->alert, 0, sizeof(f_thread_mutex_t)); + memset(&lock->cancel, 0, sizeof(f_thread_mutex_t)); + memset(&lock->print, 0, sizeof(f_thread_mutex_t)); + + memset(&lock->process, 0, sizeof(f_thread_lock_t)); + memset(&lock->rule, 0, sizeof(f_thread_lock_t)); + + memset(&lock->alert_condition, 0, sizeof(f_thread_condition_t)); } #endif // _di_controller_lock_delete_ diff --git a/sources/c/main/common/type/lock.h b/sources/c/main/common/type/lock.h index 9bd5a90..6e1b291 100644 --- a/sources/c/main/common/type/lock.h +++ b/sources/c/main/common/type/lock.h @@ -54,36 +54,6 @@ extern "C" { #endif // _di_controller_lock_t_ /** - * Delete the mutex lock and if the mutex lock is busy, forcibly unlock it and then delete it. - * - * @param mutex - * The mutex lock to delete. - * Will be set to NULL if delete succeeded. - * - * This pointer cannot be "* const" because of pthread_mutex_destroy(). - * - * @see f_thread_mutex_delete() - */ -#ifndef _di_controller_lock_delete_mutex_ - extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex); -#endif // _di_controller_lock_delete_mutex_ - -/** - * Delete the r/w lock and if the r/w lock is busy, forcibly unlock it and then delete it. - * - * @param lock - * The r/w lock to delete. - * Will be set to NULL if delete succeeded. - * - * This pointer cannot be "* const" because of pthread_rwlock_destroy(). - * - * @see f_thread_lock_delete() - */ -#ifndef _di_controller_lock_delete_rw_ - extern void controller_lock_delete_rw(f_thread_lock_t *lock); -#endif // _di_controller_lock_delete_rw_ - -/** * Fully deallocate all memory for the given lock without caring about return status. * * @param lock diff --git a/sources/c/main/common/type/process.c b/sources/c/main/common/type/process.c deleted file mode 100644 index f2b4b00..0000000 --- a/sources/c/main/common/type/process.c +++ /dev/null @@ -1,36 +0,0 @@ -#include "../../controller.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _di_controller_process_delete_ - f_status_t controller_process_delete(controller_process_t * const process) { - - if (!process) return F_status_set_error(F_parameter); - - f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->name_entry.string, &process->name_entry.used, &process->name_entry.size); - f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_cgroup.string, &process->path_cgroup.used, &process->path_cgroup.size); - f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_control.string, &process->path_control.used, &process->path_control.size); - f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_current.string, &process->path_current.used, &process->path_current.size); - f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_pid.string, &process->path_pid.used, &process->path_pid.size); - f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_setting.string, &process->path_setting.used, &process->path_setting.size); - - f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->entry.define.array, &process->entry.define.used, &process->entry.define.size, &f_string_maps_delete_callback); - f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->entry.parameter.array, &process->entry.parameter.used, &process->entry.parameter.size, &f_string_maps_delete_callback); - f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->exit.define.array, &process->exit.define.used, &process->exit.define.size, &f_string_maps_delete_callback); - f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->exit.parameter.array, &process->exit.parameter.used, &process->exit.parameter.size, &f_string_maps_delete_callback); - - controller_control_delete(&process->control); - controller_entry_items_delete(&process->entry.items); - controller_entry_items_delete(&process->exit.items); - - controller_rules_delete(&process->rules); - - return F_okay; - } -#endif // _di_controller_process_delete_ - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/sources/c/main/common/type/program.c b/sources/c/main/common/type/program.c new file mode 100644 index 0000000..6a21a67 --- /dev/null +++ b/sources/c/main/common/type/program.c @@ -0,0 +1,33 @@ +#include "../../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_program_delete_ + void controller_program_delete(controller_program_t * const program) { + + if (!program) return; + + f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->name_entry.string, &program->name_entry.used, &program->name_entry.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_cgroup.string, &program->path_cgroup.used, &program->path_cgroup.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_control.string, &program->path_control.used, &program->path_control.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_current.string, &program->path_current.used, &program->path_current.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_pid.string, &program->path_pid.used, &program->path_pid.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_setting.string, &program->path_setting.used, &program->path_setting.size); + + f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->entry.define.array, &program->entry.define.used, &program->entry.define.size, &f_string_maps_delete_callback); + f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->entry.parameter.array, &program->entry.parameter.used, &program->entry.parameter.size, &f_string_maps_delete_callback); + f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->exit.define.array, &program->exit.define.used, &program->exit.define.size, &f_string_maps_delete_callback); + f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->exit.parameter.array, &program->exit.parameter.used, &program->exit.parameter.size, &f_string_maps_delete_callback); + + controller_control_delete(&program->control); + controller_entry_items_delete(&program->entry.items); + controller_entry_items_delete(&program->exit.items); + controller_rules_delete(&program->rules); + } +#endif // _di_controller_program_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/type/process.h b/sources/c/main/common/type/program.h similarity index 72% rename from sources/c/main/common/type/process.h rename to sources/c/main/common/type/program.h index b5db1bd..01e888e 100644 --- a/sources/c/main/common/type/process.h +++ b/sources/c/main/common/type/program.h @@ -5,19 +5,19 @@ * API Version: 0.7 * Licenses: lgpl-2.1-or-later * - * Provides the common process type structures. + * Provides the common program type structures. * * This is auto-included and should not need to be explicitly included. */ -#ifndef _controller_main_common_type_process_h -#define _controller_main_common_type_process_h +#ifndef _controller_main_common_type_program_h +#define _controller_main_common_type_program_h #ifdef __cplusplus extern "C" { #endif /** - * Controller process data. + * Controller program process data. * * ready: State representing if the settings are all loaded and is ready to run program operations. * mode: Controller setting mode based on the setting mode enumerator. @@ -36,7 +36,7 @@ extern "C" { * exit: The Exit settings. * rules: All rules and their respective settings. */ -#ifndef _di_controller_process_t_ +#ifndef _di_controller_program_t_ typedef struct { uint8_t ready; uint8_t mode; @@ -54,9 +54,9 @@ extern "C" { controller_entry_t entry; controller_entry_t exit; controller_rules_t rules; - } controller_process_t; + } controller_program_t; - #define controller_process_t_initialize { \ + #define controller_program_t_initialize { \ 0, \ 0, \ 0, \ @@ -71,27 +71,22 @@ extern "C" { controller_entry_t_initialize, \ controller_rules_t_initialize, \ } -#endif // _di_controller_process_t_ +#endif // _di_controller_program_t_ /** - * Delete the Controller process data. + * Delete the Controller program data. * - * @param process - * A pointer to the current process settings. + * @param program + * A pointer to the current program settings. * * Must not be NULL. - * - * @return - * F_okay on success. - * - * F_parameter (with error bit) if a parameter is invalid. */ -#ifndef _di_controller_process_delete_ - extern f_status_t controller_process_delete(controller_process_t * const process); -#endif // _di_controller_process_delete_ +#ifndef _di_controller_program_delete_ + extern void controller_program_delete(controller_program_t * const program); +#endif // _di_controller_program_delete_ #ifdef __cplusplus } // extern "C" #endif -#endif // _controller_main_common_type_process_h +#endif // _controller_main_common_type_program_h diff --git a/sources/c/main/common/type/rule.h b/sources/c/main/common/type/rule.h index f05607a..f4ae5a1 100644 --- a/sources/c/main/common/type/rule.h +++ b/sources/c/main/common/type/rule.h @@ -274,7 +274,7 @@ extern "C" { uid_t user; gid_t group; - f_time_spec_t timestamp; + f_time_simple_t timestamp; f_string_dynamic_t alias; f_string_dynamic_t engine; @@ -323,7 +323,7 @@ extern "C" { 0, \ 0, \ 0, \ - f_time_spec_t_initialize, \ + f_time_simple_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ diff --git a/sources/c/main/common/type/thread.c b/sources/c/main/common/type/thread.c index 8a97919..1f497d2 100644 --- a/sources/c/main/common/type/thread.c +++ b/sources/c/main/common/type/thread.c @@ -10,8 +10,9 @@ extern "C" { if (!thread) return; controller_lock_delete(&thread->lock); - controller_process_delete(&thread->process); controller_cache_delete(&thread->cache); + + f_memory_arrays_resize(0, sizeof(controller_instance_t), (void **) &thread->instances.array, &thread->instances.used, &thread->instances.size, &f_instances_delete_callback); } #endif // _di_controller_thread_delete_ diff --git a/sources/c/main/common/type/thread.h b/sources/c/main/common/type/thread.h index a3ddd4d..2970a3c 100644 --- a/sources/c/main/common/type/thread.h +++ b/sources/c/main/common/type/thread.h @@ -23,7 +23,7 @@ extern "C" { * * The "enabled" and "signal" utilize the lock: lock.process. * - * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE. + * enabled: F_true when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when F_false. * signal: The code of any signal received. * status: A status used by the main entry/rule processing thread for synchronous operations. * @@ -33,12 +33,12 @@ extern "C" { * id_rule: The thread ID representing the Rule Process. * id_signal: The thread ID representing the Signal Process. * - * lock: A r/w lock for operating on this structure. - * process: All Rule Process thread data. - * cache: A cache used by the main entry/rule processing thread for synchronous operations. + * lock: A r/w lock for operating on this structure. + * instances: All Rule Instance thread data. + * cache: A cache used by the main entry/rule processing thread for synchronous operations. */ #ifndef _di_controller_thread_t_ - typedef struct { + typedef struct controller_thread_t_ { uint8_t enabled; int signal; f_status_t status; @@ -50,7 +50,7 @@ extern "C" { f_thread_id_t id_signal; controller_lock_t lock; - controller_process_t process; + controller_instances_t instances; controller_cache_t cache; } controller_thread_t; @@ -64,7 +64,7 @@ extern "C" { f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ controller_lock_t_initialize, \ - controller_processs_t_initialize, \ + controller_instances_t_initialize, \ controller_cache_t_initialize, \ } #endif // _di_controller_thread_t_ diff --git a/sources/c/main/controller.h b/sources/c/main/controller.h index 0d63508..2743bcd 100644 --- a/sources/c/main/controller.h +++ b/sources/c/main/controller.h @@ -74,15 +74,18 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include +#include #include #include +#include #include #include #include @@ -93,6 +96,8 @@ #include #include #include +#include +#include #include #ifdef __cplusplus diff --git a/sources/c/main/print/error.c b/sources/c/main/print/error.c index 0ee495f..5bc6c20 100644 --- a/sources/c/main/print/error.c +++ b/sources/c/main/print/error.c @@ -32,6 +32,18 @@ extern "C" { } #endif // _di_controller_main_print_error_file_ +#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) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + fll_error_print(print, status, function, fll_error_file_flag_fallback_e); + + return F_okay; + } +#endif // _di_controller_main_print_error_status_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/main/print/error.h b/sources/c/main/print/error.h index c29205b..71e8665 100644 --- a/sources/c/main/print/error.h +++ b/sources/c/main/print/error.h @@ -21,7 +21,6 @@ extern "C" { * * @param print * The output structure to print to. - * * Must not be NULL. * * This does not alter print.custom.setting.state.status. @@ -45,7 +44,6 @@ extern "C" { * * @param print * The output structure to print to. - * * Must not be NULL. * * The print.custom is expected to be of type fss_read_main_t. @@ -73,6 +71,31 @@ extern "C" { extern 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); #endif // _di_controller_main_print_error_file_ +/** + * Print generic error message regarding a function failing in some way. + * + * @param print + * The output structure to print to. + * Must not be NULL. + * + * This does not alter print.custom.setting.state.status. + * @param function + * The name of the function associated with the error. + * @param status + * The status code to print an error message about. + * + * @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_status_ + extern f_status_t controller_main_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status); +#endif // _di_controller_main_print_error_status_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/main/thread.c b/sources/c/main/thread.c index 2214fb7..29c20c0 100644 --- a/sources/c/main/thread.c +++ b/sources/c/main/thread.c @@ -4,18 +4,98 @@ extern "C" { #endif -#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_) - void * controller_main_thread_signal(void * const main) { +#ifndef _di_controller_main_thread_signal_ + void controller_main_thread_signal(controller_global_t * const global, const bool is_normal) { - f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + if (!global || !global->main || !global->thread) return; + if (!controller_main_thread_is_enabled(is_normal, global->thread)) return; + if (!(global->main->setting.flag & controller_main_flag_interruptible_e)) return; + + f_status_t status = F_okay; + siginfo_t information; + f_time_spec_t time = f_time_spec_t_initialize; + + 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); + + memset((void *) &information, 0, sizeof(siginfo_t)); + + status = f_signal_wait_until(&global->main->program.signal.set, &time, &information); + if (status == F_time_out) continue; + + 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); + + break; + } + } // while + } +#endif // _di_controller_main_thread_signal_ - if (main) { - controller_main_signal_handler((controller_main_t *) main); +#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) { + + if (!state || !state->custom || !internal) return F_interrupt_not; + + controller_interrupt_t * const custom = (controller_interrupt_t *) state->custom; + controller_thread_t * const thread = custom->thread; + + if (!controller_main_thread_is_enabled(custom->is_normal, thread)) { + return 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); } + 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) { + + if (!state || !state->custom || !internal) return F_interrupt_not; + + controller_interrupt_t * const custom = (controller_interrupt_t *) state->custom; + controller_thread_t * const thread = custom->thread; + + if (!controller_main_thread_is_enabled(custom->is_normal, thread)) { + return 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); + } + + return F_interrupt_not; + } +#endif // _di_controller_main_thread_signal_state_iki_ + +#ifndef _di_controller_main_thread_signal_normal_ + void * controller_main_thread_signal_normal(void * const global) { + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_main_thread_signal((controller_global_t *) global, F_true); + + return 0; + } +#endif // _di_controller_main_thread_signal_normal_ + +#ifndef _di_controller_main_thread_signal_other_ + void * controller_main_thread_signal_other(void * const arguments) { + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_main_thread_signal((controller_global_t *) global, F_false); + return 0; } -#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_) +#endif // _di_controller_main_thread_signal_other_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/main/thread.h b/sources/c/main/thread.h index d6fa55e..3290be0 100644 --- a/sources/c/main/thread.h +++ b/sources/c/main/thread.h @@ -13,33 +13,85 @@ #define _controller_main_thread_h /** - * Thread handler for signals/interrupts. + * Thread for handling signals/interrupts. * - * If main.signal is non-zero, then this 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 program and settings data. + * @param global + * The global data. * * Must not be NULL. + * @param is_normal + * If TRUE, then process as if this operates during a normal operation (entry and control). + * If FALSE, then process as if this operates during a an exit operation. + */ +#ifndef _di_controller_main_thread_signal_ + extern void controller_main_thread_signal(controller_global_t * const global, const bool is_normal); +#endif // _di_controller_main_thread_signal_ + +/** + * Callback passed to FSS functions for checking for interrupts. + * + * @param state + * The state data. + * @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); +#endif // _di_controller_main_thread_signal_state_fss_ + +/** + * Callback passed to IKI functions for checking for interrupts. + * + * @param state + * The state data. + * @param internal + * Not used. + * + * @return + * F_interrupt_not if not interrupted. * - * Must be of type controller_main_t. + * 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); +#endif // _di_controller_main_thread_signal_state_iki_ + +/** + * Thread for handling signals/interrupts during normal operations. + * + * @param arguments + * The thread arguments. + * Must be of type controller_global_t. * * @return * 0, always. * - * @see f_thread_cancel_state_set() + * @see controller_main_thread_signal() + */ +#ifndef _di_controller_main_thread_signal_normal_ + extern void * controller_main_thread_signal_normal(void * const arguments); +#endif // _di_controller_main_thread_signal_normal_ + +/** + * Thread for handling signals/interrupts during other operations. + * + * @param arguments + * The thread arguments. + * Must be of type controller_global_t. + * + * @return + * 0, always. * * @see controller_main_thread_signal() */ -#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_) - extern void * controller_main_thread_signal(void * const main); -#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_) +#ifndef _di_controller_main_thread_signal_other_ + extern void * controller_main_thread_signal_other(void * const arguments); +#endif // _di_controller_main_thread_signal_other_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/main/thread/instance.c b/sources/c/main/thread/instance.c new file mode 100644 index 0000000..3da4a86 --- /dev/null +++ b/sources/c/main/thread/instance.c @@ -0,0 +1,434 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_thread_instance_ + void controller_thread_instance(const uint8_t is_normal, controller_instance_t * const instance) { + + if (!instance) return; + if (!controller_thread_is_enabled(is_normal, instance->main_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); + controller_main_delete(instance->main_data); + + // According to some man pages, pthread_exit() calls exit(0), so expliticly exit to ensure a non-zero code is returned when needed. + if (instance->main_data->program.child) exit(instance->main_data->program.child); + } + } +#endif // _di_controller_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) { + + if (!global) return; + + f_thread_mutex_lock(&global->thread->lock.cancel); + + // Only cancel when enabled. + if (!controller_thread_is_enabled(is_normal, global->thread)) { + f_thread_mutex_unlock(&global->thread->lock.cancel); + + return; + } + + controller_entry_t * const entry = is_normal ? &global->setting->entry : &global->setting->exit; + controller_instance_t *instance = 0; + + f_time_spec_t time = f_time_spec_t_initialize; + f_status_t status = F_okay; + f_number_unsigned_t i = 0; + f_number_unsigned_t j = 0; + pid_t pid = 0; + + // A simple but inaccurate interval counter (expect this to be replaced in the future). + const f_number_unsigned_t interval_nanoseconds = entry->timeout_exit < 1000 ? (entry->timeout_exit < 100 ? 5000000 : 100000000) : 500000000; + const f_number_unsigned_t interval_milliseconds = entry->timeout_exit < 1000 ? (entry->timeout_exit < 100 ? 5 : 100) : 500; + + time.tv_sec = 0; + time.tv_nsec = interval_nanoseconds; + + if (global->setting->mode == controller_setting_mode_helper_e && global->main->program.parameters.array[controller_parameter_validate_e].result == f_console_result_none_e) { + int value = 0; + f_number_unsigned_t lapsed = 0; + + for (i = 0; i < global->thread->instances.used; ++i) { + + if (!global->thread->instances.array[i]) continue; + + instance = global->thread->instances.array[i]; + + if (!instance->id_thread) continue; + + controller_thread_detach(&instance->id_thread); + + instance->id_thread = 0; + } // for + } + + // Use the alert lock to toggle enabled (using it as if it is a write like and a signal lock). + status = f_thread_mutex_lock(&global->thread->lock.alert); + + if (F_status_is_error(status)) { + global->thread->enabled = controller_thread_enabled_not_e; + } + else { + if (by == controller_thread_cancel_execute_e) { + global->thread->enabled = controller_thread_enabled_execute_e; + } + else if (by == controller_thread_cancel_exit_e) { + global->thread->enabled = controller_thread_enabled_not_e; + } + else if (by == controller_thread_cancel_exit_execute_e) { + global->thread->enabled = controller_thread_enabled_exit_execute_e; + } + else { + global->thread->enabled = controller_thread_enabled_exit_e; + } + + f_thread_mutex_unlock(&global->thread->lock.alert); + } + + if (global->thread->id_cleanup) { + f_thread_cancel(global->thread->id_cleanup); + f_thread_join(global->thread->id_cleanup, 0); + + global->thread->id_cleanup = 0; + } + + if (global->thread->id_control) { + f_thread_cancel(global->thread->id_control); + f_thread_join(global->thread->id_control, 0); + + global->thread->id_control = 0; + } + + // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel(). + if (by != controller_thread_cancel_signal_e && global->thread->id_signal) { + f_thread_cancel(global->thread->id_signal); + f_thread_join(global->thread->id_signal, 0); + + global->thread->id_signal = 0; + } + + if (global->setting->mode == controller_setting_mode_helper_e && global->main->program.parameters.array[controller_parameter_validate_e].result == f_console_result_none_e) { + f_thread_mutex_unlock(&global->thread->lock.cancel); + + return; + } + + for (; i < global->thread->instances.used; ++i) { + + if (!global->thread->instances.array[i]) continue; + + instance = global->thread->instances.array[i]; + + // Do not cancel exit instances, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) { + continue; + } + + for (j = 0; j < instance->childs.used; ++j) { + + if (instance->childs.array[j] > 0) { + f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, instance->childs.array[j]); + } + } // for + + for (j = 0; j < instance->path_pids.used; ++j) { + + if (instance->path_pids.array[j].used && f_file_exists(instance->path_pids.array[j], F_true) == F_true) { + status = controller_file_pid_read(instance->path_pids.array[j], &pid); + + if (pid) { + f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, pid); + } + } + } // for + } // for + + if (entry->timeout_exit && !(entry->flag & controller_entry_flag_timeout_exit_no_e)) { + f_number_unsigned_t lapsed = 0; + + for (i = 0; i < global->thread->instances.used && lapsed < entry->timeout_exit; ++i) { + + if (!global->thread->instances.array[i]) continue; + + instance = global->thread->instances.array[i]; + + // Do not wait for instances, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) { + continue; + } + + for (j = 0; j < instance->childs.used && lapsed < entry->timeout_exit; ++j) { + + while (instance->childs.array[j] > 0 && lapsed < entry->timeout_exit) { + + // A hackish way to determine if the child instance exists while waiting. + if (getpgid(instance->childs.array[j]) >= 0) { + time.tv_sec = 0; + time.tv_nsec = interval_nanoseconds; + + f_time_sleep_spec(&time, 0); + + lapsed += interval_milliseconds; + } + else { + instance->childs.array[j] = 0; + + break; + } + } // while + } // for + + for (j = 0; j < instance->path_pids.used && lapsed < entry->timeout_exit; ++j) { + + if (instance->path_pids.array[j].used && f_file_exists(instance->path_pids.array[j], F_true) == F_true) { + status = controller_file_pid_read(instance->path_pids.array[j], &pid); + + if (pid) { + while (lapsed < entry->timeout_exit) { + + // A hackish way to determine if the instance exists while waiting. + if (getpgid(pid) >= 0) { + time.tv_sec = 0; + time.tv_nsec = interval_nanoseconds; + + f_time_sleep_spec(&time, 0); + + lapsed += interval_milliseconds; + } + else { + instance->path_pids.array[j].used = 0; + + break; + } + } // while + } + } + } // for + } // for + } + + for (i = 0; i < global->thread->instances.size; ++i) { + + if (!global->thread->instances.array[i]) continue; + + instance = global->thread->instances.array[i]; + + // Do not kill exit instances, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue; + + if (instance->id_thread) { + if (instance->childs.used) { + for (j = 0; j < instance->childs.used; ++j) { + + if (instance->childs.array[j] > 0) { + f_signal_send(F_signal_kill, instance->childs.array[j]); + + time.tv_sec = 0; + time.tv_nsec = controller_thread_exit_process_cancel_wait_d; + + instance->childs.array[j] = 0; + } + } // for + + f_time_sleep_spec(&time, 0); + } + + f_thread_join(instance->id_thread, 0); + + instance->id_thread = 0; + } + + if (!(entry->flag & controller_entry_flag_timeout_exit_no_e)) { + for (j = 0; j < instance->childs.size; ++j) { + + // Do not kill exit processes, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue; + + if (instance->childs.array[j]) { + + // A hackish way to determine if the child instance exists, and if it does then forcibly terminate it. + if (getpgid(instance->childs.array[j]) >= 0) { + f_signal_send(F_signal_kill, instance->childs.array[j]); + } + + instance->childs.array[j] = 0; + } + } // for + } + + if (!(entry->flag & controller_entry_flag_timeout_exit_no_e)) { + for (j = 0; j < instance->path_pids.used; ++j) { + + // Do not kill exit processes, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue; + + if (f_file_exists(instance->path_pids.array[j], F_true) == F_true) { + status = controller_file_pid_read(instance->path_pids.array[j], &pid); + + if (pid) { + f_signal_send(F_signal_kill, pid); + } + + f_file_remove(instance->path_pids.array[j]); + instance->path_pids.array[j].used = 0; + } + } // for + } + + // Shrink the child pids as much as possible. + while (instance->childs.used) { + + // Do not shrink below an exit instances, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) break; + if (instance->childs.array[j] > 0) break; + + --instance->childs.used; + } // while + + // Shrink the path pids as much as possible. + while (instance->path_pids.used) { + + // Do not shrink below an exit instances, when not performing "execute" during exit. + if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) break; + if (instance->path_pids.array[j].used) break; + + --instance->path_pids.used; + } // while + } // for + + f_thread_mutex_unlock(&global->thread->lock.cancel); + } +#endif // _di_controller_thread_instance_cancel_ + +#ifndef _di_controller_thread_instance_exit_ + void controller_thread_instance_exit(controller_global_t * const global) { + + if (!global) return; + + if (global->thread->enabled != controller_thread_enabled_exit_e) return; + + if (global->setting->ready == controller_setting_ready_done_e) { + + // The exit processing runs using the entry thread. + if (global->thread->id_entry) { + f_thread_cancel(global->thread->id_entry); + f_thread_join(global->thread->id_entry, 0); + + global->thread->id_entry = 0; + } + + // 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); + } + + 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); + + if (F_status_is_error(status)) { + if (global->main->program.error.verbosity > f_console_verbosity_quiet_e) { + controller_main_print_error_status(&global->main->program.error, macro_controller_f(f_thread_create), F_status_set_fine(status)); + } + + 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(&global->thread->lock.alert); + } + else { + global->thread->enabled = controller_thread_enabled_not_e; + } + } + else { + f_time_spec_t time = f_time_spec_t_initialize; + + do { + status = f_thread_mutex_lock(&global->thread->lock.alert); + + if (F_status_is_error(status)) { + global->thread->enabled = controller_thread_enabled_not_e; + + break; + } + + controller_time(controller_thread_exit_ready_timeout_seconds_d, controller_thread_exit_ready_timeout_nanoseconds_d, &time); + + status = f_thread_condition_wait_timed(&time, &global->thread->lock.alert_condition, &global->thread->lock.alert); + + f_thread_mutex_unlock(&global->thread->lock.alert); + + } while (F_status_is_error_not(status) && global->thread->enabled == controller_thread_enabled_exit_e); + + if (F_status_is_error(status)) { + 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(&global->thread->lock.alert); + } + else { + global->thread->enabled = controller_thread_enabled_not_e; + } + } + } + + // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel(). + if (global->thread->id_signal) { + f_thread_cancel(global->thread->id_signal); + f_thread_join(global->thread->id_signal, 0); + + global->thread->id_signal = 0; + } + + controller_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))) { + global->thread->enabled = controller_thread_enabled_not_e; + + f_thread_mutex_unlock(&global->thread->lock.alert); + } + else { + global->thread->enabled = controller_thread_enabled_not_e; + } + } + } +#endif // _di_controller_thread_instance_exit_ + +#ifndef _di_controller_thread_instance_normal_ + void * controller_thread_instance_normal(void * const arguments) { + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_thread_instance(F_true, (controller_instance_t *) arguments); + + return 0; + } +#endif // _di_controller_thread_instance_normal_ + +#ifndef _di_controller_thread_instance_other_ + void * controller_thread_instance_other(void * const arguments) { + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + controller_thread_instance(F_false, (controller_instance_t *) arguments); + + return 0; + } +#endif // _di_controller_thread_instance_other_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/thread/instance.h b/sources/c/main/thread/instance.h new file mode 100644 index 0000000..ee13a82 --- /dev/null +++ b/sources/c/main/thread/instance.h @@ -0,0 +1,103 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the thread "instance" functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_thread_instance_h +#define _controller_main_thread_instance_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Asynchronously execute a Rule process. + * + * @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. + * + * @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_ + +/** + * Cancel all process threads. + * + * @param global + * The global thread data. + * + * This does not alter global.main.setting.state.status. + * @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 by + * Designate the way in which the cancellation should operate. + * + * If controller_thread_cancel_signal_e, then this was called from within the signal handling thread, so do not cancel the signal thread. + * 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_ + +/** + * Process the Exit file, if applicable. + * + * @param global + * The global thread data. + * + * 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_ + +/** + * Asynchronously execute a Rule process during normal operations. + * + * @param arguments + * The thread arguments. + * Must be of type controller_data_t. + * + * @return + * 0, always. + * + * @see controller_thread_instance() + */ +#ifndef _di_controller_thread_instance_normal_ + extern void * controller_thread_instance_normal(void * const arguments); +#endif // _di_controller_thread_instance_normal_ + +/** + * Asynchronously execute a Rule process during other operations. + * + * @param arguments + * The thread arguments. + * Must be of type controller_data_t. + * + * @return + * 0, always. + * + * @see controller_thread_instance() + */ +#ifndef _di_controller_thread_instance_other_ + extern void * controller_thread_instance_other(void * const arguments); +#endif // _di_controller_thread_instance_other_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_thread_instance_h diff --git a/sources/c/main/thread/is.c b/sources/c/main/thread/is.c new file mode 100644 index 0000000..bfa4d09 --- /dev/null +++ b/sources/c/main/thread/is.c @@ -0,0 +1,34 @@ +#include "../controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_main_thread_is_enabled_ + f_status_t controller_main_thread_is_enabled(const uint8_t is_normal, controller_thread_t * const thread) { + + if (!thread) return F_false; + + return is_normal ? thread->enabled == controller_thread_enabled_e : thread->enabled; + } +#endif // _di_controller_main_thread_is_enabled_ + +#ifndef _di_controller_main_thread_is_enabled_process_ + f_status_t controller_main_thread_is_enabled_process(controller_instance_t * const instance, controller_thread_t * const thread) { + + if (!instance) return F_false; + + return controller_main_thread_is_enabled_process_type(instance->type, thread); + } +#endif // _di_controller_main_thread_is_enabled_process_ + +#ifndef _di_controller_main_thread_is_enabled_process_type_ + f_status_t controller_main_thread_is_enabled_process_type(const uint8_t type, controller_thread_t * const thread) { + + return controller_main_thread_is_enabled(type != controller_data_type_exit_e, thread); + } +#endif // _di_controller_main_thread_is_enabled_process_type_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/thread/is.h b/sources/c/main/thread/is.h new file mode 100644 index 0000000..3a07baa --- /dev/null +++ b/sources/c/main/thread/is.h @@ -0,0 +1,58 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the thread "is" functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_thread_is_h +#define _controller_main_thread_is_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Check to see if thread is enabled for the normal operations like entry and control or for exit operations. + * + * @param is_normal + * If TRUE, then process as if this operates during a normal operation (entry and control). + * If FALSE, then process as if this operates during a an exit operation. + * @param thread + * The thread data. + * + * @return + * F_true when enabled. + * F_false when disabled. + */ +#ifndef _di_controller_main_thread_is_enabled_ + extern f_status_t controller_main_thread_is_enabled(const uint8_t is_normal, controller_thread_t * const thread); +#endif // _di_controller_main_thread_is_enabled_ + +/** + * Check to see if thread is enabled for the normal operations like entry and control or for exit operations for some process. + * + * @param instance + * The instance to use when checking if thread is enabled. + * @param thread + * The thread data. + * + * @return + * F_true when enabled. + * F_false when disabled or when parameter is invalid.. + * + * @see controller_main_thread_is_enabled_process_type() + */ +#ifndef _di_controller_main_thread_is_enabled_process_ + extern f_status_t controller_main_thread_is_enabled_process(controller_instance_t * const instance, controller_thread_t * const thread); +#endif // _di_controller_main_thread_is_enabled_process_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_thread_is_h diff --git a/sources/c/main/time.c b/sources/c/main/time.c new file mode 100644 index 0000000..99b7205 --- /dev/null +++ b/sources/c/main/time.c @@ -0,0 +1,79 @@ +#include "controller.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_controller_time_now_ + void controller_time_now(const time_t seconds, const long nanoseconds, f_time_spec_t * const time) { + + { + f_time_value_t now = f_time_value_t_initialize; + + f_time_of_day_get(&now); + + time->tv_sec = now.tv_sec + seconds; + time->tv_nsec = (now.tv_usec * 1000) + nanoseconds; + } + + // If tv_nsec is 1 second or greater, then increment seconds. + if (time->tv_nsec >= 1000000000) { + ++(time->tv_sec); + + time->tv_nsec -= 1000000000; + } + } +#endif // _di_controller_time_now_ + +/* +#ifndef _di_controller_time_milliseconds_ + f_time_spec_t controller_time_milliseconds(const f_number_unsigned_t milliseconds) { + + f_time_spec_t time; + + f_time_spec_millisecond(0, milliseconds, &time); + + return time; + } +#endif // _di_controller_time_milliseconds_ + +#ifndef _di_controller_time_seconds_ + f_time_simple_t controller_time_seconds(const f_number_unsigned_t seconds) { + + f_time_spec_t time; + + f_time_spec_millisecond(seconds, 0, &time); + + return time; + } +#endif // _di_controller_time_seconds_ +*/ + +#ifndef _di_controller_time_sleep_nanoseconds_ + f_status_t controller_time_sleep_nanoseconds(controller_global_t * const global, const f_time_spec_t time) { + + if (!global || !global->setting) return F_status_set_error(F_parameter); + + // When sleep is a second or more, instead wait for terminating signals if interruptible. + if ((global->main->setting.flag & controller_setting_flag_interruptible_e) && time.tv_sec) { + siginfo_t information; + f_signal_t signal = f_signal_t_initialize; + + memset(&information, 0, sizeof(siginfo_t)); + + f_signal_set_empty(&signal.set); + f_signal_set_add(F_signal_abort, &signal.set); + f_signal_set_add(F_signal_interrupt, &signal.set); + f_signal_set_add(F_signal_quit, &signal.set); + f_signal_set_add(F_signal_termination, &signal.set); + + return f_signal_wait_until(&signal.set, &time, &information); + } + + return f_time_sleep_spec(time, remaining); + } +#endif // _di_controller_time_sleep_nanoseconds_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/time.h b/sources/c/main/time.h new file mode 100644 index 0000000..644e9bb --- /dev/null +++ b/sources/c/main/time.h @@ -0,0 +1,59 @@ +/** + * FLL - Level 3 + * + * Project: Controller + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides time functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _controller_main_time_h +#define _controller_main_time_h + +/** + * Get the current time, plus the given offset. + * + * @param seconds + * The seconds to add to current time. + * @param nanoseconds + * The nanoseconds to add to current time. + * @param time + * The resulting current time. + * + * @see f_time_of_day_get() + */ +#ifndef _di_controller_time_now_ + extern void controller_time_now(const time_t seconds, const long nanoseconds, f_time_spec_t * const time); +#endif // _di_controller_time_now_ + +/** + * Sleep for the given time. + * + * @param global + * The global data. + * Must not be NULL. + * + * This does not alter global.main.setting.state.status. + * @param time + * The time in nanoseconds to wait. + * + * @return + * Success from: f_signal_wait_until(). + * Success from: f_time_of_day_get(). + * + * Errors (with error bit) from: f_signal_wait_until(). + * Errors (with error bit) from: f_time_of_day_get(). + * + * @see f_time_of_day_get() + */ +#ifndef _di_controller_time_sleep_nanoseconds_ + extern f_status_t controller_time_sleep_nanoseconds(controller_global_t * const global, const f_time_spec_t time); +#endif // _di_controller_time_sleep_nanoseconds_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _controller_main_time_h -- 1.8.3.1