]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Wed, 24 Mar 2021 03:57:47 +0000 (22:57 -0500)
committerKevin Day <thekevinday@gmail.com>
Wed, 24 Mar 2021 03:57:47 +0000 (22:57 -0500)
level_3/controller/c/private-common.c
level_3/controller/c/private-common.h
level_3/controller/c/private-controller.c
level_3/controller/c/private-entry.c
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/c/private-thread.c
level_3/controller/c/private-thread.h

index 3ed2c031b52b2534394a005dfe3753c2e612ac2e..4a5e6ae1011214532f3295b3e4c44e985b0dd32a 100644 (file)
@@ -150,11 +150,13 @@ extern "C" {
 #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_
 
index df59d78438bc4d051ea10ad467b0672779eef463..ac709f145357de4cb810b475dac0785d9dd895ac 100644 (file)
 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"
@@ -274,6 +279,11 @@ extern "C" {
   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,
@@ -295,6 +305,12 @@ extern "C" {
   };
 #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;
@@ -319,10 +335,19 @@ extern "C" {
 /**
  * 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 {
@@ -349,6 +374,14 @@ extern "C" {
   }
 #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)"
@@ -399,6 +432,13 @@ extern "C" {
     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;
@@ -419,6 +459,13 @@ extern "C" {
     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,
@@ -447,6 +494,13 @@ extern "C" {
     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;
@@ -467,6 +521,35 @@ extern "C" {
     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,
@@ -592,6 +675,13 @@ extern "C" {
     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;
@@ -613,37 +703,46 @@ extern "C" {
 #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;
@@ -664,6 +763,16 @@ extern "C" {
     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,
@@ -712,6 +821,13 @@ extern "C" {
     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;
@@ -732,6 +848,13 @@ extern "C" {
     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;
@@ -753,6 +876,13 @@ extern "C" {
     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;
@@ -773,6 +903,12 @@ extern "C" {
     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;
@@ -790,6 +926,22 @@ extern "C" {
     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,
@@ -803,7 +955,6 @@ extern "C" {
   typedef struct {
     bool interruptable;
     uint8_t ready;
-    int signal;
 
     f_number_unsigned_t timeout_kill;
     f_number_unsigned_t timeout_start;
@@ -823,7 +974,6 @@ extern "C" {
   #define controller_setting_t_initialize { \
     F_false, \
     0, \
-    0, \
     3, \
     3, \
     3, \
@@ -839,7 +989,6 @@ extern "C" {
   #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; \
@@ -852,6 +1001,16 @@ extern "C" {
     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;
@@ -882,6 +1041,25 @@ extern "C" {
     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;
@@ -924,26 +1102,25 @@ extern "C" {
     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,
@@ -953,10 +1130,8 @@ extern "C" {
 
   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;
@@ -968,8 +1143,6 @@ extern "C" {
 
   #define controller_asynchronous_t_initialize { \
     f_thread_id_t_initialize, \
-    f_thread_lock_t_initialize, \
-    f_thread_lock_attribute_t_initialize, \
     0, \
     0, \
     0, \
@@ -978,19 +1151,15 @@ extern "C" {
     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;
@@ -1011,9 +1180,26 @@ extern "C" {
     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;
@@ -1026,6 +1212,7 @@ extern "C" {
 
   #define controller_thread_t_initialize { \
     F_true, \
+    0, \
     f_thread_id_t_initialize, \
     f_thread_id_t_initialize, \
     f_thread_id_t_initialize, \
@@ -1036,6 +1223,7 @@ extern "C" {
 
   #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, \
@@ -1046,6 +1234,7 @@ extern "C" {
 
   #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); \
@@ -1053,6 +1242,15 @@ extern "C" {
     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.
@@ -1063,7 +1261,7 @@ extern "C" {
   #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;
@@ -1073,8 +1271,8 @@ extern "C" {
 
   #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, \
@@ -1082,7 +1280,7 @@ extern "C" {
   }
 
   #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; \
index d188ced2b5a976ac4d46f93c764b40b2815d14db..24e82ca0b27dc22ab81e474c2461f5317e45d95a 100644 (file)
@@ -259,7 +259,7 @@ extern "C" {
 
     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;
       }
@@ -451,7 +451,7 @@ extern "C" {
 
       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;
         }
 
@@ -639,8 +639,8 @@ extern "C" {
 
     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;
@@ -697,19 +697,21 @@ extern "C" {
     //       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);
@@ -717,9 +719,9 @@ extern "C" {
           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);
@@ -728,18 +730,18 @@ extern "C" {
               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);
@@ -748,9 +750,9 @@ extern "C" {
                 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);
@@ -773,9 +775,9 @@ extern "C" {
               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);
@@ -797,10 +799,10 @@ extern "C" {
               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);
               }
 
@@ -815,9 +817,9 @@ extern "C" {
               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);
@@ -833,7 +835,7 @@ extern "C" {
           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) {
 
@@ -865,9 +867,9 @@ extern "C" {
             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) {
@@ -875,7 +877,7 @@ extern "C" {
 
               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);
@@ -895,7 +897,7 @@ extern "C" {
           }
 
           // 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;
@@ -931,7 +933,7 @@ extern "C" {
           // 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);
 
@@ -941,37 +943,35 @@ extern "C" {
             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;
@@ -991,7 +991,7 @@ extern "C" {
 
             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);
@@ -1032,7 +1032,7 @@ extern "C" {
             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;
@@ -1056,56 +1056,23 @@ extern "C" {
               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.
@@ -1124,34 +1091,23 @@ extern "C" {
             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;
             }
 
@@ -1163,25 +1119,25 @@ extern "C" {
             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) {
@@ -1189,7 +1145,7 @@ extern "C" {
 
               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);
@@ -1201,7 +1157,7 @@ extern "C" {
           }
           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);
@@ -1219,7 +1175,7 @@ extern "C" {
         }
       } // for
 
-      if (thread_data.setting->signal) {
+      if (thread_data.thread->signal) {
         status = F_signal;
       }
 
@@ -1235,7 +1191,7 @@ extern "C" {
       }
 
       // 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;
index d2f52477e64d13080566333a38daaa6a06458ea6..7f42a2284f4c20a071b1c6438f93884786aa056d 100644 (file)
@@ -702,7 +702,7 @@ extern "C" {
 
         for (; i < cache->object_items.used; ++i) {
 
-          if (thread_data.setting->signal) {
+          if (thread_data.thread->signal) {
             return F_signal;
           }
 
@@ -853,7 +853,7 @@ extern "C" {
 
               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;
                 }
 
index 3dfdc0f195436a05456a1a3684acd64431b2e785..7c8e72906d538f14fdd7c9ca0e43352bafd89de9 100644 (file)
@@ -770,7 +770,7 @@ extern "C" {
 
     for (i = 0; i < rule->items.used; ++i) {
 
-      if (thread_data.setting->signal) {
+      if (thread_data.thread->signal) {
         status = F_signal;
         break;
       }
@@ -779,7 +779,7 @@ extern "C" {
 
       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;
         }
@@ -1109,6 +1109,7 @@ extern "C" {
   }
 #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) {
 
@@ -1985,20 +1986,77 @@ extern "C" {
   }
 #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;
@@ -2006,37 +2064,89 @@ extern "C" {
 
     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;
index be56f00d4260c8eefcdc5d8296046854359aed17..76b203ba1f5c1d19d2457dcb765c67df73f773d8 100644 (file)
@@ -593,8 +593,8 @@ extern "C" {
  *
  * 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.
  *
@@ -623,7 +623,7 @@ extern "C" {
  *   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_
 
 /**
index 53eefb6f7d7ea2a1cdb3236b009e147f42ca4fe6..e9be5607cb94e6ca3544ebb81aa9f67f658c6fe2 100644 (file)
@@ -9,40 +9,73 @@
 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) {
@@ -174,12 +207,12 @@ extern "C" {
 
     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)) {
@@ -210,13 +243,16 @@ extern "C" {
       }
       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) {
@@ -238,7 +274,7 @@ extern "C" {
               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;
@@ -271,14 +307,14 @@ extern "C" {
       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)) {
@@ -358,7 +394,7 @@ extern "C" {
 
       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;
index 99e7f80480825653bc9973a058e9a119f55b472b..22051b38ecc180ac0405b6a5658b843935e07453 100644 (file)
@@ -22,9 +22,9 @@ extern "C" {
  * @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.