#ifndef _di_controller_process_delete_simple_
void controller_process_delete_simple(controller_process_t *process) {
- f_string_dynamic_resize(0, &process->id);
+ f_string_dynamic_resize(0, &process->id_rule);
f_thread_lock_delete(&process->lock);
- f_thread_lock_attribute_delete(&process->attribute);
- f_thread_condition_delete(&process->wait);
+ f_thread_lock_delete(&process->active);
+
+ f_thread_lock_attribute_delete(&process->lock_attribute);
+ f_thread_lock_attribute_delete(&process->active_attribute);
}
#endif // _di_controller_process_delete_simple_
extern "C" {
#endif
+/**
+ * All special strings used within this program.
+ *
+ * These are generally the names to match, representing some action or setting.
+ */
#ifndef _di_controller_string_
#define controller_string_action "action"
#define controller_string_actions "actions"
const static f_string_t controller_string_yes_s = controller_string_yes;
#endif // _di_controller_string_
+/**
+ * A set of codes for resource limitations.
+ *
+ * This essentally converts the POSIX standard names into a more verbose format.
+ */
#ifndef _di_controller_resource_limit_t_
enum {
controller_resource_limit_type_as = RLIMIT_AS,
};
#endif // _di_controller_resource_limit_t_
+/**
+ * A structure for passing execution arguments to the execute functions.
+ *
+ * parameter: All parameters sent to the program on execution.
+ * as: All special properties to apply, such as cpu affinity.
+ */
#ifndef _di_controller_execute_set_t_
typedef struct {
fl_execute_parameter_t parameter;
/**
* A structure for sharing mutexes globally between different threads.
*
- * The asynchronous lock is intended to lock any activity on the asynchronouss structure.
+ * The asynchronous lock is intended to lock any activity on the asynchronouss structure and related.
* The print lock is intended to lock any activity printing to stdout/stderr.
* The process lock is intended to lock any activity on the processs structure.
* The rule lock is intended to lock any activity on the rules structure.
+ *
+ * print: The print mutex lock.
+ * asynchronous: The asynchronous r/w lock.
+ * asynchronous_attribute: The asynchronous r/w lock attribute.
+ * process: The process r/w lock.
+ * process_attribute: The process r/w lock attribute.
+ * rule: The rule r/w lock.
+ * rule_attribute: The rule r/w lock attribute.
+ *
*/
#ifndef _di_controller_lock_t_
typedef struct {
}
#endif // _di_controller_mutex_t_
+/**
+ * A Rule Action.
+ *
+ * type: The Rule Action type.
+ * line: The line number where the Rule Action begins.
+ * status: The last execution status of the Rule Action.
+ * parameters: All parameters associated with the Rule Action.
+ */
#ifndef _di_controller_rule_action_t_
#define controller_rule_action_method_string_extended "FSS-0001 (Extended)"
#define controller_rule_action_method_string_extended_list "FSS-0003 (Extended List)"
f_macro_string_dynamics_t_clear(rule.parameters)
#endif // _di_controller_rule_action_t_
+/**
+ * The Rule Actions.
+ *
+ * array: An array of Rule Actions.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_rule_actions_t_
typedef struct {
controller_rule_action_t *array;
actions.used = 0;
#endif // _di_controller_rule_actions_t_
+/**
+ * A Rule Item.
+ *
+ * type: The type of the Rule Item.
+ * line: The line number where the Rule Item begins.
+ * actions: The actions associated with the Rule Item.
+ */
#ifndef _di_controller_rule_item_t_
enum {
controller_rule_item_type_command = 1,
controller_macro_rule_actions_t_clear(item.actions);
#endif // _di_controller_rule_item_t_
+/**
+ * The Rule Items.
+ *
+ * array: An array of Rule Items.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_rule_items_t_
typedef struct {
controller_rule_item_t *array;
items.used = 0;
#endif // _di_controller_rule_items_t_
+/**
+ * A Rule.
+ *
+ * timeout_kill: The timeout to wait relating to using a kill signal.
+ * timeout_start: The timeout to wait relating to starting a process.
+ * timeout_stop: The timeout to wait relating to stopping a process.
+ * has: Bitwise set of "has" codes representing what the Rule has.
+ * nice: The niceness value if the Rule "has" nice.
+ * user: The User ID if the Rule "has" a user.
+ * group: The Group ID if the Rule "has" a group.
+ * timestamp: The timestamp when the Rule was loaded.
+ * id: The distinct ID (machine name) of the rule, such as "service/ssh".
+ * name: A human name for the Rule (does not have to be distinct).
+ * path: The path to the Rule file.
+ * script: The program or path to the program of the scripting engine to use when processing scripts in this Rule.
+ * define: Any defines (environment variables) made available to the Rule for IKI substitution or just as environment variables.
+ * parameters: Any parameters made available to the Rule for IKI substitution.
+ * environment: All environment variables allowed to be exposed to the Rule when processing.
+ * need: A Rule ID (machine name) of the Rule that is needed (required).
+ * want: A Rule ID (machine name) of the Rule that is wanted (optional).
+ * wish: A Rule ID (machine name) of the Rule that is wished for (optional).
+ * affinity: The cpu affinity to be used when executing the Rule.
+ * capability: The capability setting if the Rule "has" a capability.
+ * control_group: The control group setting if the Rule "has" a control group.
+ * groups: The groups to assign to the user to run as (with the first group being the primary group).
+ * limits: The cpu/resource limits to use when executing the Rule.
+ * scheduler: The scheduler setting if the Rule "has" a scheduler.
+ * items: All items associated with the Rule.
+ */
#ifndef _di_controller_rule_t_
enum {
controller_rule_setting_type_affinity = 1,
controller_macro_rule_items_t_clear(rule.items)
#endif // _di_controller_rule_t_
+/**
+ * The Rules.
+ *
+ * array: An array of Rules.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_rules_t_
typedef struct {
controller_rule_t *array;
#endif // _di_controller_rules_t_
/**
- * Store controller process information for some rule.
+ * A Rule Process.
*
- * This refers to "process" as in the processing of a rule and does not refer to "process" as in a CPU process.
+ * This refers to "process" as in the processing of a single rule for the given Rule ID and does not refer to "process" as in a CPU Process.
*
- * This holds the success/failure rate and any associated locks.
- * This operates based on the rule id string (such as "network/ntpdate").
+ * id_rule: The Rule ID, such as "network/ntpdate".
+ * status: The last execution status of the Rule.
+ * lock: A read/write lock on the structure.
+ * active: A read/write lock representing that something is currently using this (read locks = in use, write lock = see if in use and possibly prepare for delete).
+ * lock_attribute: The lock attribute for "lock".
+ * active_attribute: The lock attribute for "active".
*/
#ifndef _di_controller_process_t_
typedef struct {
- f_string_dynamic_t id;
+ f_string_dynamic_t id_rule;
f_status_t status;
f_thread_lock_t lock;
- f_thread_lock_attribute_t attribute;
- f_thread_condition_t wait;
+ f_thread_lock_t active;
+ f_thread_lock_attribute_t lock_attribute;
+ f_thread_lock_attribute_t active_attribute;
} controller_process_t;
#define controller_process_t_initialize { \
f_string_dynamic_t_initialize \
F_known_not, \
f_thread_lock_t_initialize, \
+ f_thread_lock_t_initialize, \
+ f_thread_lock_attribute_t_initialize, \
f_thread_lock_attribute_t_initialize, \
- f_thread_condition_t_initialize, \
}
-
- #define controller_macro_process_t_clear(process) \
- process.status = F_known_not; \
- f_macro_string_dynamic_t_clear(process.id)
#endif // _di_controller_process_t_
+/**
+ * The Rule Processes.
+ *
+ * array: An array of rule processes.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_processs_t_
typedef struct {
controller_process_t *array;
process.used = 0;
#endif // _di_controller_processs_t_
+/**
+ * An Entry Item Action
+ *
+ * type: The type of Action.
+ * code: A single code or sub-type associated with the Action.
+ * line: The line number where the Entry Item begins.
+ * number: The unsigned number that some types use instead of the "parameters".
+ * status: The overall status.
+ * parameters: The values associated with the Action.
+ */
#ifndef _di_controller_entry_action_t_
enum {
controller_entry_action_type_consider = 1,
f_macro_string_dynamics_t_clear(action.parameters)
#endif // _di_controller_entry_action_t_
+/**
+ * The Entry Item Actions.
+ *
+ * array: An array of Entry Item Actions.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_entry_actions_t_
typedef struct {
controller_entry_action_t *array;
actions.used = 0;
#endif // _di_controller_entry_actions_t_
+/**
+ * An Entry Item.
+ *
+ * line: The line number where the Entry Item begins.
+ * name: The name of the Entry Item.
+ * actions: The Actions associated with the Entry Item.
+ */
#ifndef _di_controller_entry_item_t_
typedef struct {
f_array_length_t line;
controller_macro_entry_actions_t_clear(item.actions)
#endif // _di_controller_entry_item_t_
+/**
+ * An Entry Items.
+ *
+ * array: An array of Entry Items.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_entry_items_t_
typedef struct {
controller_entry_item_t *array;
items.used = 0;
#endif // _di_controller_entry_items_t_
+/**
+ * The Entry.
+ *
+ * status: The overall status.
+ * items: The array of entry items.
+ */
#ifndef _di_controller_entry_t_
typedef struct {
f_status_t status;
controller_macro_entry_items_t_clear(entry.items)
#endif // _di_controller_entry_t_
+/**
+ * All setting data.
+ *
+ * interruptable: TRUE if the program responds to interrupt signals, FALSE to block/ignore interrupt signals.
+ * ready: State representing if the settings are all loaded and is ready to run program operations.
+ * timeout_kill: The timeout to wait relating to using a kill signal.
+ * timeout_start: The timeout to wait relating to starting a process.
+ * timeout_stop: The timeout to wait relating to stopping a process.
+ * failsafe_enabled: TRUE if failsafe execution is enabled, FALSE otherwise.
+ * failsafe_rule_id: The Rule ID (such as "failsafe/bash") to execute when failsafe execution is enabled.
+ * path_control: File path to the control socket.
+ * path_pid: File path to the PID file.
+ * path_setting: File path to the setting directory.
+ * entry: The entry settings.
+ * rules: All rules and their respective settings.
+ */
#ifndef _di_controller_setting_t
enum {
controller_setting_ready_no = 0,
typedef struct {
bool interruptable;
uint8_t ready;
- int signal;
f_number_unsigned_t timeout_kill;
f_number_unsigned_t timeout_start;
#define controller_setting_t_initialize { \
F_false, \
0, \
- 0, \
3, \
3, \
3, \
#define controller_macro_setting_t_clear(setting) \
setting.interruptable = F_false; \
setting.ready = 0; \
- setting.signal = 0; \
setting.timeout_kill = 3; \
setting.timeout_start = 3; \
setting.timeout_stop = 3; \
controller_macro_rules_t_clear(entry.setting)
#endif // _di_controller_setting_t
+/**
+ * Action related cache.
+ *
+ * line_action: The line in some file representing an Action.
+ * line_item: The line in some file representing an Item.
+ * name_action: A NULL terminated name of some Action.
+ * name_file: A NULL terminated name of some File.
+ * name_item: A NULL terminated name of some Item.
+ * generic: A NULL terminated string for general use.
+ */
#ifndef _di_controller_cache_action_t_
typedef struct {
f_array_length_t line_action;
f_macro_string_dynamic_t_clear(cache.generic)
#endif // _di_controller_cache_action_t_
+/**
+ * A cache intended for re-using memory while loading and processing rules whenever possible.
+ *
+ * timestamp: The timestamp.
+ * range_action: The Range for some Action.
+ * ats: Locations.
+ * stack: Locations within a items history used as a history stack for circular recursion prevention.
+ * comments: Comments associated with a buffer string.
+ * delimits: Delimits associated with a buffer string.
+ * content_action: The specific Content for some Action.
+ * content_actions: Content for some Action.
+ * content_items: Content for some Item.
+ * object_actions: Objects for some Action.
+ * object_items: Objects for some Item.
+ * buffer_file: A generic file related buffer.
+ * buffer_item: A generic item related buffer.
+ * buffer_path: A generic path related buffer.
+ * action: A cache for some Action, often used by error printing for reporting where an error happened.
+ */
#ifndef _di_controller_cache_t_
typedef struct {
f_time_spec_t timestamp;
f_string_dynamic_t_initialize, \
controller_cache_action_t_initialize, \
}
-
- #define controller_macro_cache_t_clear(cache) \
- f_macro_time_spec_t_clear(cache.timestamp) \
- f_macro_string_range_t_clear(cache.range_action) \
- cache.ats = 0; \
- cache.stack = 0; \
- f_macro_time_spec_t_clear(cache.timestamp) \
- f_macro_fss_comments_t_clear(cache.comments) \
- f_macro_fss_delimits_t_clear(cache.delimits) \
- f_macro_fss_content_t_clear(cache.content_action) \
- f_macro_fss_contents_t_clear(cache.content_actions) \
- f_macro_fss_contents_t_clear(cache.content_items) \
- f_macro_fss_objects_t_clear(cache.object_actions) \
- f_macro_fss_objects_t_clear(cache.object_items) \
- f_macro_string_dynamic_t_clear(cache.buffer_file) \
- f_macro_string_dynamic_t_clear(cache.buffer_item) \
- f_macro_string_dynamic_t_clear(cache.buffer_path) \
- controller_macro_cache_action_t_clear(cache.action)
#endif // _di_controller_cache_t_
+/**
+ * Stores data passed to a thread on thread creation, specifically for rule processing.
+ *
+ * The thread has different states:
+ * - active: The thread is running.
+ * - done: The thread has finished executed but has not been cleaned up.
+ * - joined: The thread has been cleaned up, this is safe to delete.
+ *
+ * id: The thread id, which is controlled by pthread functions.
+ * id_process: The id representing the rule process this asynchronous thread operates for.
+ * state: The state of the asynchronous.
+ * action: The action being performed.
+ * options: Configuration options for this asynchronous thread.
+ * child: The process id of a child process, if one is running (when forking to execute a child process).
+ * stack: The execution stack representing all other rule processes (by process id) that called this (to prevent infinite recursion). // @todo is this needed here anymore?
+ * cache: A per asynchronous thread cache.
+ */
#ifndef _di_controller_asynchronous_t_
enum {
controller_asynchronous_state_active = 1,
typedef struct {
f_thread_id_t id;
- f_thread_lock_t lock;
- f_thread_lock_attribute_t attribute;
+ f_array_length_t id_process;
- f_array_length_t index;
uint8_t state;
uint8_t action;
uint8_t options;
#define controller_asynchronous_t_initialize { \
f_thread_id_t_initialize, \
- f_thread_lock_t_initialize, \
- f_thread_lock_attribute_t_initialize, \
0, \
0, \
0, \
f_array_lengths_t_initialize, \
controller_cache_t_initialize \
}
-
- // @fixme remove the clear() macros..clear isn't safe when mixing in mutexes and whatnot that cannot be cleared.
- #define controller_macro_asynchronous_t_clear(asynchronous) \
- f_macro_thread_id_t_clear(asynchronous.id) \
- asynchronous.index = 0; \
- asynchronous.state = 0; \
- asynchronous.action = 0; \
- asynchronous.options = 0; \
- asynchronous.child = 0; \
- f_macro_array_lengths_t_clear(asynchronous.stack) \
- controller_macro_cache_t_clear(asynchronous.cache)
#endif // _di_controller_asynchronous_t_
+/**
+ * The asynchronous execution data.
+ *
+ * array: An array of asynchronous execution data.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
#ifndef _di_controller_asynchronouss_t_
typedef struct {
controller_asynchronous_t *array;
asynchronouss.used = 0;
#endif // _di_controller_asynchronouss_t_
+/**
+ * A structure for managing threads.
+ *
+ * This is essentially data shared globally between threads, about threads.
+ *
+ * As a special case, index 0 of asynchronouss is reserved for use the main thread and is not used by any Rule Processes.
+ *
+ * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE.
+ * signal: The code of any signal received.
+ * id_cleanup: The thread ID representing the cleanup Process.
+ * id_control: The thread ID representing the cleanup Process.
+ * id_rule: The thread ID representing the cleanup Process.
+ * id_signal: The thread ID representing the cleanup Process.
+ * lock: A r/w lock for operating on this structure.
+ * asynchronouss: All Rule Process thread data.
+ */
#ifndef _di_controller_thread_t_
typedef struct {
bool enabled;
+ int signal;
f_thread_id_t id_cleanup;
f_thread_id_t id_control;
#define controller_thread_t_initialize { \
F_true, \
+ 0, \
f_thread_id_t_initialize, \
f_thread_id_t_initialize, \
f_thread_id_t_initialize, \
#define controller_macro_thread_t_initialize(lock, asynchronouss) { \
F_true, \
+ 0, \
f_thread_id_t_initialize, \
f_thread_id_t_initialize, \
f_thread_id_t_initialize, \
#define controller_macro_thread_t_clear(thread) \
thread.enabled = F_true; \
+ thread.signal = 0; \
f_macro_thread_id_t_clear(thread.id_cleanup); \
f_macro_thread_id_t_clear(thread.id_control); \
f_macro_thread_id_t_clear(thread.id_rule); \
controller_macro_asynchronouss_t_clear(thread.asynchronouss)
#endif // _di_controller_data_common_t_
+/**
+ * A wrapper used for passing all data to each individual asynchronous thread.
+ *
+ * id_process: The index in the processs array representing the current process.
+ * data: All standard program data.
+ * setting: All loaded settings.
+ * processs: All Rule Process data.
+ * thread: All thread related data.
+ */
#ifndef _di_controller_thread_data_t_
// @todo relocate these under a different ifdef block.
#define controller_thread_cache_cleanup_interval_long 3600 // 1 hour in seconds.
#define controller_thread_asynchronous_max 65535 // Total number of asynchronous threads allowed at any one time.
typedef struct {
- f_array_length_t id;
+ f_array_length_t id_process;
controller_data_t *data;
controller_setting_t *setting;
#define controller_thread_data_t_initialize { 0, 0, 0, 0, 0 }
- #define controller_macro_thread_data_t_initialize(id, data, setting, processs, thread) { \
- id, \
+ #define controller_macro_thread_data_t_initialize(id_process, data, setting, processs, thread) { \
+ id_process, \
data, \
setting, \
processs, \
}
#define controller_macro_thread_data_t_clear(thread_data) \
- thread_data.id = 0; \
+ thread_data.id_process = 0; \
thread_data.data = 0; \
thread_data.setting = 0; \
thread_data.processs = 0; \
for (f_array_length_t i = 0; i < processs.used; ++i) {
- if (fl_string_dynamic_compare(id, processs.array[i].id) == F_equal_to) {
+ if (fl_string_dynamic_compare(id, processs.array[i].id_rule) == F_equal_to) {
*at = i;
return F_true;
}
for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) {
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
return F_signal;
}
uint8_t rule_options = 0;
- controller_entry_actions_t *actions = 0;
-
+ controller_entry_action_t *entry_action = 0;
+ controller_entry_actions_t *entry_actions = 0;
controller_process_t *process = 0;
const bool simulate = thread_data.data->parameters[controller_parameter_test].result == f_console_result_found;
// I would much rather gain the write lock and then release the read lock, but that is likely not possible.
for (;;) {
- actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions;
+ entry_actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions;
- for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) {
+ for (; cache->ats.array[at_j] < entry_actions->used; ++cache->ats.array[at_j]) {
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
status = F_signal;
break;
}
- cache->action.line_action = actions->array[cache->ats.array[at_j]].line;
+ entry_action = &entry_actions->array[cache->ats.array[at_j]];
+
+ cache->action.line_action = entry_action->line;
cache->action.name_action.used = 0;
- status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->action.name_action);
+ status = controller_string_dynamic_append_terminated(controller_entry_action_type_name(entry_action->type), &cache->action.name_action);
if (F_status_is_error(status)) {
controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread);
return status;
}
- if (F_status_is_error(actions->array[cache->ats.array[at_j]].status)) {
+ if (F_status_is_error(entry_action->status)) {
- if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+ if (entry_action->type == controller_entry_action_type_rule) {
if (simulate) {
f_thread_mutex_lock(&thread_data.thread->lock.print);
fprintf(thread_data.data->output.stream, "The entry item action '");
fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_action.string, thread_data.data->context.set.title.after->string);
- if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ if (entry_action->parameters.used) {
fprintf(thread_data.data->output.stream, f_string_space_s);
fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.before->string);
- controller_entry_action_parameters_print(thread_data.data->output.stream, actions->array[cache->ats.array[at_j]]);
+ controller_entry_action_parameters_print(thread_data.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.after->string);
}
- fprintf(thread_data.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require ? "required" : "optional", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+ fprintf(thread_data.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
f_thread_mutex_unlock(&thread_data.thread->lock.print);
}
- else if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
+ else if (entry_action->code & controller_entry_rule_code_require) {
if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
f_thread_mutex_lock(&thread_data.thread->lock.print);
fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action '", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s);
fprintf(thread_data.data->error.to.stream, "%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->action.name_action.string);
- if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ if (entry_action->parameters.used) {
fprintf(thread_data.data->error.to.stream, f_string_space_s);
- controller_entry_action_parameters_print(thread_data.data->error.to.stream, actions->array[cache->ats.array[at_j]]);
+ controller_entry_action_parameters_print(thread_data.data->error.to.stream, entry_actions->array[cache->ats.array[at_j]]);
}
fprintf(thread_data.data->error.to.stream, "%s%s' is ", thread_data.data->error.notable.after->string, thread_data.data->error.context.before->string);
fprintf(thread_data.data->warning.to.stream, "%s%sThe entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s);
fprintf(thread_data.data->warning.to.stream, "%s%s%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, cache->action.name_action.string);
- if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ if (entry_action->parameters.used) {
fprintf(thread_data.data->warning.to.stream, f_string_space_s);
- controller_entry_action_parameters_print(thread_data.data->warning.to.stream, actions->array[cache->ats.array[at_j]]);
+ controller_entry_action_parameters_print(thread_data.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]);
}
fprintf(thread_data.data->warning.to.stream, "%s%s' is ", thread_data.data->warning.notable.after->string, thread_data.data->warning.context.before->string);
fprintf(thread_data.data->output.stream, "The entry item action '");
fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_action.string, thread_data.data->context.set.title.after->string);
- if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ if (entry_action->parameters.used) {
fprintf(thread_data.data->output.stream, f_string_space_s);
fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.before->string);
- controller_entry_action_parameters_print(thread_data.data->output.stream, actions->array[cache->ats.array[at_j]]);
+ controller_entry_action_parameters_print(thread_data.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.after->string);
}
fprintf(thread_data.data->warning.to.stream, "%s%sThe entry item action '", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s);
fprintf(thread_data.data->warning.to.stream, "%s%s", thread_data.data->warning.notable.before->string, cache->action.name_action.string);
- if (actions->array[cache->ats.array[at_j]].parameters.used) {
+ if (entry_action->parameters.used) {
fprintf(thread_data.data->warning.to.stream, f_string_space_s);
- controller_entry_action_parameters_print(thread_data.data->warning.to.stream, actions->array[cache->ats.array[at_j]]);
+ controller_entry_action_parameters_print(thread_data.data->warning.to.stream, entry_actions->array[cache->ats.array[at_j]]);
}
fprintf(thread_data.data->warning.to.stream, "%s' is in a ", thread_data.data->warning.notable.after->string);
continue;
}
- if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) {
+ if (entry_action->type == controller_entry_action_type_ready) {
if (thread_data.setting->ready == controller_setting_ready_wait) {
f_thread_mutex_unlock(&thread_data.thread->lock.print);
}
}
- else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) {
+ else if (entry_action->type == controller_entry_action_type_item) {
- if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= thread_data.setting->entry.items.used) {
+ if (entry_action->number == 0 || entry_action->number >= thread_data.setting->entry.items.used) {
// This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
fprintf(thread_data.data->error.to.stream, "%s%sInvalid entry item index ", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s);
- fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, thread_data.data->error.notable.after->string);
+ fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, entry_action->number, thread_data.data->error.notable.after->string);
fprintf(thread_data.data->error.to.stream, "%s detected.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
controller_entry_error_print_cache(thread_data.data->error, cache->action);
}
// continue into the requested item.
- cache->ats.array[cache->ats.used] = actions->array[cache->ats.array[at_j]].number;
+ cache->ats.array[cache->ats.used] = entry_action->number;
cache->ats.array[cache->ats.used + 1] = 0;
at_i = cache->ats.used;
// exit inner loop to force restarting and start processing the requested item.
break;
}
- else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_consider || actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+ else if (entry_action->type == controller_entry_action_type_consider || entry_action->type == controller_entry_action_type_rule) {
status = controller_rules_increase(&thread_data.setting->rules);
return status;
}
- const f_array_length_t rule_id_length = actions->array[cache->ats.array[at_j]].parameters.array[0].used + actions->array[cache->ats.array[at_j]].parameters.array[1].used + 1;
- char rule_id_name[rule_id_length + 1];
- const f_string_static_t rule_id = f_macro_string_static_t_initialize(rule_id_name, rule_id_length);
+ const f_array_length_t id_rule_length = entry_action->parameters.array[0].used + entry_action->parameters.array[1].used + 1;
+ char id_rule_name[id_rule_length + 1];
+ const f_string_static_t id_rule = f_macro_string_static_t_initialize(id_rule_name, id_rule_length);
- memcpy(rule_id_name, actions->array[cache->ats.array[at_j]].parameters.array[0].string, actions->array[cache->ats.array[at_j]].parameters.array[0].used);
- memcpy(rule_id_name + actions->array[cache->ats.array[at_j]].parameters.array[0].used + 1, actions->array[cache->ats.array[at_j]].parameters.array[1].string, actions->array[cache->ats.array[at_j]].parameters.array[1].used);
+ memcpy(id_rule_name, entry_action->parameters.array[0].string, entry_action->parameters.array[0].used);
+ memcpy(id_rule_name + entry_action->parameters.array[0].used + 1, entry_action->parameters.array[1].string, entry_action->parameters.array[1].used);
- rule_id_name[actions->array[cache->ats.array[at_j]].parameters.array[0].used] = f_path_separator_s[0];
- rule_id_name[rule_id_length] = 0;
+ id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s[0];
+ id_rule_name[id_rule_length] = 0;
f_thread_lock_read(&thread_data.thread->lock.rule);
- at = controller_rule_find_loaded(rule_id, thread_data);
-
- const f_array_length_t used = thread_data.setting->rules.used;
-
- f_thread_unlock(&thread_data.thread->lock.rule);
+ at = controller_rule_find_loaded(id_rule, thread_data);
if (simulate) {
f_thread_mutex_lock(&thread_data.thread->lock.print);
fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(thread_data.data->output.stream, "%s entry item rule '", actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule ? "Processing" : "Considering");
- fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, rule_id.string, thread_data.data->context.set.title.after->string);
+ fprintf(thread_data.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering");
+ fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, id_rule.string, thread_data.data->context.set.title.after->string);
fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]);
f_thread_mutex_unlock(&thread_data.thread->lock.print);
}
// the rule is not yet loaded, ensure that it is loaded.
- if (at == used) {
+ if (at == thread_data.setting->rules.used) {
+
+ f_thread_unlock(&thread_data.thread->lock.rule);
// rule execution will re-use the existing cache, so save the current cache.
const f_array_length_t cache_line_action = cache->action.line_action;
f_thread_lock_write(&thread_data.thread->lock.rule);
- status = controller_rule_read(rule_id, thread_data, cache, &thread_data.setting->rules.array[thread_data.setting->rules.used]);
+ status = controller_rule_read(id_rule, thread_data, cache, &thread_data.setting->rules.array[thread_data.setting->rules.used]);
// restore cache.
memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used);
f_thread_unlock(&thread_data.thread->lock.rule);
}
- if (F_status_is_error_not(status) && actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_rule) {
+ if (F_status_is_error_not(status) && entry_action->type == controller_entry_action_type_rule) {
// rule execution will re-use the existing cache, so save the current cache.
const f_array_length_t cache_line_action = cache->action.line_action;
rule_options |= controller_rule_option_simulate;
}
- if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_require) {
+ if (entry_action->code & controller_entry_rule_code_require) {
rule_options |= controller_rule_option_require;
}
- if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_wait) {
+ if (entry_action->code & controller_entry_rule_code_wait) {
rule_options |= controller_rule_option_wait;
}
- if (actions->array[cache->ats.array[at_j]].code & controller_entry_rule_code_asynchronous) {
+ if (entry_action->code & controller_entry_rule_code_asynchronous) {
rule_options |= controller_rule_option_asynchronous;
- // @todo this function will need to do the same process prep work as is done right before controller_rule_process().
- status = controller_rule_process_asynchronous(at, controller_rule_action_type_start, rule_options, thread_data, cache);
+ // @todo
+ //status = controller_rule_process_asynchronous(id_rule, controller_rule_action_type_start, rule_options, thread_data, cache);
}
else {
-
- f_array_length_t at_process = 0;
-
- f_thread_lock_read(&thread_data.thread->lock.process);
-
- if (controller_find_process(rule_id, *thread_data.processs, &at_process) == F_false) {
- f_thread_unlock(&thread_data.thread->lock.process);
- f_thread_lock_write(&thread_data.thread->lock.process);
-
- status = controller_processs_increase(thread_data.processs);
-
- if (F_status_is_error(status)) {
- controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, thread_data.thread);
- }
- else {
- at_process = thread_data.processs->used;
- }
- }
-
- f_thread_unlock(&thread_data.thread->lock.process);
-
- if (F_status_is_error_not(status)) {
- f_thread_lock_write(&thread_data.processs->array[at_process].lock);
-
- controller_rule_t rule = controller_rule_t_initialize;
-
- status = controller_rule_copy(thread_data.setting->rules.array[at], &rule);
-
- f_thread_condition_signal(&thread_data.processs->array[at_process].wait);
- f_thread_unlock(&thread_data.processs->array[at_process].lock);
-
- status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, cache);
-
- controller_rule_delete_simple(&rule);
- }
+ // @todo
+ // status = controller_rule_process(id_rule, controller_rule_action_type_start, rule_options, thread_data, cache);
}
// restore cache.
cache->action.line_action = cache_line_action;
cache->action.line_item = cache_line_item;
- if (status == F_child || status == F_signal) break;
- }
-
- // @todo this may need to be relocated (currently it may result in multiple error messages due to other messages being printed above.)
- if (F_status_is_error(status)) {
- f_thread_mutex_lock(&thread_data.thread->lock.print);
-
- controller_entry_error_print_cache(thread_data.data->error, cache->action);
-
- f_thread_mutex_unlock(&thread_data.thread->lock.print);
-
- if (!simulate || F_status_set_fine(status) == F_memory_not) {
+ if (!simulate || F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal) {
break;
}
}
}
- else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_timeout) {
+ else if (entry_action->type == controller_entry_action_type_timeout) {
if (simulate) {
f_string_t code = "";
- if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) {
+ if (entry_action->code == controller_entry_timeout_code_kill) {
code = controller_string_kill_s;
}
- else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_start) {
+ else if (entry_action->code == controller_entry_timeout_code_start) {
code = controller_string_start_s;
}
- else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_stop) {
+ else if (entry_action->code == controller_entry_timeout_code_stop) {
code = controller_string_stop_s;
}
fprintf(thread_data.data->output.stream, "' setting '");
fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.important.before->string, code, thread_data.data->context.set.important.after->string);
fprintf(thread_data.data->output.stream, "' to '");
- fprintf(thread_data.data->output.stream, "%s%llu%s", thread_data.data->context.set.important.before->string, actions->array[cache->ats.array[at_j]].number, thread_data.data->context.set.important.after->string);
+ fprintf(thread_data.data->output.stream, "%s%llu%s", thread_data.data->context.set.important.before->string, entry_action->number, thread_data.data->context.set.important.after->string);
fprintf(thread_data.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
f_thread_mutex_unlock(&thread_data.thread->lock.print);
}
- if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_kill) {
- thread_data.setting->timeout_kill = actions->array[cache->ats.array[at_j]].number;
+ if (entry_action->code == controller_entry_timeout_code_kill) {
+ thread_data.setting->timeout_kill = entry_action->number;
}
- else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_start) {
- thread_data.setting->timeout_start = actions->array[cache->ats.array[at_j]].number;
+ else if (entry_action->code == controller_entry_timeout_code_start) {
+ thread_data.setting->timeout_start = entry_action->number;
}
- else if (actions->array[cache->ats.array[at_j]].code == controller_entry_timeout_code_stop) {
- thread_data.setting->timeout_stop = actions->array[cache->ats.array[at_j]].number;
+ else if (entry_action->code == controller_entry_timeout_code_stop) {
+ thread_data.setting->timeout_stop = entry_action->number;
}
}
- else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_failsafe) {
+ else if (entry_action->type == controller_entry_action_type_failsafe) {
- if (actions->array[cache->ats.array[at_j]].number == 0 || actions->array[cache->ats.array[at_j]].number >= thread_data.setting->entry.items.used) {
+ if (entry_action->number == 0 || entry_action->number >= thread_data.setting->entry.items.used) {
// This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
fprintf(thread_data.data->error.to.stream, "%s%sInvalid entry item index ", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s);
- fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].number, thread_data.data->error.notable.after->string);
+ fprintf(thread_data.data->error.to.stream, "%s%s%llu%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, entry_action->number, thread_data.data->error.notable.after->string);
fprintf(thread_data.data->error.to.stream, "%s detected.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
controller_entry_error_print_cache(thread_data.data->error, cache->action);
}
else {
thread_data.setting->failsafe_enabled = F_true;
- thread_data.setting->failsafe_rule_id = actions->array[cache->ats.array[at_j]].number;
+ thread_data.setting->failsafe_rule_id = entry_action->number;
if (simulate) {
f_thread_mutex_lock(&thread_data.thread->lock.print);
}
} // for
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
status = F_signal;
}
}
// end of actions found, so drop to previous loop in stack.
- if (cache->ats.array[at_j] == actions->used) {
+ if (cache->ats.array[at_j] == entry_actions->used) {
// all actions for "main" are processed so there is nothing left to do.
if (at_i == 0) break;
for (; i < cache->object_items.used; ++i) {
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
return F_signal;
}
for (j = 0; j < thread_data.setting->entry.items.array[i].actions.used; ++j) {
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
return F_signal;
}
for (i = 0; i < rule->items.used; ++i) {
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
status = F_signal;
break;
}
for (j = 0; j < rule->items.array[i].actions.used; ++j) {
- if (thread_data.setting->signal) {
+ if (thread_data.thread->signal) {
status = F_signal;
break;
}
}
#endif // _di_controller_rule_execute_pid_with_
+// @todo consider changing this to accept "at" as an argument and returning status so that error status can be returned.
#ifndef _di_controller_rule_find_loaded_
f_array_length_t controller_rule_find_loaded(const f_string_static_t rule_id, controller_thread_data_t thread_data) {
}
#endif // _di_controller_rule_process_
+#ifndef _di_controller_rule_process_do_
+ f_status_t controller_rule_process_do(const controller_rule_t rule, const f_array_length_t at_process, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) {
+
+ f_array_length_t at_process = 0;
+
+ f_thread_lock_read(&thread_data.thread->lock.process);
+
+ if (controller_find_process(rule_id, *thread_data.processs, &at_process) == F_false) {
+ f_thread_unlock(&thread_data.thread->lock.process);
+ f_thread_lock_write(&thread_data.thread->lock.process);
+
+ status = controller_processs_increase(thread_data.processs);
+
+ if (F_status_is_error(status)) {
+ controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, thread_data.thread);
+ }
+ else {
+ at_process = thread_data.processs->used;
+ }
+ }
+
+ f_thread_unlock(&thread_data.thread->lock.process);
+
+ if (F_status_is_error_not(status)) {
+
+ // retrieve a copy of the rule and use that for the lifespan of the rule's execution within the designated process.
+ controller_rule_t rule = controller_rule_t_initialize;
+
+ status = controller_rule_copy(thread_data.setting->rules.array[at], &rule);
+
+ f_thread_unlock(&thread_data.thread->lock.rule);
+
+ if (F_status_is_error(status)) {
+ controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_rule_copy", F_true, thread_data.thread);
+ }
+ else {
+ status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, cache);
+
+ controller_rule_delete_simple(&rule);
+
+ if (F_status_is_error(status)) {
+ f_thread_mutex_lock(&thread_data.thread->lock.print);
+
+ controller_entry_error_print_cache(thread_data.data->error, cache->action);
+
+ f_thread_mutex_unlock(&thread_data.thread->lock.print);
+ }
+ }
+ }
+ }
+#endif // _di_controller_rule_process_do_
+
#ifndef _di_controller_rule_process_asynchronous_
- f_status_t controller_rule_process_asynchronous(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) {
+ f_status_t controller_rule_process_asynchronous(const f_string_static_t id_rule, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) {
- f_thread_mutex_lock(&thread_data->lock.asynchronous);
+ f_thread_lock_read(&thread_data.lock.asynchronous);
if (!thread_data.thread->enabled) {
- f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous);
+ f_thread_mutex_unlock(&thread_data.lock.asynchronous);
return F_signal;
}
+ f_thread_mutex_unlock(&thread_data.lock.asynchronous);
+ f_thread_lock_write(&thread_data.lock.asynchronous);
+
f_status_t status = controller_asynchronouss_increase(&thread_data.thread->asynchronouss);
if (F_status_is_error(status)) {
+ controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "controller_asynchronouss_increase", F_true, thread_data.thread);
+
f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous);
return status;
controller_asynchronous_t *asynchronous = &thread_data.thread->asynchronouss.array[thread_data.thread->asynchronouss.used++];
- controller_macro_asynchronous_t_clear((*asynchronous));
+ f_thread_lock_read(&thread_data.lock.process);
- asynchronous->index = index;
- asynchronous->state = controller_asynchronous_state_active;
- asynchronous->action = action;
- asynchronous->options = options;
- asynchronous->thread_data.thread = (void *) thread_data.thread;
- asynchronous->cache.line_action = thread_data.thread->cache_action->line_action;
- asynchronous->cache.line_item = thread_data.thread->cache_action->line_item;
+ if (controller_find_process(id_rule, *thread_data.processs, &asynchronous->id_process) == F_true) {
- status = f_string_dynamic_append(thread_data.thread->cache_action->name_action, &asynchronous->cache.name_action);
-
- if (F_status_is_error_not(status)) {
- status = f_string_dynamic_append(thread_data.thread->cache_action->name_file, &asynchronous->cache.name_file);
+ // use read locks to designate that the process is in use.
+ f_thread_lock_read(&thread_data.processs->array[asynchronous->id_process].lock);
}
+ else {
- if (F_status_is_error_not(status)) {
- status = f_string_dynamic_append(thread_data.thread->cache_action->name_item, &asynchronous->cache.name_item);
+ status = F_status_set_error(F_failure);
+
+ if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&thread_main->thread->lock.print);
+
+ fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(thread_data.data->output.stream, "The entry item rule '");
+ fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, id_rule.string, thread_data.data->context.set.title.after->string);
+ fprintf(thread_data.data->output.stream, "' is no longer loaded.%c", f_string_eol_s[0]);
+
+ controller_entry_error_print_cache(thread_data.data->error, cache->action);
+
+ f_thread_mutex_unlock(&thread_data.thread->lock.print);
+ }
}
+ f_thread_unlock(&thread_data.lock.process);
+
if (F_status_is_error_not(status)) {
- status = f_thread_create(0, &asynchronous->id, controller_thread_asynchronous, (void *) asynchronous);
+
+ asynchronous->state = controller_asynchronous_state_active;
+ asynchronous->action = action;
+ asynchronous->options = options;
+ asynchronous->thread_data.thread = (void *) thread_data.thread;
+ //asynchronous->stack.used = 0; // @todo stack should be passed along each call!, might be better to make this a pointer. Maybe make this a id of process id?
+
+ f_macro_time_spec_t_clear(asynchronous->cache.timestamp)
+ f_macro_string_range_t_clear(asynchronous->cache.range_action)
+
+ asynchronous->cache.ats.used = 0;
+ asynchronous->cache.stack.used = 0;
+ asynchronous->cache.comments.used = 0;
+ asynchronous->cache.delimits.used = 0;
+ asynchronous->cache.content_action.used = 0;
+ asynchronous->cache.content_actions.used = 0;
+ asynchronous->cache.content_items.used = 0;
+ asynchronous->cache.object_actions.used = 0;
+ asynchronous->cache.object_items.used = 0;
+ asynchronous->cache.buffer_file.used = 0;
+ asynchronous->cache.buffer_item.used = 0;
+ asynchronous->cache.buffer_path.used = 0;
+ asynchronous->cache.action.used = 0;
+ asynchronous->cache.line_action = thread_data.thread->cache_action->line_action;
+ asynchronous->cache.line_item = thread_data.thread->cache_action->line_item;
+
+ if (F_status_is_error_not(status)) {
+ status = f_string_dynamic_append(thread_data.thread->cache_action->name_action, &asynchronous->cache.name_action);
+
+ if (F_status_is_error_not(status)) {
+ status = f_string_dynamic_append(thread_data.thread->cache_action->name_file, &asynchronous->cache.name_file);
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = f_string_dynamic_append(thread_data.thread->cache_action->name_item, &asynchronous->cache.name_item);
+ }
+ else {
+ controller_entry_error_print(thread_data.data->error, asynchronous->cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, thread_data.thread);
+ }
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = f_thread_create(0, &asynchronous->id, controller_thread_asynchronous_process, (void *) asynchronous);
+ }
}
if (F_status_is_error(status)) {
- controller_macro_asynchronous_t_delete_simple((*asynchronous));
+ controller_entry_error_print(thread_data.data->error, asynchronous->cache->action, F_status_set_fine(status), "f_thread_create", F_true, thread_data.thread);
+
+ controller_asynchronous_delete_simple(asynchronous);
thread_data.thread->asynchronouss.used--;
}
- f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous);
+ f_thread_unlock(&thread_data->lock.asynchronous);
if (F_status_is_error(status)) {
return status;
*
* This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array.
*
- * @param index
- * Position in the rules array representing the rule to execute
+ * @param id_rule
+ * The ID of the rule, such as "boot/init".
* @param action
* The action to perform based on the action type codes.
*
* Errors (with error bit) from: f_thread_create().
*/
#ifndef _di_controller_rule_process_asynchronous_
- extern f_status_t controller_rule_process_asynchronous(const f_array_length_t index, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+ extern f_status_t controller_rule_process_asynchronous(const f_string_static_t id_rule, const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_process_asynchronous_
/**
extern "C" {
#endif
-#ifndef _di_controller_thread_asynchronous_
- void * controller_thread_asynchronous(void *arguments) {
+#ifndef _di_controller_thread_asynchronous_process_
+ void * controller_thread_asynchronous_process(void *arguments) {
controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) arguments;
- controller_thread_t *thread_main = (controller_thread_t *) asynchronous->thread;
+ controller_thread_t *main = (controller_thread_t *) asynchronous->thread;
+
+ f_thread_lock_read(&main->lock.asynchronous);
+
+ if (!main->enabled) {
+ f_thread_unlock(&main->lock.asynchronous);
- if (!thread_main->enabled) {
return 0;
}
- controller_thread_t thread = controller_thread_t_initialize;
+ f_thread_unlock(&main->lock.asynchronous);
- f_thread_mutex_lock(&thread_main->setting->rules.array[asynchronous->index].lock);
- f_thread_mutex_lock(&asynchronous->lock);
+ f_array_length_t at_process = 0;
- thread.cache_main = thread_main->cache_main;
- thread.cache_action = &asynchronous->cache;
- thread.data = thread_main->data;
- thread.lock = thread_main->lock;
- thread.setting = thread_main->setting;
- thread.stack = &asynchronous->stack;
+ f_thread_lock_read(&main->thread->lock.process);
- if (controller_rule_process(asynchronous->index, asynchronous->action, asynchronous->options, &thread, asynchronous) != F_child) {
- asynchronous->state = controller_asynchronous_state_done;
+ if (controller_find_process(rule.id, *main->processs, &at_process) == F_false) {
+ f_thread_unlock(&main->thread->lock.process);
+ f_thread_lock_write(&main->thread->lock.process);
+
+ const f_status_t status = controller_processs_increase(main->processs);
+
+ if (F_status_is_error(status)) {
+ controller_entry_error_print(main->data->error, asynchronous->cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, main->thread);
+
+ f_thread_unlock(&main->thread->lock.process);
+ return 0;
+ }
+ else {
+ at_process = main->processs->used++;
+ }
}
- f_thread_mutex_unlock(&asynchronous->lock);
+ // once the "active" lock is in place for some process, then it will not be deleted and should be guaranteed to not change or be relocated.
+ f_thread_lock_read(&main->processs.array[id_process].active);
+ f_thread_unlock(&main->thread->lock.process);
+
+ // @todo looks like I do need a r/w lock on controller_asynchronous_t after all.
- f_thread_condition_signal(&thread_main->setting->rules.array[asynchronous->index].wait);
- f_thread_mutex_unlock(&thread_main->setting->rules.array[asynchronous->index].lock);
+ controller_rule_t rule = controller_rule_t_initialize;
+
+ // @todo copy rule, finding the rule using main->processs.array[id_process].id_rule.
+ //status = controller_rule_copy(, &rule);
+
+ {
+ const f_status_t status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, asynchronous->cache);
+
+ asynchronous->state = controller_asynchronous_state_done;
+
+ if (F_status_is_error(status)) {
+ f_thread_mutex_lock(&thread_data.thread->lock.print);
+
+ controller_entry_error_print_cache(thread_data.data->error, asynchronous->cache->action);
+
+ f_thread_mutex_unlock(&thread_data.thread->lock.print);
+ }
+ }
+
+ f_thread_unlock(&main->processs.array[id_process].active);
return 0;
}
-#endif // _di_controller_thread_asynchronous_
+#endif // _di_controller_thread_asynchronous_process_
#ifndef _di_controller_thread_asynchronous_cancel_
void controller_thread_asynchronous_cancel(controller_thread_t *thread) {
controller_thread_t thread = controller_thread_t_initialize;
controller_processs_t processs = controller_processs_t_initialize;
- controller_thread_data_t data_main = controller_macro_thread_data_t_initialize(0, data, setting, &processs, &thread);
+ controller_thread_data_t thread_data = controller_macro_thread_data_t_initialize(0, data, setting, &processs, &thread);
status = controller_asynchronouss_increase(&thread.asynchronouss);
if (F_status_is_error_not(status)) {
- status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &data_main);
+ status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &thread_data);
}
if (F_status_is_error(status)) {
}
else {
- status = controller_entry_read(entry_name, data_main, &thread.asynchronouss.array[0].cache);
+ // index 0 is reserved for running the main thread cache.
+ thread.asynchronouss.used = 1;
+
+ status = controller_entry_read(entry_name, thread_data, &thread.asynchronouss.array[0].cache);
if (F_status_is_error(status)) {
setting->ready = controller_setting_ready_fail;
}
else if (status != F_signal && status != F_child) {
- status = controller_preprocess_entry(data_main, &thread.asynchronouss.array[0].cache);
+ status = controller_preprocess_entry(thread_data, &thread.asynchronouss.array[0].cache);
}
if (F_status_is_error_not(status) && status != F_signal && status != F_child) {
status = F_status_set_error(F_available_not);
}
else {
- status = controller_process_entry(data_main, &thread.asynchronouss.array[0].cache);
+ status = controller_process_entry(thread_data, &thread.asynchronouss.array[0].cache);
if (F_status_is_error(status)) {
setting->ready = controller_setting_ready_fail;
if (data->parameters[controller_parameter_validate].result == f_console_result_none) {
controller_rule_wait_all(&thread);
- status = f_thread_create(0, &thread.id_rule, &controller_thread_rule, (void *) &data_main);
+ status = f_thread_create(0, &thread.id_rule, &controller_thread_rule, (void *) &thread_data);
if (F_status_is_error_not(status)) {
- status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &data_main);
+ status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &thread_data);
}
if (F_status_is_error_not(status)) {
- status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &data_main);
+ status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &thread_data);
}
if (F_status_is_error(status)) {
if (thread_data->data->parameters[controller_parameter_interruptable].result == f_console_result_found) {
if (signal == F_signal_interrupt || signal == F_signal_abort || signal == F_signal_quit || signal == F_signal_termination) {
- thread_data->setting->signal = signal;
+ thread_data->thread->signal = signal;
controller_thread_asynchronous_cancel(thread_data->thread);
break;
* @return
* 0, always.
*/
-#ifndef _di_controller_thread_asynchronous_
- extern void * controller_thread_asynchronous(void *arguments) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_thread_asynchronous_
+#ifndef _di_controller_thread_asynchronous_process_
+ extern void * controller_thread_asynchronous_process(void *arguments) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_thread_asynchronous_process_
/**
* Cancel all asynchronous threads.