build_sources_library main/common.c main/common/define.c main/common/enumeration.c main/common/print.c main/common/string.c main/common/type.c
build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.c main/common/type/execute.c main/common/type/global.c main/common/type/lock.c main/common/type/instance.c main/common/type/program.c main/common/type/rule.c main/common/type/thread.c
build_sources_library main/common/string/general.c main/common/string/rule.c
-build_sources_library main/instance.c main/path.c
+build_sources_library main/instance.c main/path.c main/process.c
build_sources_library main/rule.c main/rule/action.c main/rule/execute.c main/rule/expand.c main/rule/instance.c main/rule/is.c main/rule/item.c main/rule/parameter.c main/rule/read.c main/rule/setting.c main/rule/validate.c main/rule/wait.c
build_sources_library main/print/action.c main/print/data.c main/print/debug.c main/print/error.c main/print/lock.c main/print/message.c main/print/rule.c main/print/verbose.c main/print/warning.c
build_sources_library main/print/rule/action.c main/print/rule/item.c main/print/rule/setting.c
build_sources_headers main/common/enumeration/control.h main/common/enumeration/entry.h main/common/enumeration/instance.h main/common/enumeration/program.h main/common/enumeration/rule.h main/common/enumeration/thread.h
build_sources_headers main/common/string/general.h main/common/string/rule.h
build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/entry.h main/common/type/execute.h main/common/type/global.h main/common/type/lock.h main/common/type/instance.h main/common/type/program.h main/common/type/rule.h main/common/type/thread.h
-build_sources_headers main/instance.h main/path.h
+build_sources_headers main/instance.h main/path.h main/process.h
build_sources_headers main/rule.h main/rule/action.h main/rule/execute.h main/rule/expand.h main/rule/instance.h main/rule/is.h main/rule/item.h main/rule/parameter.h main/rule/read.h main/rule/setting.h main/rule/validate.h main/rule/wait.h
build_sources_headers main/print/action.h main/print/data.h main/print/debug.h main/print/error.h main/print/lock.h main/print/message.h main/print/rule.h main/print/verbose.h main/print/warning.h
build_sources_headers main/print/rule/action.h main/print/rule/item.h main/print/rule/setting.h
return;
}
- // @todo controller_main(&data, &program); (also needs to include things like controller_main_thread())
+ controller_main_process(data, program);
if (main->setting.state.status == F_status_set_error(F_child)) return;
if (main->setting.state.status == F_status_set_error(F_interrupt)) {
* A pointer to the current program settings.
*
* Must not be NULL.
+ *
+ * @see controller_main_process()
*/
#ifndef _di_controller_controller_main_
extern void controller_controller_main(controller_main_t * const main, controller_program_t * const program);
controller_main_setting_load(arguments, &data, &program);
}
- controller_controller_main(&data, &program);
+ controller_main_process(&data, &program);
controller_main_delete(&data);
return;
}
- // @todo controller_main(&data, &program);
+ controller_main_process(data, program);
if (main->setting.state.status == F_status_set_error(F_child)) return;
if (main->setting.state.status == F_status_set_error(F_interrupt)) {
/**
* Execute main program.
*
+ * @todo this may or may not be needed. For now controller_main_process() is being written as a complete replacement to this.
+ *
* If main.signal is non-zero, then this blocks and handles the following signals:
* - F_signal_abort
* - F_signal_broken_pipe
* A pointer to the current program settings.
*
* Must not be NULL.
+ *
+ * @see controller_main_process()
*/
#ifndef _di_controller_init_main_
extern void controller_init_main(controller_main_t * const main, controller_program_t * const program);
controller_main_setting_load(arguments, &data, &program);
}
- controller_init_main(&data, &program);
+ controller_main_process(&data, &program);
fll_program_standard_set_down(&data.program);
index = main->program.parameters.array[controller_parameter_settings_e].values.array[main->program.parameters.array[controller_parameter_settings_e].values.used - 1];
controller_path_canonical_relative(main, program->path_current, args[index], &program->path_setting);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ controller_main_print_error_file(&main->program.error, macro_controller_f(controller_path_canonical_relative), args[index], f_file_operation_verify_s, fll_error_file_type_path_e);
+
+ return;
+ }
}
else {
main->setting.state.status = f_string_dynamic_append(controller_default_path_settings_s, &program->path_setting);
- }
- if (F_status_is_error(main->setting.state.status)) {
- if (main->program.parameters.array[controller_parameter_settings_e].locations.used) {
- controller_main_print_error_file(&main->program.error, macro_controller_f(controller_path_canonical_relative), args[index], f_file_operation_verify_s, fll_error_file_type_path_e);
- }
- else {
+ if (F_status_is_error(main->setting.state.status)) {
controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append));
- }
- return;
+ return;
+ }
}
if (!program->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) {
controller_main_print_debug_directory_path_empty(&main->program.warning, f_console_symbol_long_normal_s, controller_long_cgroup_s);
}
}
+ else {
+ main->setting.state.status = f_string_dynamic_append_nulless(f_control_group_path_system_prefix_s, &program->path_cgroup);
+
+ if (F_status_is_error_not(main->setting.state.status)) {
+ main->setting.state.status = f_string_dynamic_append_nulless(f_control_group_path_system_default_s, &program->path_cgroup);
+ }
+
+ if (F_status_is_error(main->setting.state.status)) {
+ controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append_nulless));
+
+ return;
+ }
+
+ main->setting.state.status = f_string_dynamic_append_assure(f_path_separator_s, &program->path_cgroup);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append_assure));
+
+ return;
+ }
+ }
if (main->program.parameters.array[controller_parameter_interruptible_e].result & f_console_result_found_e) {
if (main->program.parameters.array[controller_parameter_uninterruptible_e].result & f_console_result_found_e) {
else if (main->program.parameters.array[controller_parameter_uninterruptible_e].result & f_console_result_found_e) {
main->setting.flag &= ~controller_main_flag_interruptible_e;
}
+
+ if (main->program.parameters.array[f_console_standard_parameter_daemon_e].result & f_console_result_found_e) {
+ main->setting.flag |= controller_main_flag_daemon_e;
+ }
+
+ if (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) {
+ main->setting.flag |= controller_main_flag_validate_e;
+ }
}
#endif // _di_controller_main_setting_load_
* controller_main_flag_*_e:
* - none: No flags set.
* - copyright: Print copyright.
+ * - daemon: Run the process in the background and create a PID file.
* - error: Check if status is "error".
* - fine: Check if status is "fine".
* - help: Print help.
* - interruptible: The process is interruptible.
* - pipe: Use the input pipe.
+ * - validate: Perform validation of rules rather than execution.
* - version: Print version.
* - version_copyright_help: A helper flag representing version, copyright, and help flag bits being set.
* - warning: Check if status is "warning".
enum {
controller_main_flag_none_e = 0x0,
controller_main_flag_copyright_e = 0x1,
- controller_main_flag_error_e = 0x2,
- controller_main_flag_fine_e = 0x4,
- controller_main_flag_help_e = 0x8,
- controller_main_flag_interruptible_e = 0x10,
- controller_main_flag_pipe_e = 0x20,
- controller_main_flag_version_e = 0x40,
- controller_main_flag_version_copyright_help_e = 0x49,
- controller_main_flag_warning_e = 0x80,
+ controller_main_flag_daemon_e = 0x2,
+ controller_main_flag_error_e = 0x4,
+ controller_main_flag_fine_e = 0x8,
+ controller_main_flag_help_e = 0x10,
+ controller_main_flag_interruptible_e = 0x20,
+ controller_main_flag_pipe_e = 0x40,
+ controller_main_flag_validate_e = 0x80,
+ controller_main_flag_version_e = 0x100,
+ controller_main_flag_version_copyright_help_e = 0x111,
+ controller_main_flag_warning_e = 0x200,
}; // enum
#endif // _di_controller_main_flag_e_
"f_rip_dynamic_partial_nulless",
"f_string_append_assure",
"f_string_dynamic_append",
+ "f_string_dynamic_append_assure",
"f_string_dynamic_append_nulless",
"f_string_dynamic_partial_append",
"f_string_dynamic_partial_append_nulless",
controller_f_f_rip_dynamic_partial_nulless_e,
controller_f_f_string_append_assure_e,
controller_f_f_string_dynamic_append_e,
+ controller_f_f_string_dynamic_append_assure_e,
controller_f_f_string_dynamic_append_nulless_e,
controller_f_f_string_dynamic_partial_append_e,
controller_f_f_string_dynamic_partial_append_nulless_e,
/**
* A wrapper used for passing a common set of all data, particularly for sharing between threads.
*
- * main: The main program data.
- * program: The program data.
- * thread: The thread data for a specific thread.
+ * Properties:
+ * - main: The main program data.
+ * - program: The program data.
+ * - thread: The thread data for a specific thread.
*
- * message: A message printer, with custom set to this structure.
- * output: An output printer, with custom set to this structure.
- * error: An error printer, with custom set to this structure.
- * warning: A warning printer, with custom set to this structure.
- * debug: A debug printer, with custom set to this structure.
+ * - message: The output file for normal output messages (often stdout), but with custom set to (controller_global_t *).
+ * - output: The output file for normal/non-message output, aka data output (often stdout or a file), but with custom set to (controller_global_t *).
+ * - error: The output file for error output messages, but with custom set to (controller_global_t *).
+ * - warning: The output file for warning output messages, but with custom set to (controller_global_t *).
+ * - debug: The output file for debug output messages, but with custom set to (controller_global_t *).
*/
#ifndef _di_controller_global_t_
typedef struct {
controller_program_t *program;
controller_thread_t *thread;
- fl_print_t message;
- fl_print_t output;
- fl_print_t error;
- fl_print_t warning;
- fl_print_t debug;
+ fl_print_t *message;
+ fl_print_t *output;
+ fl_print_t *error;
+ fl_print_t *warning;
+ fl_print_t *debug;
} controller_global_t;
- #define controller_global_t_initialize { 0, 0, 0 }
+ #define controller_global_t_initialize { 0, 0, 0, 0, 0, 0, 0, 0 }
- #define macro_controller_global_t_initialize(main, program, thread) { \
+ #define macro_controller_global_t_initialize_1(main, program, thread, message, output, error, warning, debug) { \
main, \
program, \
thread, \
- fl_print_t_initialize, \
- fl_print_t_initialize, \
- macro_fl_print_t_initialize_error(), \
- macro_fl_print_t_initialize_warning(), \
- macro_fl_print_t_initialize_debug(), \
+ message, \
+ output, \
+ error, \
+ warning, \
+ debug, \
}
#endif // _di_controller_global_t_
* path_pids: An array of paths representing PID files.
* stack: A stack used to represent dependencies as Rule ID's to avoid circular Rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
*
- * rule: A copy of the rule actively being executed.
- * cache: The cache used by this Instance.
- *
- * main: The associated main program data (of type controller_main_t).
- * program: The associated program data.
- * thread: The associated thread data (of type f_thread_t).
+ * rule: A copy of the rule actively being executed.
+ * cache: The cache used by this Instance.
+ * global: The global data.
*/
#ifndef _di_controller_instance_t_
typedef struct {
controller_rule_t rule;
controller_cache_t cache;
-
- // @fixme change this to void *global where global is controller_global_t??
- // @fixme each instance probably needs its own thread data and this likely needs to be backported if it do-able in a non-breaking-change manner!
- // @fixme I may want to instead replace the controller_global_t with controller_instance_t during printing calls (maybe more??).
- void *main;
- controller_program_t *program;
- void *thread;
+ controller_global_t global;
} controller_instance_t;
#define controller_instance_t_initialize { \
f_number_unsigneds_t_initialize, \
controller_rule_t_initialize, \
controller_cache_t_initialize, \
- 0, \
- 0, \
- 0, \
+ controller_global_t_initialize, \
}
#endif // _di_controller_instance_t_
* cache: A cache used by the main entry/rule processing thread for synchronous operations.
*/
#ifndef _di_controller_thread_t_
- typedef struct controller_thread_t_ {
+ typedef struct {
uint8_t enabled;
int signal;
f_status_t status;
#include <program/controller/main/common/type/lock.h>
#include <program/controller/main/common/type/rule.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/type/instance.h>
#include <program/controller/main/common.h>
#include <program/controller/main/path.h>
#include <program/controller/main/print/action.h>
#include <program/controller/main/rule/setting.h>
#include <program/controller/main/rule/validate.h>
#include <program/controller/main/rule/wait.h>
+#include <program/controller/main/process.h>
#ifdef __cplusplus
extern "C" {
}
#endif // _di_controller_main_print_error_
+#ifndef _di_controller_main_print_error_failsafe_item_
+ f_status_t controller_main_print_error_failsafe_item(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const name) {
+
+ if (!print) return F_status_set_error(F_output_not);
+ if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+ controller_lock_print(print->to, thread);
+
+ fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context);
+ fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, name, print->set->notable);
+ fl_print_format(f_string_format_sentence_end_quote_s.string, print->to, print->context, print->context, f_string_eol_s);
+
+ controller_unlock_print_flush(print->to, thread);
+
+ return F_okay;
+ }
+#endif // _di_controller_main_print_error_failsafe_item_
+
#ifndef _di_controller_main_print_error_file_
f_status_t controller_main_print_error_file(fl_print_t * const print, const f_string_t function, const f_string_static_t name, const f_string_static_t operation, const uint8_t type) {
}
#endif // _di_controller_main_print_error_file_status_
+#ifndef _di_controller_main_print_error_file_pid_exists_
+ f_status_t controller_main_print_error_file_pid_exists(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const path) {
+
+ if (!print) return F_status_set_error(F_output_not);
+ if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+ controller_lock_print(print->to, 0);
+
+ fl_print_format("%r%[%QThe pid file '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context);
+ fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, path, print->set->notable);
+ fl_print_format("%[' must not already exist.%]%r", print->to, print->context, print->context, f_string_eol_s);
+
+ controller_unlock_print_flush(print->to, 0);
+
+ return F_okay;
+ }
+#endif // _di_controller_main_print_error_file_pid_exists_
+
#ifndef _di_controller_main_print_error_status_
f_status_t controller_main_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status) {
#endif // _di_controller_main_print_error_
/**
+ * Print error message regarding the failsafe item failing.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * Must not be NULL.
+ *
+ * This does not alter print.custom.setting.state.status.
+ * @param thread
+ * The name of the function associated with the error.
+ *
+ * Must not be NULL.
+ * @param name
+ * The name of the item.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ * F_output_not on success, but no printing is performed.
+ *
+ * F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_controller_main_print_error_failsafe_item_
+ extern f_status_t controller_main_print_error_failsafe_item(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const name);
+#endif // _di_controller_main_print_error_failsafe_item_
+
+/**
* Print file related error or warning messages.
*
* @param print
extern void controller_main_print_rule_error_cache(fl_print_t * const print, const controller_cache_action_t cache, const bool item);
#endif // _di_controller_main_print_rule_error_cache_
+/**
+ * Print error message regarding the pid file already existing.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * Must not be NULL.
+ *
+ * This does not alter print.custom.setting.state.status.
+ * @param thread
+ * The name of the function associated with the error.
+ *
+ * Must not be NULL.
+ * @param path
+ * The path to the PID file.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ * F_output_not on success, but no printing is performed.
+ *
+ * F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_controller_main_print_error_file_pid_exists_
+ extern f_status_t controller_main_print_error_file_pid_exists(fl_print_t * const print, controller_thread_t * const thread, f_string_dynamic_t * const path);
+#endif // _di_controller_main_print_error_file_pid_exists_
+
#ifdef __cplusplus
} // extern "C"
#endif
--- /dev/null
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_main_process_
+ void controller_main_process(controller_main_t * const main, controller_program_t * const program) {
+
+ if (!main || !program || F_status_is_error(main->setting.state.status)) return;
+
+ main->setting.state.status = F_okay;
+
+ if (main->setting.flag & controller_main_flag_version_copyright_help_e) {
+ if (main->setting.flag & controller_main_flag_help_e) {
+ controller_main_print_message_help(&main->program.message, F_false);
+ }
+ else if (main->setting.flag & controller_main_flag_version_e) {
+ fll_program_print_version(&main->program.message, controller_program_version_s);
+ }
+ else if (main->setting.flag & controller_main_flag_copyright_e) {
+ fll_program_print_copyright(&main->program.message, fll_program_copyright_year_author_s);
+ }
+
+ return;
+ }
+
+ // A custom status at this scope is used to prevent the status from being changed by any child process or sub-function.
+ f_status_t status = F_okay;
+
+ fl_print_t message = main->program.message;
+ fl_print_t output = main->program.output;
+ fl_print_t error = main->program.error;
+ fl_print_t warning = main->program.warning;
+ fl_print_t debug = main->program.debug;
+
+ controller_thread_t thread = controller_thread_t_initialize;
+ controller_global_t global = macro_controller_global_t_initialize_1(main, program, &thread, &message, &output, &error, &warning, &debug);
+
+ message.custom = output.custom = error.custom = warning.custom = debug.custom = (void *) &global;
+
+ // The global locks must be initialized, but only once, so initialize immediately upon allocation.
+ status = controller_main_lock_create(&thread.lock);
+
+ if (F_status_is_error(status)) {
+ controller_main_print_error_status(&main->program.error, macro_controller_f(controller_main_lock_create), status);
+ } else {
+ status = f_memory_array_increase(controller_allocation_small_d, sizeof(controller_instance_t), (void **) &thread.instances.array, &thread.instances.used, &thread.instances.size);
+
+ if (F_status_is_error(status)) {
+ controller_main_print_error_status(&main->program.error, macro_controller_f(f_memory_array_increase), status);
+ }
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = f_thread_create(0, &thread.id_signal, &controller_thread_signal_normal, (void *) &global);
+ }
+
+ if (F_status_is_error(status)) {
+ thread.id_signal = 0;
+
+ controller_main_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status);
+ }
+ else {
+ if (main->setting.flag & controller_main_flag_daemon_e) {
+ program->ready = controller_setting_ready_done_e;
+
+ if (f_file_exists(program->path_pid, F_true) == F_true) {
+ status = F_status_set_error(F_available_not);
+ program->ready = controller_setting_ready_abort_e;
+
+ controller_main_print_error_file_pid_exists(&main->program.error, &thread, program->path_pid);
+ }
+ }
+ else if (program->name_entry.used) {
+ status = f_thread_create(0, &thread.id_entry, &controller_main_thread_entry, (void *) &global);
+
+ if (F_status_is_error(status)) {
+ controller_main_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status);
+ }
+ else {
+ controller_thread_join(&thread.id_entry);
+
+ status = thread.status;
+ thread.id_entry = 0;
+ }
+ }
+ }
+
+ // Only make the rule and control threads available once any/all pre-processing are complete.
+ if (F_status_is_error_not(status) && status != F_failure && status != F_child && thread.enabled == controller_thread_enabled_e) {
+ if (!(main->setting.flag & controller_main_flag_validate_e)) {
+
+ // Wait for the entry thread to complete before starting the rule thread.
+ controller_main_thread_join(&thread.id_rule);
+
+ if (thread.enabled && program->mode == controller_setting_mode_service_e) {
+ status = f_thread_create(0, &thread.id_rule, &controller_main_thread_rule, (void *) &global);
+
+ if (F_status_is_error(status)) {
+ thread.id_rule = 0;
+ }
+ else {
+ status = f_thread_create(0, &thread.id_cleanup, &controller_main_thread_cleanup, (void *) &global);
+ }
+
+ if (F_status_is_error(status)) {
+ thread.id_cleanup = 0;
+
+ controller_main_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status);
+ }
+ }
+ }
+ }
+
+ if (status == F_child) {
+ main->setting.state.status = F_child;
+
+ controller_main_thread_delete(&thread);
+
+ return;
+ }
+
+ if (F_status_is_error_not(status) && status != F_failure && !(main->setting.flag & controller_main_flag_validate_e) && controller_thread_is_enabled(F_true, &thread)) {
+ if (program->mode == controller_setting_mode_service_e) {
+ controller_main_thread_join(&thread.id_signal);
+ }
+ else if (program->mode == controller_setting_mode_helper_e || program->mode == controller_setting_mode_program_e) {
+ status = controller_main_rule_wait_all(global, F_true, F_false);
+ }
+ }
+
+ controller_main_thread_process_cancel(global, F_true, controller_thread_cancel_call_e);
+
+ controller_main_thread_process_exit(&global);
+
+ if (thread.id_signal) f_thread_join(thread.id_signal, 0);
+ if (thread.id_cleanup) f_thread_join(thread.id_cleanup, 0);
+ if (thread.id_control) f_thread_join(thread.id_control, 0);
+ if (thread.id_entry) f_thread_join(thread.id_entry, 0);
+ if (thread.id_rule) f_thread_join(thread.id_rule, 0);
+
+ thread.id_cleanup = 0;
+ thread.id_control = 0;
+ thread.id_entry = 0;
+ thread.id_rule = 0;
+ thread.id_signal = 0;
+
+ controller_main_thread_delete(&thread);
+
+ if (F_status_set_fine(status) == F_interrupt) {
+ fll_program_print_signal_received(&main->program.warning, thread.signal);
+
+ if (main->program.output.verbosity > f_console_verbosity_quiet_e) {
+ fll_print_dynamic_raw(f_string_eol_s, main->program.output.to);
+ }
+
+ fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+
+ return F_status_set_error(F_interrupt);
+ }
+
+ return F_status_is_error(status) ? F_status_set_error(F_failure) : F_okay;
+ }
+#endif // _di_controller_main_process_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the main process functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_process_h
+#define _controller_main_process_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Execute main program process.
+ *
+ * If main.signal is non-zero, then this blocks and handles the following signals:
+ * - F_signal_abort
+ * - F_signal_broken_pipe
+ * - F_signal_hangup
+ * - F_signal_interrupt
+ * - F_signal_quit
+ * - F_signal_termination
+ *
+ * @param main
+ * The main program data and settings.
+ *
+ * Must not be NULL.
+ *
+ * This alters main.setting.state.status:
+ * F_okay on success.
+ * F_true on success when performing verification and verify passed.
+ * F_false on success when performing verification and verify failed.
+ * F_interrupt on (exit) signal received.
+ *
+ * F_parameter (with error bit) if main is NULL or setting is NULL.
+ * @param program
+ * A pointer to the current program settings.
+ *
+ * Must not be NULL.
+ */
+#ifndef controller_main_process
+ extern void controller_main_process(controller_main_t * const main, controller_program_t * const program);
+#endif // controller_main_process
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_process_h
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
- controller_instance_t * const instance = (controller_instance_t * const ) arguments;
+ controller_global_t * const global = (controller_global_t * const) arguments;
- if (!controller_main_thread_is_enabled(F_true, instance->thread)) return 0;
+ if (!controller_main_thread_is_enabled(F_true, global->thread)) return 0;
- controller_main_t * const main = instance->main;
- controller_cache_t * const cache = &instance->thread->cache;
- f_status_t * const status = &instance->thread->status;
+ f_status_t * const status = &global->thread->status;
- *status = controller_entry_read(*instance->global, F_true, cache);
+ *status = controller_main_entry_read(global, F_true);
if (F_status_set_fine(*status) == F_interrupt) {
- instance->setting->ready = controller_setting_ready_abort_e;
+ global->program->ready = controller_setting_ready_abort_e;
}
else if (F_status_is_error(*status)) {
- instance->setting->ready = controller_setting_ready_fail_e;
+ global->program->ready = controller_setting_ready_fail_e;
}
else if (*status != F_child) {
- *status = controller_entry_preprocess(*instance->global, F_true, cache);
+ *status = controller_main_entry_preprocess(global, F_true);
- if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) {
- controller_entry_setting_validate(*instance->global, F_true, cache);
+ if ((global->main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (global->main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) {
+ controller_main_entry_setting_validate(global, F_true);
}
}
if (F_status_is_error_not(*status) && *status != F_child) {
- if (!(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) || (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) {
-
- if (instance->setting->instance.pid == controller_entry_pid_require_e && f_file_exists(instance->setting->path_pid, F_true) == F_true) {
- if (main->program.error.verbosity > f_console_verbosity_quiet_e) {
- controller_lock_print(main->program.error.to, instance->thread);
-
- fl_print_format("%r%[%QThe pid file '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context);
- fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, instance->setting->path_pid, main->program.error.notable);
- fl_print_format("%[' must not already exist.%]%r", main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s);
-
- controller_unlock_print_flush(main->program.error.to, instance->thread);
- }
+ if (!(global->main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) || (global->main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) {
- instance->setting->ready = controller_setting_ready_fail_e;
+ if (global->program->entry.pid == controller_entry_pid_require_e && f_file_exists(global->program->path_pid, F_true) == F_true) {
*status = F_status_set_error(F_available_not);
+ global->program->ready = controller_setting_ready_fail_e;
+
+ controller_main_print_error_file_pid_exists(&global->main->program.error, global->thread, global->program->path_pid);
}
else {
- *status = controller_entry_process(instance->global, cache, F_false, F_true);
+ *status = controller_main_entry_process(global, F_false, F_true);
if (F_status_is_error(*status)) {
- instance->setting->ready = controller_setting_ready_fail_e;
+ global->program->ready = controller_setting_ready_fail_e;
- if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (instance->setting->flag & controller_setting_flag_failsafe_e)) {
- const uint8_t original_enabled = instance->thread->enabled;
+ if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (program->flag & controller_setting_flag_failsafe_e)) {
+ const uint8_t original_enabled = global->thread->enabled;
// Restore operating mode so that the failsafe can execute.
- *status = f_thread_mutex_lock(&instance->thread->lock.alert);
+ *status = f_thread_mutex_lock(&global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
- instance->thread->enabled = controller_thread_enabled_e;
+ global->thread->enabled = controller_thread_enabled_e;
- f_thread_mutex_unlock(&instance->thread->lock.alert);
+ f_thread_mutex_unlock(&global->thread->lock.alert);
}
- // Restart the signal thread to allow for signals while operating the failsafe Items.
- if (!instance->thread->id_signal) {
- f_thread_create(0, &instance->thread->id_signal, &controller_main_thread_signal_normal, (void *) instance->global);
+ // Restart the signal global->thread to allow for signals while operating the failsafe Items.
+ if (!global->thread->id_signal) {
+ f_thread_create(0, &global->thread->id_signal, &controller_main_thread_signal_normal, (void *) global);
}
- const f_status_t status_failsafe = controller_entry_process(instance->global, cache, F_true, F_true);
+ const f_status_t status_failsafe = controller_main_entry_process(global, F_true, F_true);
if (F_status_is_error(status_failsafe)) {
- if (main->program.error.verbosity > f_console_verbosity_quiet_e) {
- controller_lock_print(main->program.error.to, instance->thread);
-
- fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context);
- fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, instance->setting->instance.items.array[instance->setting->failsafe_item_id].name, main->program.error.notable);
- fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s);
-
- controller_unlock_print_flush(main->program.error.to, instance->thread);
- }
-
*status = F_status_set_error(F_failure);
+
+ controller_main_print_error_failsafe_item(&global->main->program.error, global->thread, global->program->entry.items.array[program->failsafe_item_id].name);
}
else {
// Restore operating mode to value prior to failsafe mode.
- *status = f_thread_mutex_lock(&instance->thread->lock.alert);
+ *status = f_thread_mutex_lock(&global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
- instance->thread->enabled = original_enabled;
+ global->thread->enabled = original_enabled;
- f_thread_mutex_unlock(&instance->thread->lock.alert);
+ f_thread_mutex_unlock(&global->thread->lock.alert);
}
*status = F_failure;
}
}
else if (F_status_set_fine(*status) == F_interrupt) {
- instance->setting->ready = controller_setting_ready_abort_e;
+ global->program->ready = controller_setting_ready_abort_e;
}
else if (*status != F_child) {
- instance->setting->ready = controller_setting_ready_done_e;
+ global->program->ready = controller_setting_ready_done_e;
}
}
- if (F_status_is_error_not(*status) && *status != F_child && main->program.parameters.array[controller_parameter_validate_e].result == f_console_result_none_e && instance->setting->mode == controller_setting_mode_helper_e) {
+ if (F_status_is_error_not(*status) && *status != F_child && global->main->program.parameters.array[controller_parameter_validate_e].result == f_console_result_none_e && global->program->mode == controller_setting_mode_helper_e) {
f_time_spec_t time;
time.tv_sec = controller_main_thread_exit_helper_timeout_seconds_d;
time.tv_nsec = controller_main_thread_exit_helper_timeout_nanoseconds_d;
nanosleep(&time, 0);
- controller_main_thread_process_cancel(*(instance->global), F_true, controller_thread_cancel_exit_e);
+ controller_main_thread_process_cancel(global, F_true, controller_thread_cancel_exit_e);
}
}
}
// A forked child process should deallocate memory on exit.
// It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below.
- controller_thread_delete_simple(instance->thread);
- controller_process_delete(instance->setting);
- controller_main_delete(main);
+ controller_main_thread_delete(global->thread);
+ controller_main_program_delete(global->program);
+ controller_main_delete(global->main);
- // According to the manpages, pthread_exit() calls exit(0), which the value of main->program.child should be returned instead.
- if (main->program.child) exit(main->program.child);
+ // According to the manpages, pthread_exit() calls exit(0), which the value of global->main->program.child should be returned instead.
+ if (global->main->program.child) exit(global->main->program.child);
return 0;
}
- f_thread_condition_signal_all(&instance->thread->lock.alert_condition);
+ f_thread_condition_signal_all(&global->thread->lock.alert_condition);
return 0;
}
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
- controller_main_entry_t *instance = (controller_main_entry_t *) arguments;
+ controller_global_t * const global = (controller_global_t * const) arguments;
- controller_main_t * const main = instance->main;
- controller_cache_t * const cache = &instance->thread->cache;
- f_status_t * const status = &instance->thread->status;
+ controller_main_t * const main = global->main;
+ controller_cache_t * const cache = &global->thread->cache;
+ f_status_t * const status = &global->thread->status;
- *status = controller_entry_read(*instance->global, F_false, cache);
+ *status = controller_entry_read(global, F_false);
if (F_status_set_fine(*status) == F_interrupt) {
- instance->setting->ready = controller_setting_ready_abort_e;
+ global->program->ready = controller_setting_ready_abort_e;
}
else if (F_status_is_error(*status)) {
- instance->setting->ready = controller_setting_ready_fail_e;
+ global->program->ready = controller_setting_ready_fail_e;
}
else if (*status == F_file_found_not) {
- instance->setting->ready = controller_setting_ready_done_e;
+ global->program->ready = controller_setting_ready_done_e;
}
else if (*status != F_child) {
- *status = controller_entry_preprocess(*instance->global, F_false, cache);
+ *status = controller_entry_preprocess(global, F_false, cache);
if ((main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e) && (main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e)) {
- controller_entry_setting_validate(*instance->global, F_false, cache);
+ controller_entry_setting_validate(global, F_false, cache);
}
}
if (F_status_is_error_not(*status) && *status != F_child && *status != F_file_found_not) {
if (!(main->program.parameters.array[controller_parameter_validate_e].result & f_console_result_found_e) || (main->program.parameters.array[controller_parameter_simulate_e].result & f_console_result_found_e)) {
- *status = controller_entry_process(instance->global, cache, F_false, F_false);
+ *status = controller_entry_process(global, F_false, F_false);
if (F_status_is_error(*status)) {
- instance->setting->ready = controller_setting_ready_fail_e;
+ global->program->ready = controller_setting_ready_fail_e;
- if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (instance->setting->flag & controller_setting_flag_failsafe_e)) {
+ if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (global->program->flag & controller_setting_flag_failsafe_e)) {
- const uint8_t original_enabled = instance->thread->enabled;
+ const uint8_t original_enabled = global->thread->enabled;
// Restore operating mode so that the failsafe can execute.
if (F_status_set_fine(*status) == F_execute) {
- *status = f_thread_mutex_lock(&instance->thread->lock.alert);
+ *status = f_thread_mutex_lock(&global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
- instance->thread->enabled = controller_thread_enabled_exit_e;
+ global->thread->enabled = controller_thread_enabled_exit_e;
- f_thread_mutex_unlock(&instance->thread->lock.alert);
+ f_thread_mutex_unlock(&global->thread->lock.alert);
}
// Restart the signal thread to allow for signals while operating the failsafe Items.
- if (!instance->thread->id_signal) {
- f_thread_create(0, &instance->thread->id_signal, &controller_main_thread_signal_other, (void *) instance->global);
+ if (!global->thread->id_signal) {
+ f_thread_create(0, &global->thread->id_signal, &controller_main_thread_signal_other, (void *) global);
}
}
- const f_status_t status_failsafe = controller_entry_process(instance->global, cache, F_true, F_false);
+ const f_status_t status_failsafe = controller_entry_process(global, F_true, F_false);
if (F_status_is_error(status_failsafe)) {
- if (main->program.error.verbosity > f_console_verbosity_quiet_e) {
- controller_lock_print(main->program.error.to, instance->thread);
-
- fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", main->program.error.to, f_string_eol_s, main->program.error.context, main->program.error.prefix, main->program.error.context);
- fl_print_format(f_string_format_Q_single_s.string, main->program.error.to, main->program.error.notable, instance->setting->instance.items.array[instance->setting->failsafe_item_id].name, main->program.error.notable);
- fl_print_format(f_string_format_sentence_end_quote_s.string, main->program.error.to, main->program.error.context, main->program.error.context, f_string_eol_s);
-
- controller_unlock_print_flush(main->program.error.to, instance->thread);
- }
-
*status = F_status_set_error(F_failure);
+
+ controller_main_print_error_failsafe_item(&global->main->program.error, global->thread, global->program->entry.items.array[program->failsafe_item_id].name);
}
else {
// Restore operating mode to value prior to failsafe mode.
- *status = f_thread_mutex_lock(&instance->thread->lock.alert);
+ *status = f_thread_mutex_lock(&global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
- instance->thread->enabled = original_enabled;
+ global->thread->enabled = original_enabled;
- f_thread_mutex_unlock(&instance->thread->lock.alert);
+ f_thread_mutex_unlock(&global->thread->lock.alert);
}
*status = F_failure;
}
}
else if (F_status_set_fine(*status) == F_interrupt) {
- instance->setting->ready = controller_setting_ready_abort_e;
+ global->program->ready = controller_setting_ready_abort_e;
}
else if (*status != F_child) {
- instance->setting->ready = controller_setting_ready_done_e;
+ global->program->ready = controller_setting_ready_done_e;
}
}
}
// A forked child process should deallocate memory on exit.
// It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below.
- controller_thread_delete_simple(instance->thread);
- controller_process_delete(instance->setting);
+ controller_thread_delete_simple(global->thread);
+ controller_process_delete(global->program);
controller_main_delete(main);
return 0;
}
- if (F_status_is_error_not(f_thread_mutex_lock(&instance->thread->lock.alert))) {
- instance->thread->enabled = controller_thread_enabled_not_e;
+ if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) {
+ global->thread->enabled = controller_thread_enabled_not_e;
- f_thread_mutex_unlock(&instance->thread->lock.alert);
+ f_thread_mutex_unlock(&global->thread->lock.alert);
}
- f_thread_condition_signal_all(&instance->thread->lock.alert_condition);
+ f_thread_condition_signal_all(&global->thread->lock.alert_condition);
return 0;
}