_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).
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
#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) {
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);
}
#ifndef _controller_controller_h
#define _controller_controller_h
-// Include pre-requirements.
-#ifndef _GNU_SOURCE
- #define _GNU_SOURCE
-#endif // _GNU_SOURCE
-
-// Libc includes.
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-// FLL-0 includes.
-#include <fll/level_0/type.h>
-#include <fll/level_0/status.h>
-#include <fll/level_0/memory.h>
-#include <fll/level_0/string.h>
-#include <fll/level_0/utf.h>
-#include <fll/level_0/capability.h>
-#include <fll/level_0/color.h>
-#include <fll/level_0/compare.h>
-#include <fll/level_0/console.h>
-#include <fll/level_0/control_group.h>
-#include <fll/level_0/conversion.h>
-#include <fll/level_0/execute.h>
-#include <fll/level_0/iki.h>
-#include <fll/level_0/limit.h>
-#include <fll/level_0/path.h>
-#include <fll/level_0/pipe.h>
-#include <fll/level_0/print.h>
-#include <fll/level_0/rip.h>
-#include <fll/level_0/signal.h>
-#include <fll/level_0/socket.h>
-
-#ifndef _di_thread_support_
- #include <fll/level_0/thread.h>
-#endif // _di_thread_support_
-
-// FLL-1 includes.
-#include <fll/level_1/conversion.h>
-#include <fll/level_1/path.h>
-#include <fll/level_1/print.h>
-
-// FLL-2 includes.
-#include <fll/level_2/error.h>
-#include <fll/level_2/print.h>
-#include <fll/level_2/program.h>
-
// Controller includes.
-#include <program/controller/main/common/define.h>
-#include <program/controller/main/common/enumeration.h>
-#include <program/controller/main/common/print.h>
-#include <program/controller/main/common/string.h>
-#include <program/controller/main/common/string/general.h>
-#include <program/controller/main/common/string/rule.h>
-#include <program/controller/main/common/define/control.h>
-#include <program/controller/main/common/define/entry.h>
-#include <program/controller/main/common/define/rule.h>
-#include <program/controller/main/common/define/thread.h>
-#include <program/controller/main/common/enumeration/control.h>
-#include <program/controller/main/common/enumeration/entry.h>
-#include <program/controller/main/common/enumeration/rule.h>
-#include <program/controller/main/common/enumeration/process.h>
-#include <program/controller/main/common/enumeration/thread.h>
-#include <program/controller/main/common/type/cache.h>
-#include <program/controller/main/common/type/control.h>
-#include <program/controller/main/common/type/entry.h>
-#include <program/controller/main/common/type/lock.h>
-#include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/process.h>
-#include <program/controller/main/common/type/thread.h>
-#include <program/controller/main/common/type.h>
-#include <program/controller/main/common.h>
-#include <program/controller/main/path.h>
-#include <program/controller/main/print/data.h>
-#include <program/controller/main/print/debug.h>
-#include <program/controller/main/print/error.h>
-#include <program/controller/main/print/lock.h>
-#include <program/controller/main/print/message.h>
-#include <program/controller/main/print/verbose.h>
-#include <program/controller/main/print/warning.h>
-#include <program/controller/main/signal.h>
-#include <program/controller/main/thread.h>
+#include <program/controller/main/controller.h>
#include <program/controller/controller/string.h>
#ifdef __cplusplus
* 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
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;
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);
#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) {
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);
}
#ifndef _controller_init_h
#define _controller_init_h
-// Include pre-requirements.
-#ifndef _GNU_SOURCE
- #define _GNU_SOURCE
-#endif // _GNU_SOURCE
-
-// Libc includes.
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-// FLL-0 includes.
-#include <fll/level_0/type.h>
-#include <fll/level_0/status.h>
-#include <fll/level_0/memory.h>
-#include <fll/level_0/string.h>
-#include <fll/level_0/utf.h>
-#include <fll/level_0/capability.h>
-#include <fll/level_0/color.h>
-#include <fll/level_0/compare.h>
-#include <fll/level_0/console.h>
-#include <fll/level_0/control_group.h>
-#include <fll/level_0/conversion.h>
-#include <fll/level_0/execute.h>
-#include <fll/level_0/iki.h>
-#include <fll/level_0/limit.h>
-#include <fll/level_0/path.h>
-#include <fll/level_0/pipe.h>
-#include <fll/level_0/print.h>
-#include <fll/level_0/rip.h>
-#include <fll/level_0/signal.h>
-#include <fll/level_0/socket.h>
-
-#ifndef _di_thread_support_
- #include <fll/level_0/thread.h>
-#endif // _di_thread_support_
-
-// FLL-1 includes.
-#include <fll/level_1/conversion.h>
-#include <fll/level_1/path.h>
-#include <fll/level_1/print.h>
-
-// FLL-2 includes.
-#include <fll/level_2/error.h>
-#include <fll/level_2/print.h>
-#include <fll/level_2/program.h>
-
// Controller includes.
-#include <program/controller/main/common/define.h>
-#include <program/controller/main/common/enumeration.h>
-#include <program/controller/main/common/print.h>
-#include <program/controller/main/common/string.h>
-#include <program/controller/main/common/string/general.h>
-#include <program/controller/main/common/string/rule.h>
-#include <program/controller/main/common/define/control.h>
-#include <program/controller/main/common/define/entry.h>
-#include <program/controller/main/common/define/rule.h>
-#include <program/controller/main/common/define/thread.h>
-#include <program/controller/main/common/enumeration/control.h>
-#include <program/controller/main/common/enumeration/entry.h>
-#include <program/controller/main/common/enumeration/rule.h>
-#include <program/controller/main/common/enumeration/process.h>
-#include <program/controller/main/common/enumeration/thread.h>
-#include <program/controller/main/common/type/cache.h>
-#include <program/controller/main/common/type/control.h>
-#include <program/controller/main/common/type/entry.h>
-#include <program/controller/main/common/type/lock.h>
-#include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/process.h>
-#include <program/controller/main/common/type/thread.h>
-#include <program/controller/main/common/type.h>
-#include <program/controller/main/common.h>
-#include <program/controller/main/path.h>
-#include <program/controller/main/print/data.h>
-#include <program/controller/main/print/debug.h>
-#include <program/controller/main/print/error.h>
-#include <program/controller/main/print/lock.h>
-#include <program/controller/main/print/message.h>
-#include <program/controller/main/print/verbose.h>
-#include <program/controller/main/print/warning.h>
-#include <program/controller/main/signal.h>
-#include <program/controller/main/thread.h>
+#include <program/controller/main/controller.h>
#include <program/controller/init/string.h>
#ifdef __cplusplus
* 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
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;
}
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);
#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;
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[] = {
}
// 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) {
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) {
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)) {
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)) {
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) {
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) {
#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.
*
*
* 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.
*
* @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
--- /dev/null
+/**
+ * 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
* 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).
* - 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
#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_
*
* @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
#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;
} // 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;
} // 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_
* @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_
/**
* @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_
/**
* @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_
/**
* @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
--- /dev/null
+#include "../../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * 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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
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_
#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
+++ /dev/null
-#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
--- /dev/null
+#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
* 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.
* 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;
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, \
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
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;
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, \
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_
*
* 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.
*
* 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;
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;
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_
#include <program/controller/main/common/enumeration/entry.h>
#include <program/controller/main/common/enumeration/rule.h>
#include <program/controller/main/common/enumeration/process.h>
+#include <program/controller/main/common/enumeration/program.h>
#include <program/controller/main/common/enumeration/thread.h>
#include <program/controller/main/common/type/cache.h>
#include <program/controller/main/common/type/control.h>
#include <program/controller/main/common/type/entry.h>
#include <program/controller/main/common/type/lock.h>
#include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/process.h>
+#include <program/controller/main/common/type/program.h>
+#include <program/controller/main/common/type/instance.h>
#include <program/controller/main/common/type/thread.h>
#include <program/controller/main/common/type.h>
+#include <program/controller/main/common/type/global.h>
#include <program/controller/main/common.h>
#include <program/controller/main/path.h>
#include <program/controller/main/print/data.h>
#include <program/controller/main/print/verbose.h>
#include <program/controller/main/print/warning.h>
#include <program/controller/main/signal.h>
+#include <program/controller/main/thread/is.h>
+#include <program/controller/main/thread/instance.h>
#include <program/controller/main/thread.h>
#ifdef __cplusplus
}
#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
*
* @param print
* The output structure to print to.
- *
* Must not be NULL.
*
* This does not alter print.custom.setting.state.status.
*
* @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.
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
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"
#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"
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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