]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Mon, 29 Mar 2021 01:34:45 +0000 (20:34 -0500)
committerKevin Day <thekevinday@gmail.com>
Mon, 29 Mar 2021 01:34:45 +0000 (20:34 -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-controller.h
level_3/controller/c/private-entry.c
level_3/controller/c/private-entry.h
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 4a5e6ae1011214532f3295b3e4c44e985b0dd32a..319f9112ad9b957b0a99d85006857732c28d7e0a 100644 (file)
@@ -5,59 +5,6 @@
 extern "C" {
 #endif
 
-#ifndef _di_controller_asynchronous_delete_simple_
-  void controller_asynchronous_delete_simple(controller_asynchronous_t *asynchronous) {
-
-    f_macro_array_lengths_t_delete_simple(asynchronous->stack)
-
-    controller_cache_delete_simple(&asynchronous->cache);
-  }
-#endif // _di_controller_asynchronous_delete_simple_
-
-#ifndef _di_controller_asynchronouss_increase_
-  f_status_t controller_asynchronouss_increase(controller_asynchronouss_t *asynchronouss) {
-
-    if (asynchronouss->used + 1 > asynchronouss->size) {
-      f_array_length_t size = asynchronouss->used + controller_default_allocation_step;
-
-      if (size > f_array_length_t_size) {
-        if (asynchronouss->used + 1 > f_array_length_t_size) {
-          return F_status_set_error(F_array_too_large);
-        }
-
-        size = f_array_length_t_size;
-      }
-
-      return controller_asynchronouss_resize(size, asynchronouss);
-    }
-
-    return F_data_not;
-  }
-#endif // _di_controller_asynchronous_increase_
-
-#ifndef _di_controller_asynchronouss_resize_
-  f_status_t controller_asynchronouss_resize(const f_array_length_t length, controller_asynchronouss_t *asynchronouss) {
-
-    f_status_t status = F_none;
-
-    for (f_array_length_t i = length; i < asynchronouss->size; ++i) {
-      controller_asynchronous_delete_simple(&asynchronouss->array[i]);
-    } // for
-
-    status = f_memory_resize(asynchronouss->size, length, sizeof(controller_asynchronous_t), (void **) & asynchronouss->array);
-
-    if (F_status_is_error_not(status)) {
-      asynchronouss->size = length;
-
-      if (asynchronouss->used > asynchronouss->size) {
-        asynchronouss->used = length;
-      }
-    }
-
-    return status;
-  }
-#endif // _di_controller_asynchronouss_resize_
-
 #ifndef _di_controller_cache_action_delete_simple_
   void controller_cache_action_delete_simple(controller_cache_action_t *cache) {
 
@@ -147,16 +94,49 @@ extern "C" {
   }
 #endif // _di_controller_error_print_
 
+#ifndef _di_controller_lock_create_
+  f_status_t controller_lock_create(controller_lock_t *lock) {
+
+    f_status_t status = f_thread_mutex_create(0, &lock->print);
+    if (F_status_is_error(status)) return status;
+
+    status = f_thread_lock_create(0, &lock->entry);
+    if (F_status_is_error(status)) return status;
+
+    status = f_thread_lock_create(0, &lock->process);
+    if (F_status_is_error(status)) return status;
+
+    status = f_thread_lock_create(0, &lock->rule);
+    if (F_status_is_error(status)) return status;
+
+    return F_none;
+  }
+#endif // _di_controller_lock_create_
+
+#ifndef _di_controller_lock_delete_simple_
+  void controller_lock_delete_simple(controller_lock_t *lock) {
+
+    f_thread_mutex_delete(&lock->print);
+
+    f_thread_lock_delete(&lock->entry);
+    f_thread_lock_delete(&lock->process);
+    f_thread_lock_delete(&lock->rule);
+  }
+#endif // _di_controller_lock_delete_simple_
+
 #ifndef _di_controller_process_delete_simple_
   void controller_process_delete_simple(controller_process_t *process) {
 
-    f_string_dynamic_resize(0, &process->id_rule);
+    f_string_dynamic_resize(0, &process->alias_rule);
 
     f_thread_lock_delete(&process->lock);
     f_thread_lock_delete(&process->active);
+    f_thread_mutex_delete(&process->running);
+    f_thread_condition_delete(&process->wait);
+
+    controller_cache_delete_simple(&process->cache);
 
-    f_thread_lock_attribute_delete(&process->lock_attribute);
-    f_thread_lock_attribute_delete(&process->active_attribute);
+    f_macro_array_lengths_t_delete_simple(process->stack)
   }
 #endif // _di_controller_process_delete_simple_
 
@@ -200,6 +180,32 @@ extern "C" {
     status = f_memory_resize(processs->size, length, sizeof(controller_process_t), (void **) & processs->array);
 
     if (F_status_is_error_not(status)) {
+
+      // the lock must be initialized, but only once, so initialize immediately upon allocation.
+      while (processs->size < length) {
+
+        status = f_thread_lock_create(0, &processs->array[processs->size].lock);
+
+        if (F_status_is_error_not(status)) {
+          status = f_thread_lock_create(0, &processs->array[processs->size].active);
+        }
+
+        if (F_status_is_error_not(status)) {
+          status = f_thread_mutex_create(0, &processs->array[processs->size].running);
+        }
+
+        if (F_status_is_error_not(status)) {
+          status = f_thread_condition_create(0, &processs->array[processs->size].wait);
+        }
+
+        ++processs->size;
+
+        if (F_status_is_error(status)) {
+          processs->size = length;
+          return status;
+        }
+      } // while
+
       processs->size = length;
 
       if (processs->used > processs->size) {
@@ -235,7 +241,7 @@ extern "C" {
 #ifndef _di_controller_rule_delete_simple_
   void controller_rule_delete_simple(controller_rule_t *rule) {
 
-    f_string_dynamic_resize(0, &rule->id);
+    f_string_dynamic_resize(0, &rule->alias);
     f_string_dynamic_resize(0, &rule->name);
     f_string_dynamic_resize(0, &rule->path);
     f_string_dynamic_resize(0, &rule->script);
@@ -346,18 +352,8 @@ extern "C" {
 #ifndef _di_controller_thread_delete_simple_
   void controller_thread_delete_simple(controller_thread_t *thread) {
 
-    f_thread_mutex_delete(&thread->lock.print);
-
-    f_thread_lock_delete(&thread->lock.asynchronous);
-    f_thread_lock_attribute_delete(&thread->lock.asynchronous_attribute);
-
-    f_thread_lock_delete(&thread->lock.process);
-    f_thread_lock_attribute_delete(&thread->lock.process_attribute);
-
-    f_thread_lock_delete(&thread->lock.rule);
-    f_thread_lock_attribute_delete(&thread->lock.rule_attribute);
-
-    controller_asynchronouss_resize(0, &thread->asynchronouss);
+    controller_lock_delete_simple(&thread->lock);
+    controller_processs_resize(0, &thread->processs);
   }
 #endif // _di_controller_thread_delete_simple_
 
index ac709f145357de4cb810b475dac0785d9dd895ac..ebab445247514e0c38c14d0ba7fdac04d97d3257 100644 (file)
@@ -306,6 +306,109 @@ extern "C" {
 #endif // _di_controller_resource_limit_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_array_length_t line_item;
+
+    f_string_dynamic_t name_action;
+    f_string_dynamic_t name_file;
+    f_string_dynamic_t name_item;
+
+    f_string_dynamic_t generic;
+  } controller_cache_action_t;
+
+  #define controller_cache_action_t_initialize { \
+    0, \
+    0, \
+    f_string_dynamic_t_initialize, \
+    f_string_dynamic_t_initialize, \
+    f_string_dynamic_t_initialize, \
+    f_string_dynamic_t_initialize, \
+  }
+
+  #define controller_macro_cache_action_t_clear(cache) \
+    cache.line_action = 0; \
+    cache.line_item = 0; \
+    f_macro_string_dynamic_t_clear(cache.name_action) \
+    f_macro_string_dynamic_t_clear(cache.name_file) \
+    f_macro_string_dynamic_t_clear(cache.name_item) \
+    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_range_t range_action;
+
+    f_array_lengths_t ats;
+    f_array_lengths_t stack;
+
+    f_fss_comments_t comments;
+    f_fss_delimits_t delimits;
+
+    f_fss_content_t content_action;
+    f_fss_contents_t content_actions;
+    f_fss_contents_t content_items;
+    f_fss_objects_t object_actions;
+    f_fss_objects_t object_items;
+
+    f_string_dynamic_t buffer_file;
+    f_string_dynamic_t buffer_item;
+    f_string_dynamic_t buffer_path;
+
+    controller_cache_action_t action;
+  } controller_cache_t;
+
+  #define controller_cache_t_initialize { \
+    f_time_spec_t_initialize, \
+    f_string_range_t_initialize, \
+    f_array_lengths_t_initialize, \
+    f_array_lengths_t_initialize, \
+    f_fss_comments_t_initialize, \
+    f_fss_delimits_t_initialize, \
+    f_fss_content_t_initialize, \
+    f_fss_contents_t_initialize, \
+    f_fss_contents_t_initialize, \
+    f_fss_objects_t_initialize, \
+    f_fss_objects_t_initialize, \
+    f_string_dynamic_t_initialize, \
+    f_string_dynamic_t_initialize, \
+    f_string_dynamic_t_initialize, \
+    controller_cache_action_t_initialize, \
+  }
+#endif // _di_controller_cache_t_
+
+/**
  * A structure for passing execution arguments to the execute functions.
  *
  * parameter: All parameters sent to the program on execution.
@@ -324,53 +427,37 @@ extern "C" {
 
   #define controller_macro_execute_set_t_initialize(option, environment, signals, data, as) { \
     fl_macro_execute_parameter_t_initialize(option, environment, signals, data), \
-    as \
+    as, \
   }
-
-  #define controller_macro_execute_set_t_clear(set) \
-    fl_macro_execute_parameter_t_clear(set.parameter) \
-    fl_macro_execute_as_t_clear(set.as)
 #endif // _di_controller_execute_set_t_
 
 /**
  * A structure for sharing mutexes globally between different threads.
  *
- * 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 entry lock is intended to lock any activity on the entrys structure.
  * 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.
- *
+ * print:   The print mutex lock.
+ * entry:   The entry r/w lock.
+ * process: The process r/w lock.
+ * rule:    The rule r/w lock.
  */
 #ifndef _di_controller_lock_t_
   typedef struct {
     f_thread_mutex_t print;
 
-    f_thread_lock_t asynchronous;
-    f_thread_lock_attribute_t asynchronous_attribute;
-
+    f_thread_lock_t entry;
     f_thread_lock_t process;
-    f_thread_lock_attribute_t process_attribute;
-
     f_thread_lock_t rule;
-    f_thread_lock_attribute_t rule_attribute;
   } controller_lock_t;
 
   #define controller_lock_t_initialize { \
     f_thread_mutex_t_initialize, \
     f_thread_lock_t_initialize, \
-    f_thread_lock_attribute_t_initialize, \
     f_thread_lock_t_initialize, \
-    f_thread_lock_attribute_t_initialize, \
     f_thread_lock_t_initialize, \
-    f_thread_lock_attribute_t_initialize \
   }
 #endif // _di_controller_mutex_t_
 
@@ -424,12 +511,6 @@ extern "C" {
     F_known_not, \
     f_string_dynamics_t_initialize, \
   }
-
-  #define controller_macro_rule_action_t_clear(rule) \
-    type = 0; \
-    line = 0; \
-    status = F_known_not; \
-    f_macro_string_dynamics_t_clear(rule.parameters)
 #endif // _di_controller_rule_action_t_
 
 /**
@@ -452,11 +533,6 @@ extern "C" {
     0, \
     0, \
   }
-
-  #define controller_macro_rule_actions_t_clear(actions) \
-    actions.array = 0; \
-    actions.size = 0; \
-    actions.used = 0;
 #endif // _di_controller_rule_actions_t_
 
 /**
@@ -487,11 +563,6 @@ extern "C" {
       0, \
       controller_rule_actions_t_initialize, \
     }
-
-  #define controller_macro_rule_item_t_clear(item) \
-    item.type = 0; \
-    item.line = 0; \
-    controller_macro_rule_actions_t_clear(item.actions);
 #endif // _di_controller_rule_item_t_
 
 /**
@@ -514,11 +585,6 @@ extern "C" {
     0, \
     0, \
   }
-
-  #define controller_macro_rule_items_t_clear(items) \
-    items.array = 0; \
-    items.size = 0; \
-    items.used = 0;
 #endif // _di_controller_rule_items_t_
 
 /**
@@ -596,7 +662,7 @@ extern "C" {
 
     f_time_spec_t timestamp;
 
-    f_string_dynamic_t id;
+    f_string_dynamic_t alias;
     f_string_dynamic_t name;
     f_string_dynamic_t path;
     f_string_dynamic_t script;
@@ -646,33 +712,6 @@ extern "C" {
     f_execute_scheduler_t_initialize, \
     controller_rule_items_initialize, \
   }
-
-  #define controller_macro_rule_t_clear(rule) \
-    rule.timeout_kill = 0; \
-    rule.timeout_start = 0; \
-    rule.timeout_stop = 0; \
-    rule.has = 0; \
-    rule.nice = 0; \
-    rule.user = 0; \
-    rule.group = 0; \
-    f_macro_time_spec_t_clear(rule.timestamp) \
-    f_macro_string_dynamic_t_clear(rule.id) \
-    f_macro_string_dynamic_t_clear(rule.name) \
-    f_macro_string_dynamic_t_clear(rule.path) \
-    f_macro_string_dynamic_t_clear(rule.script) \
-    f_macro_string_maps_t_clear(rule.define) \
-    f_macro_string_maps_t_clear(rule.parameter) \
-    f_macro_string_dynamics_t_clear(rule.environment) \
-    f_macro_string_dynamics_t_clear(rule.need) \
-    f_macro_string_dynamics_t_clear(rule.want) \
-    f_macro_string_dynamics_t_clear(rule.wish) \
-    f_macro_int32s_t_clear(rule.affinity) \
-    f_macro_capability_t_clear(rule.capability) \
-    f_macro_control_group_t_clear(rule.control_group) \
-    f_macro_int32s_t_clear(rule.groups) \
-    f_macro_limit_sets_t_clear(rule.limits) \
-    f_macro_execute_scheduler_t_clear(rule.scheduler) \
-    controller_macro_rule_items_t_clear(rule.items)
 #endif // _di_controller_rule_t_
 
 /**
@@ -695,11 +734,6 @@ extern "C" {
     0, \
     0, \
   }
-
-  #define controller_macro_rules_t_clear(rules) \
-    rules.array = 0; \
-    rules.size = 0; \
-    rules.used = 0;
 #endif // _di_controller_rules_t_
 
 /**
@@ -707,32 +741,80 @@ extern "C" {
  *
  * 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.
  *
- * 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".
+ * Process States:
+ * - idle:   No process is running for this rule.
+ * - busy:   A process is actively using this, and is running synchronously.
+ * - active: A process is actively using this, and is running asynchronously.
+ * - done:   A process has finished running on this and there is a thread that needs to be cleaned up.
+ *
+ * id:            The ID of this process relative to the processes array.
+ * alias_rule:    The Rule alias, such as "network/ntpdate".
+ * status:        The last execution status of the Rule.
+ * state:         The state of the process.
+ * 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).
+ * id_thread:     The thread id, a valid ID when state is "active", and an invalid ID when the state is "busy".
+ * 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 = begin deleting).
+ * running:       A mutex lock for working with "wait" to designate that the process is being executed and to trigger anything waiting when done.
+ * wait:          A thread condition to tell a process waiting process that the rule has is done being processed.
+ * cache:         The cache used in this process.
+ * stack:         A stack used to represent dependencies to avoid circular rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
+ * main_data:     Used for passing the controller_data_t data to the process thread (to populate controller_main_t).
+ * main_setting:  Used for passing the controller_setting_t data to the process thread (to populate controller_main_t).
+ * main_thread:   Used for passing the controller_thread_t data to the process thread (to populate controller_main_t).
  */
 #ifndef _di_controller_process_t_
+  enum {
+    controller_process_state_idle = 1,
+    controller_process_state_busy,
+    controller_process_state_active,
+    controller_process_state_done,
+  };
+
   typedef struct {
-    f_string_dynamic_t id_rule;
+    f_array_length_t id;
+    f_string_dynamic_t alias_rule;
 
     f_status_t status;
 
+    uint8_t state;
+    uint8_t action;
+    uint8_t options;
+    pid_t child;
+
+    f_thread_id_t id_thread;
     f_thread_lock_t lock;
     f_thread_lock_t active;
-    f_thread_lock_attribute_t lock_attribute;
-    f_thread_lock_attribute_t active_attribute;
+    f_thread_mutex_t running;
+    f_thread_condition_t wait;
+
+    controller_cache_t cache;
+    f_array_lengths_t stack;
+
+    void *main_data;
+    void *main_setting;
+    void *main_thread;
   } controller_process_t;
 
   #define controller_process_t_initialize { \
+    0, \
     f_string_dynamic_t_initialize \
     F_known_not, \
+    0, \
+    0, \
+    0, \
+    0, \
+    f_thread_id_t_initialize, \
     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, \
+    controller_cache_t_initialize, \
+    f_array_lengths_t_initialize, \
+    0, \
+    0, \
+    0, \
   }
 #endif // _di_controller_process_t_
 
@@ -756,11 +838,6 @@ extern "C" {
     0, \
     0, \
   }
-
-  #define controller_macro_processs_t_clear(process) \
-    process.array = 0; \
-    process.size = 0; \
-    process.used = 0;
 #endif // _di_controller_processs_t_
 
 /**
@@ -811,14 +888,6 @@ extern "C" {
     F_known_not, \
     f_string_dynamics_t_initialize, \
   }
-
-  #define controller_macro_entry_action_t_clear(action) \
-    action.type = 0; \
-    action.code = 0; \
-    action.line = 0; \
-    action.number = 0; \
-    action.status = F_known_not; \
-    f_macro_string_dynamics_t_clear(action.parameters)
 #endif // _di_controller_entry_action_t_
 
 /**
@@ -841,11 +910,6 @@ extern "C" {
     0, \
     0, \
   }
-
-  #define controller_macro_entry_actions_t_clear(actions) \
-    actions.array = 0; \
-    actions.size = 0; \
-    actions.used = 0;
 #endif // _di_controller_entry_actions_t_
 
 /**
@@ -869,11 +933,6 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       controller_entry_actions_t_initialize, \
     }
-
-  #define controller_macro_entry_item_t_clear(item) \
-    item.line = 0; \
-    f_macro_string_dynamic_t_clear(item.name) \
-    controller_macro_entry_actions_t_clear(item.actions)
 #endif // _di_controller_entry_item_t_
 
 /**
@@ -920,10 +979,6 @@ extern "C" {
     F_known_not, \
     controller_entry_items_t_initialize, \
   }
-
-  #define controller_macro_entry_t_clear(entry) \
-    entry.status = F_known_not; \
-    controller_macro_entry_items_t_clear(entry.items)
 #endif // _di_controller_entry_t_
 
 /**
@@ -985,216 +1040,24 @@ extern "C" {
     controller_entry_t_initialize, \
     controller_rules_t_initialize, \
   }
-
-  #define controller_macro_setting_t_clear(setting) \
-    setting.interruptable = F_false; \
-    setting.ready = 0; \
-    setting.timeout_kill = 3; \
-    setting.timeout_start = 3; \
-    setting.timeout_stop = 3; \
-    setting.failsafe_enabled = F_false; \
-    setting.failsafe_rule_id = 0; \
-    f_macro_string_dynamic_t_clear(entry.path_control) \
-    f_macro_string_dynamic_t_clear(entry.path_pid) \
-    f_macro_string_dynamic_t_clear(entry.path_setting) \
-    controller_macro_entry_t_clear(entry.entry) \
-    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_array_length_t line_item;
-
-    f_string_dynamic_t name_action;
-    f_string_dynamic_t name_file;
-    f_string_dynamic_t name_item;
-
-    f_string_dynamic_t generic;
-  } controller_cache_action_t;
-
-  #define controller_cache_action_t_initialize { \
-    0, \
-    0, \
-    f_string_dynamic_t_initialize, \
-    f_string_dynamic_t_initialize, \
-    f_string_dynamic_t_initialize, \
-    f_string_dynamic_t_initialize, \
-  }
-
-  #define controller_macro_cache_action_t_clear(cache) \
-    cache.line_action = 0; \
-    cache.line_item = 0; \
-    f_macro_string_dynamic_t_clear(cache.name_action) \
-    f_macro_string_dynamic_t_clear(cache.name_file) \
-    f_macro_string_dynamic_t_clear(cache.name_item) \
-    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_range_t range_action;
-
-    f_array_lengths_t ats;
-    f_array_lengths_t stack;
-
-    f_fss_comments_t comments;
-    f_fss_delimits_t delimits;
-
-    f_fss_content_t content_action;
-    f_fss_contents_t content_actions;
-    f_fss_contents_t content_items;
-    f_fss_objects_t object_actions;
-    f_fss_objects_t object_items;
-
-    f_string_dynamic_t buffer_file;
-    f_string_dynamic_t buffer_item;
-    f_string_dynamic_t buffer_path;
-
-    controller_cache_action_t action;
-  } controller_cache_t;
-
-  #define controller_cache_t_initialize { \
-    f_time_spec_t_initialize, \
-    f_string_range_t_initialize, \
-    f_array_lengths_t_initialize, \
-    f_array_lengths_t_initialize, \
-    f_fss_comments_t_initialize, \
-    f_fss_delimits_t_initialize, \
-    f_fss_content_t_initialize, \
-    f_fss_contents_t_initialize, \
-    f_fss_contents_t_initialize, \
-    f_fss_objects_t_initialize, \
-    f_fss_objects_t_initialize, \
-    f_string_dynamic_t_initialize, \
-    f_string_dynamic_t_initialize, \
-    f_string_dynamic_t_initialize, \
-    controller_cache_action_t_initialize, \
-  }
-#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,
-    controller_asynchronous_state_done,
-    controller_asynchronous_state_joined,
-  };
-
-  typedef struct {
-    f_thread_id_t id;
-    f_array_length_t id_process;
-
-    uint8_t state;
-    uint8_t action;
-    uint8_t options;
-    pid_t child;
-
-    f_array_lengths_t stack;
-    controller_cache_t cache;
-  } controller_asynchronous_t;
-
-  #define controller_asynchronous_t_initialize { \
-    f_thread_id_t_initialize, \
-    0, \
-    0, \
-    0, \
-    0, \
-    0, \
-    f_array_lengths_t_initialize, \
-    controller_cache_t_initialize \
-  }
-#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;
-
-    f_array_length_t size;
-    f_array_length_t used;
-  } controller_asynchronouss_t;
-
-  #define controller_asynchronouss_t_initialize { \
-    0, \
-    0, \
-    0, \
-  }
-
-  #define controller_macro_asynchronouss_t_clear(asynchronouss) \
-    asynchronouss.array = 0; \
-    asynchronouss.size = 0; \
-    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.
+ * As a special case, index 0 of processs 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.
+ * The "enabled" and "signal" utilize the lock: lock.process.
+ *
+ * enabled:    TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE.
+ * signal:     The code of any signal received.
+ * id_cleanup: The thread ID representing the Cleanup Process.
+ * id_control: The thread ID representing the Control Process.
+ * id_signal:  The thread ID representing the Signal Process.
+ * lock:       A r/w lock for operating on this structure.
+ * processs:   All Rule Process thread data.
  */
 #ifndef _di_controller_thread_t_
   typedef struct {
@@ -1203,11 +1066,10 @@ extern "C" {
 
     f_thread_id_t id_cleanup;
     f_thread_id_t id_control;
-    f_thread_id_t id_rule;
     f_thread_id_t id_signal;
 
     controller_lock_t lock;
-    controller_asynchronouss_t asynchronouss;
+    controller_processs_t processs;
   } controller_thread_t;
 
   #define controller_thread_t_initialize { \
@@ -1216,134 +1078,38 @@ extern "C" {
     f_thread_id_t_initialize, \
     f_thread_id_t_initialize, \
     f_thread_id_t_initialize, \
-    f_thread_id_t_initialize, \
     controller_lock_t_initialize, \
-    controller_asynchronouss_t_initialize \
+    controller_processs_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, \
-    f_thread_id_t_initialize. \
-    lock, \
-    asynchronouss \
-  }
-
-  #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); \
-    f_macro_thread_id_t_clear(thread.id_signal); \
-    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.
+ * A wrapper used for passing a common set of all data, particularly for sharing between threads.
  *
- * 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.
+ * 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_
+#ifndef _di_controller_main_t_
   // @todo relocate these under a different ifdef block.
-  #define controller_thread_cache_cleanup_interval_long  3600  // 1 hour in seconds.
-  #define controller_thread_cache_cleanup_interval_short 180   // 3 minutes in seconds.
-
-  // @fixme these aren't used? consider removing or updating.
-  #define controller_thread_asynchronous_allocation_step 16    // Total number of asynchronous threads increase by.
-  #define controller_thread_asynchronous_max             65535 // Total number of asynchronous threads allowed at any one time.
+  #define controller_thread_cache_cleanup_interval_long  3600 // 1 hour in seconds.
+  #define controller_thread_cache_cleanup_interval_short 180  // 3 minutes in seconds.
 
   typedef struct {
-    f_array_length_t id_process;
-
     controller_data_t *data;
     controller_setting_t *setting;
-    controller_processs_t *processs;
     controller_thread_t *thread;
-  } controller_thread_data_t;
+  } controller_main_t;
 
-  #define controller_thread_data_t_initialize { 0, 0, 0, 0, 0 }
+  #define controller_main_t_initialize { 0, 0, 0 }
 
-  #define controller_macro_thread_data_t_initialize(id_process, data, setting, processs, thread) { \
-    id_process, \
+  #define controller_macro_main_t_initialize(data, setting, thread) { \
     data, \
     setting, \
-    processs, \
-    thread \
+    thread, \
   }
-
-  #define controller_macro_thread_data_t_clear(thread_data) \
-    thread_data.id_process = 0; \
-    thread_data.data = 0; \
-    thread_data.setting = 0; \
-    thread_data.processs = 0; \
-    thread_data.thread = 0;
-#endif // _di_controller_thread_data_t_
-
-/**
- * Fully deallocate all memory for the given asynchronous without caring about return status.
- *
- * @param asynchronous
- *   The asynchronous to deallocate.
- *
- * @see f_macro_array_lengths_t_delete_simple()
- *
- * @see controller_cache_delete_simple()
- * @see controller_rule_delete_simple()
- */
-#ifndef _di_controller_asynchronous_delete_simple_
-  extern void controller_asynchronous_delete_simple(controller_asynchronous_t *asynchronous) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_asynchronous_delete_simple_
-
-/**
- * Increase the size of the asynchronous array, but only if necessary.
- *
- * If the given length is too large for the buffer, then attempt to set max buffer size (f_array_length_t_size).
- * If already set to the maximum buffer size, then the resize will fail.
- *
- * @param asynchronouss
- *   The asynchronous array to resize.
- *
- * @return
- *   F_none on success.
- *   F_data_not on success, but there is no reason to increase size (used + controller_default_allocation_step <= size).
- *
- *   F_array_too_large (with error bit) if the new array length is too large.
- *   F_memory_not (with error bit) on out of memory.
- *   F_parameter (with error bit) if a parameter is invalid.
- *
- * @see controller_asynchronouss_resize()
- */
-#ifndef _di_controller_asynchronouss_increase_
-  extern f_status_t controller_asynchronouss_increase(controller_asynchronouss_t *asynchronouss) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_asynchronouss_increase_
-
-/**
- * Resize the string asynchronous array.
- *
- * @param length
- *   The new size to use.
- * @param asynchronouss
- *   The asynchronous array to resize.
- *
- * @return
- *   F_none on success.
- *
- *   F_memory_not (with error bit) on out of memory.
- *   F_parameter (with error bit) if a parameter is invalid.
- *
- * @see f_memory_resize()
- */
-#ifndef _di_controller_asynchronouss_resize_
-  extern f_status_t controller_asynchronouss_resize(const f_array_length_t length, controller_asynchronouss_t *asynchronouss) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_asynchronouss_resize_
+#endif // _di_controller_main_t_
 
 /**
  * Fully deallocate all memory for the given cache without caring about return status.
@@ -1448,8 +1214,43 @@ extern "C" {
 #endif // _di_controller_error_print_
 
 /**
+ * Perform the initial, required, allocation for the lock.
+ *
+ * @param lock
+ *   The lock to allocate.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   Errors (with error bit) from f_thread_lock_delete().
+ *   Errors (with error bit) from f_thread_mutex_delete().
+ *
+ * @see f_thread_lock_delete()
+ * @see f_thread_mutex_delete()
+ */
+#ifndef _di_controller_lock_create_
+  extern f_status_t controller_lock_create(controller_lock_t *lock) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_lock_create_
+
+/**
+ * Fully deallocate all memory for the given lock without caring about return status.
+ *
+ * @param lock
+ *   The lock to deallocate.
+ *
+ * @see f_thread_lock_delete()
+ * @see f_thread_mutex_delete()
+ */
+#ifndef _di_controller_lock_delete_simple_
+  extern void controller_lock_delete_simple(controller_lock_t *lock) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_lock_delete_simple_
+
+/**
  * Fully deallocate all memory for the given process without caring about return status.
  *
+ * This does not close/cancel the id_thread.
+ * Be sure to properly close and/or detach the thread.
+ *
  * @param process
  *   The process to deallocate.
  *
@@ -1464,6 +1265,9 @@ extern "C" {
 /**
  * Fully deallocate all memory for the given processs without caring about return status.
  *
+ * This does not close/cancel the id_thread for any process.
+ * Be sure to properly close and/or detach the thread for each process.
+ *
  * @param processs
  *   The process array to deallocate.
  *
@@ -1507,10 +1311,15 @@ extern "C" {
  * @return
  *   F_none on success.
  *
- *   F_memory_not (with error bit) on out of memory.
- *   F_parameter (with error bit) if a parameter is invalid.
+ *   Errors (with error bit) from: controller_process_delete_simple().
+ *   Errors (with error bit) from: f_memory_resize().
+ *   Errors (with error bit) from: f_thread_condition_create().
+ *   Errors (with error bit) from: f_thread_lock_create().
  *
+ * @see controller_process_delete_simple()
  * @see f_memory_resize()
+ * @see f_thread_condition_create()
+ * @see f_thread_lock_create()
  */
 #ifndef _di_controller_processs_resize_
   extern f_status_t controller_processs_resize(const f_array_length_t length, controller_processs_t *processs) f_gcc_attribute_visibility_internal;
index 24e82ca0b27dc22ab81e474c2461f5317e45d95a..8938ca33309ba174a14e8d806707cd941eb6f355 100644 (file)
@@ -41,7 +41,7 @@ extern "C" {
 #endif // _di_controller_string_dynamic_partial_append_terminated_
 
 #ifndef _di_controller_file_load_
-  f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_thread_data_t thread_data, controller_cache_t *cache) {
+  f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_main_t main, controller_cache_t *cache) {
     f_status_t status = F_none;
     f_file_t file = f_file_t_initialize;
 
@@ -69,12 +69,12 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&thread_data.thread->lock.print);
+      if (main.data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main.thread->lock.print);
 
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "f_string_append", F_true);
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
       }
 
       return status;
@@ -83,25 +83,25 @@ extern "C" {
     status = f_string_dynamic_terminate_after(&cache->action.name_file);
 
     if (F_status_is_error(status)) {
-      if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&thread_data.thread->lock.print);
+      if (main.data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main.thread->lock.print);
 
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
       }
 
       return status;
     }
 
-    const f_array_length_t path_length = thread_data.setting->path_setting.used ? thread_data.setting->path_setting.used + f_path_separator_length + cache->action.name_file.used : cache->action.name_file.used;
+    const f_array_length_t path_length = main.setting->path_setting.used ? main.setting->path_setting.used + f_path_separator_length + cache->action.name_file.used : cache->action.name_file.used;
     char path[path_length + 1];
 
-    if (thread_data.setting->path_setting.used) {
-      memcpy(path, thread_data.setting->path_setting.string, thread_data.setting->path_setting.used);
-      memcpy(path + thread_data.setting->path_setting.used + f_path_separator_length, cache->action.name_file.string, cache->action.name_file.used);
+    if (main.setting->path_setting.used) {
+      memcpy(path, main.setting->path_setting.string, main.setting->path_setting.used);
+      memcpy(path + main.setting->path_setting.used + f_path_separator_length, cache->action.name_file.string, cache->action.name_file.used);
 
-      path[thread_data.setting->path_setting.used] = f_path_separator_s[0];
+      path[main.setting->path_setting.used] = f_path_separator_s[0];
     }
 
     path[path_length] = 0;
@@ -109,24 +109,24 @@ extern "C" {
     status = f_file_stream_open(path, 0, &file);
 
     if (F_status_is_error(status)) {
-      if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&thread_data.thread->lock.print);
+      if (main.data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main.thread->lock.print);
 
-        fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file);
+        fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stream_open", F_true, path, "open", fll_error_file_type_file);
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
       }
     }
     else {
       status = f_file_stream_read(file, 1, &cache->buffer_file);
 
       if (F_status_is_error(status)) {
-        if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-          f_thread_mutex_lock(&thread_data.thread->lock.print);
+        if (main.data->error.verbosity != f_console_verbosity_quiet) {
+          f_thread_mutex_lock(&main.thread->lock.print);
 
-          fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file);
+          fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stream_read", F_true, path, "read", fll_error_file_type_file);
 
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
+          f_thread_mutex_unlock(&main.thread->lock.print);
         }
       }
     }
@@ -139,12 +139,12 @@ extern "C" {
       status = f_file_stat(path, F_true, &stat_file);
 
       if (F_status_is_error(status)) {
-        if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-          f_thread_mutex_lock(&thread_data.thread->lock.print);
+        if (main.data->error.verbosity != f_console_verbosity_quiet) {
+          f_thread_mutex_lock(&main.thread->lock.print);
 
-          fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file);
+          fll_error_file_print(main.data->error, F_status_set_fine(status), "f_file_stat", F_true, path, "stat", fll_error_file_type_file);
 
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
+          f_thread_mutex_unlock(&main.thread->lock.print);
         }
       }
       else {
@@ -252,14 +252,14 @@ extern "C" {
 #endif // _di_controller_file_pid_delete_
 
 #ifndef _di_controller_find_process_
-  f_status_t controller_find_process(const f_string_static_t id, const controller_processs_t processs, f_array_length_t *at) {
+  f_status_t controller_find_process(const f_string_static_t alias, const controller_processs_t processs, f_array_length_t *at) {
 
-    if (!id.used) return F_none;
+    if (!alias.used) return F_none;
     if (!processs.used) return F_false;
 
     for (f_array_length_t i = 0; i < processs.used; ++i) {
 
-      if (fl_string_dynamic_compare(id, processs.array[i].id_rule) == F_equal_to) {
+      if (fl_string_dynamic_compare(alias, processs.array[i].alias_rule) == F_equal_to) {
         *at = i;
         return F_true;
       }
@@ -354,40 +354,40 @@ extern "C" {
 #endif // _di_controller_get_id_group_
 
 #ifndef _di_controller_perform_ready_
-  f_status_t controller_perform_ready(controller_thread_data_t thread_data, controller_cache_t *cache) {
+  f_status_t controller_perform_ready(controller_main_t main, controller_cache_t *cache) {
     f_status_t status = F_none;
 
     // only create pid file when not in validate mode.
-    if (thread_data.data->parameters[controller_parameter_validate].result == f_console_result_none) {
+    if (main.data->parameters[controller_parameter_validate].result == f_console_result_none) {
 
-      status = controller_file_pid_create(*thread_data.data, thread_data.setting->path_pid);
+      status = controller_file_pid_create(*main.data, main.setting->path_pid);
 
       // report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
       if (F_status_is_error(status)) {
 
         // always return immediately on memory errors.
         if (F_status_set_fine(status) == F_memory_not) {
-          if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+          if (main.data->error.verbosity != f_console_verbosity_quiet) {
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-            fll_error_file_print(thread_data.data->error, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file);
+            fll_error_file_print(main.data->error, F_status_set_fine(status), "controller_file_pid_create", F_true, main.setting->path_pid.string, "create", fll_error_file_type_file);
 
-            controller_entry_error_print_cache(thread_data.data->error, cache->action);
+            controller_entry_error_print_cache(main.data->error, cache->action);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
           return status;
         }
 
-        if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-          f_thread_mutex_lock(&thread_data.thread->lock.print);
+        if (main.data->warning.verbosity == f_console_verbosity_debug) {
+          f_thread_mutex_lock(&main.thread->lock.print);
 
-          fll_error_file_print(thread_data.data->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, thread_data.setting->path_pid.string, "create", fll_error_file_type_file);
+          fll_error_file_print(main.data->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, main.setting->path_pid.string, "create", fll_error_file_type_file);
 
-          controller_entry_error_print_cache(thread_data.data->warning, cache->action);
+          controller_entry_error_print_cache(main.data->warning, cache->action);
 
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
+          f_thread_mutex_unlock(&main.thread->lock.print);
         }
 
         status = F_none;
@@ -399,7 +399,7 @@ extern "C" {
 #endif // _di_controller_perform_ready_
 
 #ifndef _di_controller_preprocess_entry_
-  f_status_t controller_preprocess_entry(controller_thread_data_t thread_data, controller_cache_t *cache) {
+  f_status_t controller_preprocess_entry(controller_main_t main, controller_cache_t *cache) {
     f_status_t status = F_none;
     f_status_t status2 = F_none;
 
@@ -413,7 +413,7 @@ extern "C" {
 
     uint8_t error_has = F_false;
 
-    thread_data.setting->ready = controller_setting_ready_no;
+    main.setting->ready = controller_setting_ready_no;
 
     cache->ats.used = 0;
 
@@ -425,7 +425,7 @@ extern "C" {
     f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step)
 
     if (F_status_is_error(status)) {
-      controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread);
+      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main.thread);
       return status;
     }
 
@@ -434,24 +434,24 @@ extern "C" {
     cache->ats.array[1] = 0;
     cache->ats.used = 2;
 
-    cache->action.line_item = thread_data.setting->entry.items.array[0].line;
+    cache->action.line_item = main.setting->entry.items.array[0].line;
     cache->action.name_item.used = 0;
 
-    status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[0].name, &cache->action.name_item);
+    status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[0].name, &cache->action.name_item);
 
     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);
+      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
 
       return status;
     }
 
     for (;;) {
 
-      actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions;
+      actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions;
 
       for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) {
 
-        if (thread_data.thread->signal) {
+        if (main.thread->signal) {
           return F_signal;
         }
 
@@ -461,30 +461,30 @@ extern "C" {
         status2 = controller_string_dynamic_append_terminated(controller_entry_action_type_name(actions->array[cache->ats.array[at_j]].type), &cache->action.name_action);
 
         if (F_status_is_error(status2)) {
-          controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread);
+          controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, main.thread);
 
           return status2;
         }
 
         if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_ready) {
 
-          if (thread_data.setting->ready == controller_setting_ready_wait) {
-            if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+          if (main.setting->ready == controller_setting_ready_wait) {
+            if (main.data->warning.verbosity == f_console_verbosity_debug) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(thread_data.data->warning.to.stream, "%s%sMultiple '", 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%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, controller_string_ready_s, thread_data.data->warning.notable.after->string);
-              fprintf(thread_data.data->warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
+              fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->warning.to.stream, "%s%sMultiple '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
+              fprintf(main.data->warning.to.stream, "%s%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, controller_string_ready_s, main.data->warning.notable.after->string);
+              fprintf(main.data->warning.to.stream, "%s' entry item actions detected; only the first will be used.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(thread_data.data->warning, cache->action);
+              controller_entry_error_print_cache(main.data->warning, cache->action);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
           }
 
           // the pre-process currently only looks for "ready", so once found, pre-process is complete.
-          thread_data.setting->ready = controller_setting_ready_wait;
+          main.setting->ready = controller_setting_ready_wait;
         }
         else if (actions->array[cache->ats.array[at_j]].type == controller_entry_action_type_item) {
           error_has = F_false;
@@ -494,25 +494,25 @@ extern "C" {
           }
 
           // walk though each items and check to see if the item actually exists (skipping main).
-          for (i = 1; i < thread_data.setting->entry.items.used; ++i) {
+          for (i = 1; i < main.setting->entry.items.used; ++i) {
 
-            if (fl_string_dynamic_compare(thread_data.setting->entry.items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) {
+            if (fl_string_dynamic_compare(main.setting->entry.items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) {
 
               // check to see if "i" is already in the stack (to prevent recursion) (skipping main).
               for (j = 2; j < cache->ats.used; j += 2) {
 
                 if (cache->ats.array[j] == i) {
-                  if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-                    f_thread_mutex_lock(&thread_data.thread->lock.print);
+                  if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                    f_thread_mutex_lock(&main.thread->lock.print);
 
-                    fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-                    fprintf(thread_data.data->error.to.stream, "%s%sThe entry item named '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.setting->entry.items.array[i].name.string, thread_data.data->error.notable.after->string);
-                    fprintf(thread_data.data->error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                    fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                    fprintf(main.data->error.to.stream, "%s%sThe entry item named '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                    fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.setting->entry.items.array[i].name.string, main.data->error.notable.after->string);
+                    fprintf(main.data->error.to.stream, "%s' cannot be executed because recursion is not allowed.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                    controller_entry_error_print_cache(thread_data.data->error, cache->action);
+                    controller_entry_error_print_cache(main.data->error, cache->action);
 
-                    f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                    f_thread_mutex_unlock(&main.thread->lock.print);
                   }
 
                   if (F_status_is_error_not(status)) {
@@ -529,7 +529,7 @@ extern "C" {
               f_macro_array_lengths_t_increase_by(status2, cache->ats, controller_default_allocation_step)
 
               if (F_status_is_error(status2)) {
-                controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread);
+                controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "f_macro_array_lengths_t_increase_by", F_true, main.thread);
 
                 return status2;
               }
@@ -549,12 +549,12 @@ extern "C" {
               cache->action.line_action = 0;
 
               cache->action.name_item.used = 0;
-              cache->action.line_item = thread_data.setting->entry.items.array[i].line;
+              cache->action.line_item = main.setting->entry.items.array[i].line;
 
-              status2 = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[i].name, &cache->action.name_item);
+              status2 = controller_string_dynamic_append_terminated(main.setting->entry.items.array[i].name, &cache->action.name_item);
 
               if (F_status_is_error(status2)) {
-                controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread);
+                controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, main.thread);
 
                 return status2;
               }
@@ -563,19 +563,19 @@ extern "C" {
             }
           } // for
 
-          if (error_has || i >= thread_data.setting->entry.items.used) {
-            if (i >= thread_data.setting->entry.items.used) {
-              if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&thread_data.thread->lock.print);
+          if (error_has || i >= main.setting->entry.items.used) {
+            if (i >= main.setting->entry.items.used) {
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main.thread->lock.print);
 
-                fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-                fprintf(thread_data.data->error.to.stream, "%s%sThe entry item named '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].parameters.array[0].string, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s' does not exist.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%sThe entry item named '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, actions->array[cache->ats.array[at_j]].parameters.array[0].string, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s' does not exist.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_entry_error_print_cache(thread_data.data->error, cache->action);
+                controller_entry_error_print_cache(main.data->error, cache->action);
 
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
               }
 
               if (F_status_is_error_not(status)) {
@@ -604,13 +604,13 @@ extern "C" {
         cache->ats.used -= 2;
         cache->ats.array[at_j]++;
 
-        cache->action.line_item = thread_data.setting->entry.items.array[cache->ats.array[at_i]].line;
+        cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line;
         cache->action.name_item.used = 0;
 
-        status2 = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
+        status2 = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
 
         if (F_status_is_error(status2)) {
-          controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, thread_data.thread);
+          controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status2), "controller_string_dynamic_append_terminated", F_true, main.thread);
 
           return status2;
         }
@@ -618,8 +618,8 @@ extern "C" {
     } // for
 
     // if ready was never found in the entry, then default to always ready.
-    if (thread_data.setting->ready == controller_setting_ready_no) {
-      thread_data.setting->ready = controller_setting_ready_yes;
+    if (main.setting->ready == controller_setting_ready_no) {
+      main.setting->ready = controller_setting_ready_yes;
     }
 
     return status;
@@ -627,7 +627,7 @@ extern "C" {
 #endif // _di_controller_preprocess_entry_
 
 #ifndef _di_controller_process_entry_
-  f_status_t controller_process_entry(controller_thread_data_t thread_data, controller_cache_t *cache) {
+  f_status_t controller_process_entry(controller_main_t main, controller_cache_t *cache) {
     f_status_t status = F_none;
 
     f_array_length_t i = 0;
@@ -643,7 +643,10 @@ extern "C" {
     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;
+    // an empty stack is used here because each rule here is the first rule run in the rule's scope.
+    const f_array_lengths_t stack = f_array_lengths_t_initialize;
+
+    const bool simulate = main.data->parameters[controller_parameter_test].result == f_console_result_found;
 
     cache->ats.used = 0;
     cache->stack.used = 0;
@@ -653,15 +656,15 @@ extern "C" {
     cache->action.name_action.used = 0;
     cache->action.name_item.used = 0;
 
-    if (thread_data.setting->ready == controller_setting_ready_yes) {
-      status = controller_perform_ready(thread_data, cache);
+    if (main.setting->ready == controller_setting_ready_yes) {
+      status = controller_perform_ready(main, cache);
       if (F_status_is_error(status)) return status;
     }
 
     f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step)
 
     if (F_status_is_error(status)) {
-      controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread);
+      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main.thread);
 
       return status;
     }
@@ -671,37 +674,37 @@ extern "C" {
     cache->ats.array[1] = 0;
     cache->ats.used = 2;
 
-    cache->action.line_item = thread_data.setting->entry.items.array[0].line;
+    cache->action.line_item = main.setting->entry.items.array[0].line;
     cache->action.name_item.used = 0;
 
-    status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[0].name, &cache->action.name_item);
+    status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[0].name, &cache->action.name_item);
 
     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);
+      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
 
       return status;
     }
 
     if (simulate) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
-      fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-      fprintf(thread_data.data->output.stream, "Processing entry item rule '");
-      fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_main_s, thread_data.data->context.set.title.after->string);
-      fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]);
+      fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+      fprintf(main.data->output.stream, "Processing entry item rule '");
+      fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_main_s, main.data->context.set.title.after->string);
+      fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
     }
 
-    // @todo this function should maintain a read lock on "thread_data.thread->lock.rule", but it must immediately release the read lock before it can do a write lock (which is unfortunate).
-    //       I would much rather gain the write lock and then release the read lock, but that is likely not possible.
+    f_thread_lock_read(&main.thread->lock.entry);
+
     for (;;) {
 
-      entry_actions = &thread_data.setting->entry.items.array[cache->ats.array[at_i]].actions;
+      entry_actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions;
 
       for (; cache->ats.array[at_j] < entry_actions->used; ++cache->ats.array[at_j]) {
 
-        if (thread_data.thread->signal) {
+        if (main.thread->signal) {
           status = F_signal;
           break;
         }
@@ -714,7 +717,9 @@ extern "C" {
         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);
+          controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
+
+          f_thread_unlock(&main.thread->lock.entry);
 
           return status;
         }
@@ -724,111 +729,113 @@ extern "C" {
           if (entry_action->type == controller_entry_action_type_rule) {
 
             if (simulate) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+              f_thread_mutex_lock(&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 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);
+              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "The entry item action '");
+              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
 
               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, entry_actions->array[cache->ats.array[at_j]]);
-                fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.after->string);
+                fprintf(main.data->output.stream, f_string_space_s);
+                fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
+                controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
+                fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
               }
 
-              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]);
+              fprintf(main.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", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
             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);
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main.thread->lock.print);
 
-                fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-                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);
+                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%sThe entry item action '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                fprintf(main.data->error.to.stream, "%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.name_action.string);
 
                 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, entry_actions->array[cache->ats.array[at_j]]);
+                  fprintf(main.data->error.to.stream, f_string_space_s);
+                  controller_entry_action_parameters_print(main.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->error.to.stream, "%s%srequired%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s and is in a ", thread_data.data->error.context.before->string);
-                fprintf(thread_data.data->error.to.stream, "%s%sfailed%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s state, skipping execution.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%s' is ", main.data->error.notable.after->string, main.data->error.context.before->string);
+                fprintf(main.data->error.to.stream, "%s%srequired%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s and is in a ", main.data->error.context.before->string);
+                fprintf(main.data->error.to.stream, "%s%sfailed%s", main.data->error.context.after->string, main.data->error.notable.before->string, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s state, skipping execution.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                controller_entry_error_print_cache(thread_data.data->error, cache->action);
+                controller_entry_error_print_cache(main.data->error, cache->action);
 
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
               }
 
+              f_thread_unlock(&main.thread->lock.entry);
+
               return F_status_is_error(F_require);
             }
-            else if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+            else if (main.data->warning.verbosity == f_console_verbosity_debug) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]);
-              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);
+              fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->warning.to.stream, "%s%sThe entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
+              fprintf(main.data->warning.to.stream, "%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, cache->action.name_action.string);
 
               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, entry_actions->array[cache->ats.array[at_j]]);
+                fprintf(main.data->warning.to.stream, f_string_space_s);
+                controller_entry_action_parameters_print(main.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->warning.to.stream, "%s%srequired%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string);
-              fprintf(thread_data.data->warning.to.stream, "%s and is in a ", thread_data.data->warning.context.before->string);
-              fprintf(thread_data.data->warning.to.stream, "%s%sfailed%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string);
-              fprintf(thread_data.data->warning.to.stream, "%s state, skipping execution.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
+              fprintf(main.data->warning.to.stream, "%s%s' is ", main.data->warning.notable.after->string, main.data->warning.context.before->string);
+              fprintf(main.data->warning.to.stream, "%s%srequired%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string);
+              fprintf(main.data->warning.to.stream, "%s and is in a ", main.data->warning.context.before->string);
+              fprintf(main.data->warning.to.stream, "%s%sfailed%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string);
+              fprintf(main.data->warning.to.stream, "%s state, skipping execution.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(thread_data.data->warning, cache->action);
+              controller_entry_error_print_cache(main.data->warning, cache->action);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
           }
           else {
             if (simulate) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+              f_thread_mutex_lock(&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 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);
+              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "The entry item action '");
+              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
 
               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, entry_actions->array[cache->ats.array[at_j]]);
-                fprintf(thread_data.data->output.stream, "%s", thread_data.data->context.set.notable.after->string);
+                fprintf(main.data->output.stream, f_string_space_s);
+                fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
+                controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
+                fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
               }
 
-              fprintf(thread_data.data->output.stream, "' is in a %sfailed%s state, skipping.%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "' is in a %sfailed%s state, skipping.%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
-            else if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+            else if (main.data->warning.verbosity == f_console_verbosity_debug) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]);
-              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);
+              fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->warning.to.stream, "%s%sThe entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
+              fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.notable.before->string, cache->action.name_action.string);
 
               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, entry_actions->array[cache->ats.array[at_j]]);
+                fprintf(main.data->warning.to.stream, f_string_space_s);
+                controller_entry_action_parameters_print(main.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);
-              fprintf(thread_data.data->warning.to.stream, "%s%sfailed%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, thread_data.data->warning.notable.after->string);
-              fprintf(thread_data.data->warning.to.stream, "%s state, skipping.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
+              fprintf(main.data->warning.to.stream, "%s' is in a ", main.data->warning.notable.after->string);
+              fprintf(main.data->warning.to.stream, "%s%sfailed%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, main.data->warning.notable.after->string);
+              fprintf(main.data->warning.to.stream, "%s state, skipping.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(thread_data.data->warning, cache->action);
+              controller_entry_error_print_cache(main.data->warning, cache->action);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
           }
 
@@ -837,61 +844,70 @@ extern "C" {
 
         if (entry_action->type == controller_entry_action_type_ready) {
 
-          if (thread_data.setting->ready == controller_setting_ready_wait) {
+          if (main.setting->ready == controller_setting_ready_wait) {
 
             if (simulate) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-              fprintf(thread_data.data->output.stream, "Processing entry item action '");
-              fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_ready_s, thread_data.data->context.set.title.after->string);
-              fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "Processing entry item action '");
+              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
+              fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
             else {
-              controller_perform_ready(thread_data, cache);
-              if (F_status_is_error(status)) return status;
+              controller_perform_ready(main, cache);
+
+              if (F_status_is_error(status)) {
+                f_thread_unlock(&main.thread->lock.entry);
+
+                return status;
+              }
             }
 
-            thread_data.setting->ready = controller_setting_ready_yes;
+            main.setting->ready = controller_setting_ready_yes;
           }
           else if (simulate) {
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-            fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-            fprintf(thread_data.data->output.stream, "Ignoring entry item action '");
-            fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_ready_s, thread_data.data->context.set.title.after->string);
-            fprintf(thread_data.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
+            fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(main.data->output.stream, "Ignoring entry item action '");
+            fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
+            fprintf(main.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
         }
         else if (entry_action->type == controller_entry_action_type_item) {
 
-          if (entry_action->number == 0 || entry_action->number >= thread_data.setting->entry.items.used) {
+          if (entry_action->number == 0 || entry_action->number >= main.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) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+            if (main.data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              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, 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]);
+              fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->error.to.stream, "%s%sInvalid entry item index ", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+              fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, entry_action->number, main.data->error.notable.after->string);
+              fprintf(main.data->error.to.stream, "%s detected.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(thread_data.data->error, cache->action);
+              controller_entry_error_print_cache(main.data->error, cache->action);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
 
+            f_thread_unlock(&main.thread->lock.entry);
+
             return F_status_is_error(F_critical);
           }
 
           f_macro_array_lengths_t_increase_by(status, cache->ats, controller_default_allocation_step)
 
           if (F_status_is_error(status)) {
-            controller_entry_error_print(thread_data.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, thread_data.thread);
+            controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true, main.thread);
+
+            f_thread_unlock(&main.thread->lock.entry);
 
             return status;
           }
@@ -909,25 +925,27 @@ extern "C" {
           cache->action.line_action = 0;
 
           cache->action.name_item.used = 0;
-          cache->action.line_item = thread_data.setting->entry.items.array[cache->ats.array[at_i]].line;
+          cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line;
 
-          status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
+          status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
 
           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);
+            controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
+
+            f_thread_unlock(&main.thread->lock.entry);
 
             return status;
           }
 
           if (simulate) {
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-            fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-            fprintf(thread_data.data->output.stream, "Processing entry item '");
-            fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, cache->action.name_item.string, thread_data.data->context.set.title.after->string);
-            fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]);
+            fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(main.data->output.stream, "Processing entry item '");
+            fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_item.string, main.data->context.set.title.after->string);
+            fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
           // exit inner loop to force restarting and start processing the requested item.
@@ -935,17 +953,23 @@ extern "C" {
         }
         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);
+          f_thread_lock_write(&main.thread->lock.rule);
+
+          status = controller_rules_increase(&main.setting->rules);
+
+          f_thread_unlock(&main.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_rules_increase", F_true, thread_data.thread);
+            controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, main.thread);
+
+            f_thread_unlock(&main.thread->lock.entry);
 
             return status;
           }
 
           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);
+          const f_string_static_t alias_rule = f_macro_string_static_t_initialize(id_rule_name, id_rule_length);
 
           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);
@@ -953,25 +977,25 @@ extern "C" {
           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);
+          f_thread_lock_read(&main.thread->lock.rule);
 
-          at = controller_rule_find_loaded(id_rule, thread_data);
+          at = controller_rule_find_loaded(alias_rule, main);
 
           if (simulate) {
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+            f_thread_mutex_lock(&main.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 '", 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]);
+            fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(main.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering");
+            fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, alias_rule.string, main.data->context.set.title.after->string);
+            fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
           // the rule is not yet loaded, ensure that it is loaded.
-          if (at == thread_data.setting->rules.used) {
+          if (at == main.setting->rules.used) {
 
-            f_thread_unlock(&thread_data.thread->lock.rule);
+            f_thread_unlock(&main.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;
@@ -989,9 +1013,9 @@ extern "C" {
             memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used);
             memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used);
 
-            f_thread_lock_write(&thread_data.thread->lock.rule);
+            f_thread_lock_write(&main.thread->lock.rule);
 
-            status = controller_rule_read(id_rule, thread_data, cache, &thread_data.setting->rules.array[thread_data.setting->rules.used]);
+            status = controller_rule_read(alias_rule, main, cache, &main.setting->rules.array[main.setting->rules.used]);
 
             // restore cache.
             memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used);
@@ -1011,45 +1035,31 @@ extern "C" {
 
             if (F_status_is_error(status)) {
 
-              if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-                f_thread_mutex_lock(&thread_data.thread->lock.print);
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                f_thread_mutex_lock(&main.thread->lock.print);
 
-                controller_entry_error_print_cache(thread_data.data->error, cache->action);
+                controller_entry_error_print_cache(main.data->error, cache->action);
 
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
               }
 
               if (!simulate) {
-                f_thread_unlock(&thread_data.thread->lock.rule);
+                f_thread_unlock(&main.thread->lock.rule);
 
                 break;
               }
             }
             else {
-              thread_data.setting->rules.used++;
+              main.setting->rules.used++;
             }
 
-            f_thread_unlock(&thread_data.thread->lock.rule);
+            f_thread_unlock(&main.thread->lock.rule);
+          }
+          else {
+            f_thread_unlock(&main.thread->lock.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;
-            const f_array_length_t cache_line_item = cache->action.line_item;
-
-            const f_array_length_t cache_name_action_used = cache->action.name_action.used;
-            const f_array_length_t cache_name_item_used = cache->action.name_item.used;
-            const f_array_length_t cache_name_file_used = cache->action.name_file.used;
-
-            char cache_name_action[cache_name_action_used];
-            char cache_name_item[cache_name_item_used];
-            char cache_name_file[cache_name_file_used];
-
-            memcpy(cache_name_action, cache->action.name_action.string, cache->action.name_action.used);
-            memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used);
-            memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used);
-
             rule_options = 0;
 
             if (simulate) {
@@ -1066,30 +1076,9 @@ extern "C" {
 
             if (entry_action->code & controller_entry_rule_code_asynchronous) {
               rule_options |= controller_rule_option_asynchronous;
-
-              // @todo
-              //status = controller_rule_process_asynchronous(id_rule, controller_rule_action_type_start, rule_options, thread_data, cache);
             }
-            else {
-              // @todo
-              // status = controller_rule_process(id_rule, controller_rule_action_type_start, rule_options, thread_data, cache);
-            }
-
-            // restore cache.
-            memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used);
-            memcpy(cache->action.name_item.string, cache_name_item, cache_name_item_used);
-            memcpy(cache->action.name_file.string, cache_name_file, cache_name_file_used);
 
-            cache->action.name_action.string[cache_name_action_used] = 0;
-            cache->action.name_item.string[cache_name_item_used] = 0;
-            cache->action.name_file.string[cache_name_file_used] = 0;
-
-            cache->action.name_action.used = cache_name_action_used;
-            cache->action.name_item.used = cache_name_item_used;
-            cache->action.name_file.used = cache_name_file_used;
-
-            cache->action.line_action = cache_line_action;
-            cache->action.line_item = cache_line_item;
+            status = controller_rule_process_begin(entry_action->code & controller_entry_rule_code_asynchronous, alias_rule, controller_rule_action_type_start, rule_options, stack, main, cache);
 
             if (!simulate || F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal) {
               break;
@@ -1111,71 +1100,73 @@ extern "C" {
               code = controller_string_stop_s;
             }
 
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-            fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-            fprintf(thread_data.data->output.stream, "Processing entry item action '");
-            fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_timeout_s, thread_data.data->context.set.title.after->string);
-            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, 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]);
+            fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+            fprintf(main.data->output.stream, "Processing entry item action '");
+            fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_timeout_s, main.data->context.set.title.after->string);
+            fprintf(main.data->output.stream, "' setting '");
+            fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, code, main.data->context.set.important.after->string);
+            fprintf(main.data->output.stream, "' to '");
+            fprintf(main.data->output.stream, "%s%llu%s", main.data->context.set.important.before->string, entry_action->number, main.data->context.set.important.after->string);
+            fprintf(main.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
           if (entry_action->code == controller_entry_timeout_code_kill) {
-            thread_data.setting->timeout_kill = entry_action->number;
+            main.setting->timeout_kill = entry_action->number;
           }
           else if (entry_action->code == controller_entry_timeout_code_start) {
-            thread_data.setting->timeout_start = entry_action->number;
+            main.setting->timeout_start = entry_action->number;
           }
           else if (entry_action->code == controller_entry_timeout_code_stop) {
-            thread_data.setting->timeout_stop = entry_action->number;
+            main.setting->timeout_stop = entry_action->number;
           }
         }
         else if (entry_action->type == controller_entry_action_type_failsafe) {
 
-          if (entry_action->number == 0 || entry_action->number >= thread_data.setting->entry.items.used) {
+          if (entry_action->number == 0 || entry_action->number >= main.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) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+            if (main.data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              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, 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]);
+              fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->error.to.stream, "%s%sInvalid entry item index ", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+              fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, entry_action->number, main.data->error.notable.after->string);
+              fprintf(main.data->error.to.stream, "%s detected.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-              controller_entry_error_print_cache(thread_data.data->error, cache->action);
+              controller_entry_error_print_cache(main.data->error, cache->action);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
 
+            f_thread_unlock(&main.thread->lock.entry);
+
             return F_status_is_error(F_critical);
           }
           else {
-            thread_data.setting->failsafe_enabled = F_true;
-            thread_data.setting->failsafe_rule_id = entry_action->number;
+            main.setting->failsafe_enabled = F_true;
+            main.setting->failsafe_rule_id = entry_action->number;
 
             if (simulate) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-              fprintf(thread_data.data->output.stream, "Processing entry item action '");
-              fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.title.before->string, controller_string_failsafe_s, thread_data.data->context.set.title.after->string);
-              fprintf(thread_data.data->output.stream, "' setting value to '");
-              fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.set.important.before->string, thread_data.setting->entry.items.array[thread_data.setting->failsafe_rule_id].name.string, thread_data.data->context.set.important.after->string);
-              fprintf(thread_data.data->output.stream, "'.%c", f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->output.stream, "Processing entry item action '");
+              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_failsafe_s, main.data->context.set.title.after->string);
+              fprintf(main.data->output.stream, "' setting value to '");
+              fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, main.setting->entry.items.array[main.setting->failsafe_rule_id].name.string, main.data->context.set.important.after->string);
+              fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
           }
         }
       } // for
 
-      if (thread_data.thread->signal) {
+      if (main.thread->signal) {
         status = F_signal;
       }
 
@@ -1202,29 +1193,31 @@ extern "C" {
         cache->ats.used -= 2;
         cache->ats.array[at_j]++;
 
-        cache->action.line_item = thread_data.setting->entry.items.array[cache->ats.array[at_i]].line;
+        cache->action.line_item = main.setting->entry.items.array[cache->ats.array[at_i]].line;
         cache->action.name_item.used = 0;
 
-        status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
+        status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
 
         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);
+          controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
 
           break;
         }
       }
     } // for
 
+    f_thread_unlock(&main.thread->lock.entry);
+
     if (status == F_child || status == F_signal) {
       return status;
     }
 
     if (F_status_is_error_not(status) && simulate) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
-      fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
+      fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
     }
 
     return status;
index f6f9a745a5b9a972e423e1545084ae6043cab1b4..7e59ddd148ce469107548f076fd8f6438eda8ef7 100644 (file)
@@ -90,8 +90,8 @@ extern "C" {
  *   The length of the prefix path.
  * @param path_suffix_length
  *   The length of the suffix path.
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   The following within the cache is updated:
  *   - name_file: The partial path of the file is inserted.
@@ -114,7 +114,7 @@ extern "C" {
  * @see f_string_dynamic_terminate_after()
  */
 #ifndef _di_controller_file_load_
-  extern f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_file_load(const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_file_load_
 
 /**
@@ -164,8 +164,8 @@ extern "C" {
  *
  * This does not do any locking or unlocking for the processs data, be sure to lock appropriately before and after calling this.
  *
- * @param id
- *   The (rule) id to find.
+ * @param alias
+ *   The Rule alias to find.
  * @param processs
  *   The array of processes to.
  * @param at
@@ -177,7 +177,7 @@ extern "C" {
  *   F_true if there is a process found (address is stored in "at").
  */
 #ifndef _di_controller_find_process_
-  f_status_t controller_find_process(const f_string_static_t id, const controller_processs_t processs, f_array_length_t *at) f_gcc_attribute_visibility_internal;
+  f_status_t controller_find_process(const f_string_static_t alias, const controller_processs_t processs, f_array_length_t *at) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_find_process_
 
 /**
@@ -241,8 +241,8 @@ extern "C" {
  *
  * This does not do any locking or unlocking for the setting data, be sure to lock appropriately before and after calling this.
  *
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   The cache.
  *
@@ -254,14 +254,14 @@ extern "C" {
  * @see controller_file_pid_create()
  */
 #ifndef _di_controller_perform_ready_
-  extern f_status_t controller_perform_ready(controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_perform_ready(controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_perform_ready_
 
 /**
  * Pre-process all items for the loaded entry.
  *
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   The main/global cache to use.
  *
@@ -282,14 +282,14 @@ extern "C" {
  * @see f_string_dynamic_terminate_after()
  */
 #ifndef _di_controller_preprocess_entry_
-  extern f_status_t controller_preprocess_entry(controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_preprocess_entry(controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_preprocess_entry_
 
 /**
  * Process (execute) all items for the loaded entry.
  *
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   The main/global cache to use.
  *
@@ -306,7 +306,7 @@ extern "C" {
  * @see controller_string_dynamic_append_terminated()
  */
 #ifndef _di_controller_process_entry_
-  extern f_status_t controller_process_entry(controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_process_entry(controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_process_entry_
 
 /**
index 7f42a2284f4c20a071b1c6438f93884786aa056d..e87549388f9edb98d42e0d3315e18e5a476cb4c6 100644 (file)
@@ -91,7 +91,7 @@ extern "C" {
 #endif // _di_controller_entry_actions_increase_by_
 
 #ifndef _di_controller_entry_actions_read_
-  f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_thread_data_t thread_data, controller_cache_t *cache, controller_entry_actions_t *actions) {
+  f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_main_t main, controller_cache_t *cache, controller_entry_actions_t *actions) {
     f_status_t status = F_none;
     f_status_t status_action = F_none;
 
@@ -119,7 +119,7 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_extended_read", F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "fll_fss_extended_read", F_true);
 
       return status;
     }
@@ -127,7 +127,7 @@ extern "C" {
     status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file);
 
     if (F_status_is_error(status)) {
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
 
       return status;
     }
@@ -137,7 +137,7 @@ extern "C" {
     status = controller_entry_actions_increase_by(cache->object_actions.used, actions);
 
     if (F_status_is_error(status)) {
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_entry_actions_increase_by", F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "controller_entry_actions_increase_by", F_true);
 
       return status;
     }
@@ -167,7 +167,7 @@ extern "C" {
       status = f_fss_count_lines(cache->buffer_file, cache->object_actions.array[i].start, &cache->action.line_action);
 
       if (F_status_is_error(status)) {
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true);
         break;
       }
 
@@ -176,7 +176,7 @@ extern "C" {
       status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_actions.array[i], &cache->action.name_action);
 
       if (F_status_is_error(status)) {
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true);
         break;
       }
 
@@ -199,14 +199,14 @@ extern "C" {
         actions->array[actions->used].type = controller_entry_action_type_timeout;
       }
       else {
-        if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-          fprintf(thread_data.data->warning.to.stream, "%s%sUnknown 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.context.after->string, thread_data.data->warning.notable.before->string);
-          f_print_dynamic(thread_data.data->warning.to.stream, cache->action.name_action);
-          fprintf(thread_data.data->warning.to.stream, "%s", thread_data.data->warning.notable.after->string);
-          fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
-
-          controller_entry_error_print_cache(thread_data.data->warning, cache->action);
+        if (main.data->warning.verbosity == f_console_verbosity_debug) {
+          fprintf(main.data->warning.to.stream, "%s%sUnknown entry item action '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
+          fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string);
+          f_print_dynamic(main.data->warning.to.stream, cache->action.name_action);
+          fprintf(main.data->warning.to.stream, "%s", main.data->warning.notable.after->string);
+          fprintf(main.data->warning.to.stream, "%s'.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
+
+          controller_entry_error_print_cache(main.data->warning, cache->action);
         }
 
         continue;
@@ -237,15 +237,15 @@ extern "C" {
       if (cache->content_actions.array[i].used < at_least || cache->content_actions.array[i].used > at_most) {
         action->status = F_status_set_error(F_parameter);
 
-        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%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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->action.name_action.string, thread_data.data->error.notable.after->string);
-          fprintf(thread_data.data->error.to.stream, "%s' requires ", thread_data.data->error.context.before->string);
+        if (main.data->error.verbosity != f_console_verbosity_quiet) {
+          fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(main.data->error.to.stream, "%s%sThe entry item action '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+          fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.name_action.string, main.data->error.notable.after->string);
+          fprintf(main.data->error.to.stream, "%s' requires ", main.data->error.context.before->string);
 
           if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) {
-            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, cache->action.line_action, thread_data.data->error.notable.after->string);
-            fprintf(thread_data.data->error.to.stream, "%s or more parameters.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+            fprintf(main.data->error.to.stream, "%s%s%llu%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->action.line_action, main.data->error.notable.after->string);
+            fprintf(main.data->error.to.stream, "%s or more parameters.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
           }
           else {
             uint8_t parameters = 0;
@@ -257,9 +257,9 @@ extern "C" {
               parameters = 2;
             }
 
-            fprintf(thread_data.data->error.to.stream, "exactly ", thread_data.data->error.context.before->string);
-            fprintf(thread_data.data->error.to.stream, "%s%s%u%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, parameters, thread_data.data->error.notable.after->string);
-            fprintf(thread_data.data->error.to.stream, "%s parameters.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+            fprintf(main.data->error.to.stream, "exactly ", main.data->error.context.before->string);
+            fprintf(main.data->error.to.stream, "%s%s%u%s", main.data->error.context.after->string, main.data->error.notable.before->string, parameters, main.data->error.notable.after->string);
+            fprintf(main.data->error.to.stream, "%s parameters.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
           }
         }
       }
@@ -279,7 +279,7 @@ extern "C" {
         status = f_string_dynamics_increase_by(allocate, &action->parameters);
 
         if (F_status_is_error(status)) {
-          fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamics_increase_by", F_true);
+          fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamics_increase_by", F_true);
 
           action->status = status;
 
@@ -297,7 +297,7 @@ extern "C" {
           status = f_string_dynamic_partial_append_nulless(cache->buffer_file, cache->content_actions.array[i].array[j], &action->parameters.array[j]);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true);
 
             action->status = status;
 
@@ -319,7 +319,7 @@ extern "C" {
               status = fll_path_canonical(action->parameters.array[0].string, &cache->buffer_path);
 
               if (F_status_is_error(status)) {
-                fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+                fll_error_print(main.data->error, F_status_set_fine(status), "fll_path_canonical", F_true);
 
                 action->status = status;
 
@@ -340,9 +340,9 @@ extern "C" {
                 status_action = action->status;
               }
 
-              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%sThe entry item action must not have an empty string for a path (the first parameter).%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%sThe entry item action must not have an empty string for a path (the first parameter).%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]);
               }
             }
 
@@ -352,7 +352,7 @@ extern "C" {
               status = f_file_name_base(action->parameters.array[1].string, action->parameters.array[1].used, &cache->buffer_path);
 
               if (F_status_is_error(status)) {
-                fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_file_name_base", F_true);
+                fll_error_print(main.data->error, F_status_set_fine(status), "f_file_name_base", F_true);
 
                 if (F_status_set_fine(status) == F_memory_not) {
                   status_action = status;
@@ -368,11 +368,11 @@ extern "C" {
               else {
                 if (fl_string_dynamic_compare(action->parameters.array[1], cache->buffer_path) == F_equal_to_not) {
 
-                  if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
+                  if (main.data->error.verbosity != f_console_verbosity_quiet) {
                     status = f_string_dynamic_terminate_after(&cache->buffer_path);
 
                     if (F_status_is_error(status)) {
-                      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
+                      fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
 
                       action->status = status;
 
@@ -383,12 +383,12 @@ extern "C" {
                       break;
                     }
 
-                    fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-                    fprintf(thread_data.data->error.to.stream, "%s%sThe entry item action second parameter '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[1].string, thread_data.data->error.notable.after->string);
-                    fprintf(thread_data.data->error.to.stream, "%s' must be a base path name, such as '", thread_data.data->error.context.before->string);
-                    fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, cache->buffer_path.string, thread_data.data->error.notable.after->string);
-                    fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                    fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                    fprintf(main.data->error.to.stream, "%s%sThe entry item action second parameter '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                    fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[1].string, main.data->error.notable.after->string);
+                    fprintf(main.data->error.to.stream, "%s' must be a base path name, such as '", main.data->error.context.before->string);
+                    fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, cache->buffer_path.string, main.data->error.notable.after->string);
+                    fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
                   }
 
                   action->status = F_status_set_error(F_parameter);
@@ -406,9 +406,9 @@ extern "C" {
                 status_action = action->status;
               }
 
-              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%sThe entry item action must not have an empty string for a rule name (the second parameter).%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%sThe entry item action must not have an empty string for a rule name (the second parameter).%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]);
               }
             }
 
@@ -432,17 +432,17 @@ extern "C" {
                   }
                 }
 
-                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%sThe entry item action third parameter (and beyond) must be one of '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_asynchronous_s, thread_data.data->error.notable.after->string);
-                  fprintf(thread_data.data->error.to.stream, "%s', '", thread_data.data->error.context.before->string);
-                  fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_require_s, thread_data.data->error.notable.after->string);
-                  fprintf(thread_data.data->error.to.stream, "%s', or '", thread_data.data->error.context.before->string);
-                  fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_wait_s, thread_data.data->error.notable.after->string);
-                  fprintf(thread_data.data->error.to.stream, "%s' but instead has '", thread_data.data->error.context.before->string);
-                  fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[j].string, thread_data.data->error.notable.after->string);
-                  fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                  fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(main.data->error.to.stream, "%s%sThe entry item action third parameter (and beyond) must be one of '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                  fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_asynchronous_s, main.data->error.notable.after->string);
+                  fprintf(main.data->error.to.stream, "%s', '", main.data->error.context.before->string);
+                  fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_require_s, main.data->error.notable.after->string);
+                  fprintf(main.data->error.to.stream, "%s', or '", main.data->error.context.before->string);
+                  fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_wait_s, main.data->error.notable.after->string);
+                  fprintf(main.data->error.to.stream, "%s' but instead has '", main.data->error.context.before->string);
+                  fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[j].string, main.data->error.notable.after->string);
+                  fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
                 }
               }
             } // for
@@ -455,11 +455,11 @@ extern "C" {
                 status_action = action->status;
               }
 
-              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%sThe entry item action may not specify the reserved item '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_main_s, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%sThe entry item action may not specify the reserved item '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_main_s, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
               }
             }
           }
@@ -481,17 +481,17 @@ extern "C" {
                 status_action = action->status;
               }
 
-              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%sThe entry item action must have one of '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_kill_s, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s', '", thread_data.data->error.context.before->string);
-                fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_start_s, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s', or '", thread_data.data->error.context.before->string);
-                fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_stop_s, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s' but instead has '", thread_data.data->error.context.before->string);
-                fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[0].string, thread_data.data->error.notable.after->string);
-                fprintf(thread_data.data->error.to.stream, "%s'.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+              if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->error.to.stream, "%s%sThe entry item action must have one of '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_kill_s, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s', '", main.data->error.context.before->string);
+                fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_start_s, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s', or '", main.data->error.context.before->string);
+                fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_stop_s, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s' but instead has '", main.data->error.context.before->string);
+                fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[0].string, main.data->error.notable.after->string);
+                fprintf(main.data->error.to.stream, "%s'.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
               }
             }
 
@@ -511,17 +511,17 @@ extern "C" {
                 }
 
                 if (F_status_set_fine(status) == F_memory_not) {
-                  fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true);
+                  fll_error_print(main.data->error, F_status_set_fine(status), "fl_conversion_string_to_number_unsigned", F_true);
 
                   status_action = status;
                   break;
                 }
 
-                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%sThe entry item action parameter '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[1].string, thread_data.data->error.notable.after->string);
-                  fprintf(thread_data.data->error.to.stream, "%s' is not a valid supported number.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                  fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(main.data->error.to.stream, "%s%sThe entry item action parameter '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                  fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[1].string, main.data->error.notable.after->string);
+                  fprintf(main.data->error.to.stream, "%s' is not a valid supported number.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
                 }
               }
             }
@@ -606,14 +606,14 @@ extern "C" {
 #endif // _di_controller_entry_items_increase_by_
 
 #ifndef _di_controller_entry_read_
-  f_status_t controller_entry_read(const f_string_static_t entry_name, controller_thread_data_t thread_data, controller_cache_t *cache) {
+  f_status_t controller_entry_read(const f_string_static_t entry_name, controller_main_t main, controller_cache_t *cache) {
     f_status_t status = F_none;
 
     // @fixme all printfs in this function and child functions now need to be using the print mutex.
     // @fixme this should lock the global rule mutex until all rules for the entry have been processed.
 
-    thread_data.setting->entry.status = F_known_not;
-    thread_data.setting->entry.items.used = 0;
+    main.setting->entry.status = F_known_not;
+    main.setting->entry.items.used = 0;
 
     cache->action.line_action = 0;
     cache->action.line_item = 0;
@@ -650,7 +650,7 @@ extern "C" {
     cache->action.name_action.used = 0;
     cache->action.name_item.used = 0;
 
-    status = controller_file_load(controller_string_entries_s, entry_name, controller_string_entry_s, controller_string_entries_length, controller_string_entry_length, thread_data, cache);
+    status = controller_file_load(controller_string_entries_s, entry_name, controller_string_entry_s, controller_string_entries_length, controller_string_entry_length, main, cache);
 
     if (F_status_is_error_not(status)) {
       if (cache->buffer_file.used) {
@@ -659,24 +659,24 @@ extern "C" {
         status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments);
 
         if (F_status_is_error(status)) {
-          controller_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true, thread_data.thread);
+          controller_error_print(main.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true, main.thread);
         }
         else {
           status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file);
 
           if (F_status_is_error(status)) {
-            controller_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, thread_data.thread);
+            controller_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, main.thread);
           }
         }
       }
       else {
-        if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-          f_thread_mutex_lock(&thread_data.thread->lock.print);
+        if (main.data->error.verbosity != f_console_verbosity_quiet) {
+          f_thread_mutex_lock(&main.thread->lock.print);
 
-          fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-          fprintf(thread_data.data->error.to.stream, "%s%sThe entry file is empty.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.prefix ? thread_data.data->error.prefix : f_string_empty_s, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+          fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(main.data->error.to.stream, "%s%sThe entry file is empty.%s%c", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s, main.data->error.context.after->string, f_string_eol_s[0]);
 
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
+          f_thread_mutex_unlock(&main.thread->lock.print);
         }
 
         status = F_status_set_error(F_data_not);
@@ -684,10 +684,10 @@ extern "C" {
     }
 
     if (F_status_is_error_not(status) && cache->object_items.used) {
-      status = controller_entry_items_increase_by(cache->object_items.used, &thread_data.setting->entry.items);
+      status = controller_entry_items_increase_by(cache->object_items.used, &main.setting->entry.items);
 
       if (F_status_is_error(status)) {
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true);
       }
       else {
 
@@ -702,7 +702,7 @@ extern "C" {
 
         for (; i < cache->object_items.used; ++i) {
 
-          if (thread_data.thread->signal) {
+          if (main.thread->signal) {
             return F_signal;
           }
 
@@ -729,43 +729,43 @@ extern "C" {
           cache->action.name_action.used = 0;
           cache->action.name_item.used = 0;
 
-          status = controller_entry_items_increase_by(controller_default_allocation_step, &thread_data.setting->entry.items);
+          status = controller_entry_items_increase_by(controller_default_allocation_step, &main.setting->entry.items);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "controller_entry_items_increase_by", F_true);
             break;
           }
 
           status = controller_string_dynamic_partial_append_terminated(cache->buffer_file, cache->object_items.array[i], &cache->action.name_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_partial_append_terminated", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_partial_append_terminated", F_true);
             break;
           }
 
           status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->action.line_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true);
             break;
           }
 
           cache->action.line_item++;
 
-          for (j = (code & 0x1) ? 1 : 0; j < thread_data.setting->entry.items.used; ++j) {
+          for (j = (code & 0x1) ? 1 : 0; j < main.setting->entry.items.used; ++j) {
 
-            if (fl_string_dynamic_compare(thread_data.setting->entry.items.array[j].name, cache->action.name_item) == F_equal_to) {
-              if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-                f_thread_mutex_lock(&thread_data.thread->lock.print);
+            if (fl_string_dynamic_compare(main.setting->entry.items.array[j].name, cache->action.name_item) == F_equal_to) {
+              if (main.data->warning.verbosity == f_console_verbosity_debug) {
+                f_thread_mutex_lock(&main.thread->lock.print);
 
-                fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]);
-                fprintf(thread_data.data->warning.to.stream, "%s%sIgnoring duplicate entry item '", 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%s", thread_data.data->warning.context.after->string, thread_data.data->warning.notable.before->string, cache->action.name_file.string, thread_data.data->warning.notable.after->string);
-                fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
+                fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(main.data->warning.to.stream, "%s%sIgnoring duplicate entry item '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
+                fprintf(main.data->warning.to.stream, "%s%s%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string, cache->action.name_file.string, main.data->warning.notable.after->string);
+                fprintf(main.data->warning.to.stream, "%s'.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
 
-                controller_entry_error_print_cache(thread_data.data->warning, cache->action);
+                controller_entry_error_print_cache(main.data->warning, cache->action);
 
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
               }
 
               code |= 0x2;
@@ -782,39 +782,39 @@ extern "C" {
 
             at = 0;
 
-            if (!thread_data.setting->entry.items.used) {
-              thread_data.setting->entry.items.used = 1;
+            if (!main.setting->entry.items.used) {
+              main.setting->entry.items.used = 1;
             }
           }
-          else if (thread_data.setting->entry.items.used) {
-            at = thread_data.setting->entry.items.used++;
+          else if (main.setting->entry.items.used) {
+            at = main.setting->entry.items.used++;
           }
           else {
 
             // skip position 0, which is reserved for "main".
-            thread_data.setting->entry.items.array[0].name.used = 0;
+            main.setting->entry.items.array[0].name.used = 0;
 
             at = 1;
-            thread_data.setting->entry.items.used = 2;
+            main.setting->entry.items.used = 2;
           }
 
-          thread_data.setting->entry.items.array[at].line = cache->action.line_item;
+          main.setting->entry.items.array[at].line = cache->action.line_item;
 
-          status = controller_string_dynamic_append_terminated(cache->action.name_item, &thread_data.setting->entry.items.array[at].name);
+          status = controller_string_dynamic_append_terminated(cache->action.name_item, &main.setting->entry.items.array[at].name);
 
           if (F_status_is_error(status)) {
-            controller_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread);
+            controller_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
             break;
           }
 
-          status = controller_entry_actions_read(*range, thread_data, cache, &thread_data.setting->entry.items.array[at].actions);
+          status = controller_entry_actions_read(*range, main, cache, &main.setting->entry.items.array[at].actions);
 
           if (F_status_is_error(status)) {
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-            controller_entry_error_print_cache(thread_data.data->error, cache->action);
+            controller_entry_error_print_cache(main.data->error, cache->action);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
 
             if (F_status_set_fine(status) == F_memory_not) {
               break;
@@ -827,15 +827,15 @@ extern "C" {
           cache->action.name_item.used = 0;
 
           if (!(code & 0x1)) {
-            if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+            if (main.data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(thread_data.data->error.to.stream, "%s%sThe required entry item '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_string_main_s, thread_data.data->error.notable.after->string);
-              fprintf(thread_data.data->error.to.stream, "%s' was not found.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+              fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->error.to.stream, "%s%sThe required entry item '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+              fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_string_main_s, main.data->error.notable.after->string);
+              fprintf(main.data->error.to.stream, "%s' was not found.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
             }
 
             status = F_status_set_error(F_found_not);
@@ -849,15 +849,15 @@ extern "C" {
             // 0x1 = missing or not, 0x2 = one or more missing.
             uint8_t missing = 0;
 
-            for (i = 0; i < thread_data.setting->entry.items.used; ++i) {
+            for (i = 0; i < main.setting->entry.items.used; ++i) {
 
-              for (j = 0; j < thread_data.setting->entry.items.array[i].actions.used; ++j) {
+              for (j = 0; j < main.setting->entry.items.array[i].actions.used; ++j) {
 
-                if (thread_data.thread->signal) {
+                if (main.thread->signal) {
                   return F_signal;
                 }
 
-                action = &thread_data.setting->entry.items.array[i].actions.array[j];
+                action = &main.setting->entry.items.array[i].actions.array[j];
 
                 // only process actions that don't already have an error.
                 if (F_status_is_error(action->status)) continue;
@@ -865,9 +865,9 @@ extern "C" {
                 if (action->type == controller_entry_action_type_failsafe || action->type == controller_entry_action_type_item) {
                   missing |= 0x1;
 
-                  for (k = 0; k < thread_data.setting->entry.items.used; ++k) {
+                  for (k = 0; k < main.setting->entry.items.used; ++k) {
 
-                    if (fl_string_dynamic_compare(action->parameters.array[0], thread_data.setting->entry.items.array[k].name) == F_equal_to) {
+                    if (fl_string_dynamic_compare(action->parameters.array[0], main.setting->entry.items.array[k].name) == F_equal_to) {
                       if (missing & 0x1) {
                         missing -= 0x1;
                       }
@@ -880,33 +880,33 @@ extern "C" {
                     missing |= 0x2;
 
                     cache->action.line_action = action->line;
-                    cache->action.line_item = thread_data.setting->entry.items.array[i].line;
+                    cache->action.line_item = main.setting->entry.items.array[i].line;
 
-                    status = controller_string_dynamic_append_terminated(thread_data.setting->entry.items.array[i].name, &cache->action.name_item);
+                    status = controller_string_dynamic_append_terminated(main.setting->entry.items.array[i].name, &cache->action.name_item);
 
                     if (F_status_is_error(status)) {
-                      controller_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, thread_data.thread);
+                      controller_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_append_terminated", F_true, main.thread);
                       break;
                     }
 
-                    if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-                      f_thread_mutex_lock(&thread_data.thread->lock.print);
+                    if (main.data->error.verbosity != f_console_verbosity_quiet) {
+                      f_thread_mutex_lock(&main.thread->lock.print);
 
-                      fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-                      fprintf(thread_data.data->error.to.stream, "%s%sThe required entry item '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, action->parameters.array[0].string, thread_data.data->error.notable.after->string);
-                      fprintf(thread_data.data->error.to.stream, "%s' does not exist.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+                      fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+                      fprintf(main.data->error.to.stream, "%s%sThe required entry item '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+                      fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, action->parameters.array[0].string, main.data->error.notable.after->string);
+                      fprintf(main.data->error.to.stream, "%s' does not exist.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-                      controller_entry_error_print_cache(thread_data.data->error, cache->action);
+                      controller_entry_error_print_cache(main.data->error, cache->action);
 
-                      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                      f_thread_mutex_unlock(&main.thread->lock.print);
                     }
 
                     action->number = 0;
                     action->status = controller_status_simplify(F_found_not);
 
-                    // @fixme review how thread_data.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
-                    //thread_data.setting->entry.status = controller_status_simplify(F_found_not);
+                    // @fixme review how main.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
+                    //main.setting->entry.status = controller_status_simplify(F_found_not);
 
                     cache->action.name_action.used = 0;
                     cache->action.name_item.used = 0;
@@ -920,8 +920,8 @@ extern "C" {
 
             // the error is already fully printed and the entry status is already assigned, so immediately exit.
             if (missing & 0x2) {
-              // @fixme review how thread_data.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
-              //return thread_data.setting->entry.status;
+              // @fixme review how main.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
+              //return main.setting->entry.status;
             }
           }
         }
@@ -929,15 +929,15 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      controller_entry_error_print_cache(thread_data.data->error, cache->action);
+      controller_entry_error_print_cache(main.data->error, cache->action);
 
-      thread_data.setting->entry.status = controller_status_simplify(F_status_set_fine(status));
+      main.setting->entry.status = controller_status_simplify(F_status_set_fine(status));
     }
     else {
-      thread_data.setting->entry.status = F_none;
+      main.setting->entry.status = F_none;
     }
 
-    return thread_data.setting->entry.status;
+    return main.setting->entry.status;
   }
 #endif // _di_controller_entry_read_
 
index e4a8977c53b1cf248fb47fb3813c8e76b92a068e..1fb516c1c3a125873fa7496efc5341824a831024 100644 (file)
@@ -65,8 +65,8 @@ extern "C" {
  *
  * @param content_range
  *   The range in the list buffer representing the content.
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   A structure for containing and caching relevant data.
  * @param actions
@@ -94,7 +94,7 @@ extern "C" {
  * @see fll_fss_extended_read()
  */
 #ifndef _di_controller_entry_actions_read_
-  extern f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_thread_data_t thread_data, controller_cache_t *cache, controller_entry_actions_t *actions) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_entry_actions_read(const f_string_range_t content_range, controller_main_t main, controller_cache_t *cache, controller_entry_actions_t *actions) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_entry_actions_read_
 
 /**
@@ -170,11 +170,11 @@ extern "C" {
  *   The string identifying the entry.
  *   This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
  *   "/etc/controller/entries/example/my.entry" would have a rule id of "example/my".
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   The cache for the specific thread.
- *   This should be the cache thread_data.thread->asynchronouss.array[thread_data.id].cache.
+ *   This should be the cache main.thread->asynchronouss.array[main.id].cache.
  *
  * @return
  *   F_none on success.
@@ -206,7 +206,7 @@ extern "C" {
  * @see fll_fss_basic_list_read()
  */
 #ifndef _di_controller_entry_read_
-  extern f_status_t controller_entry_read(const f_string_static_t entry_name, controller_thread_data_t thread_data, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_entry_read(const f_string_static_t entry_name, controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_entry_read_
 
 #ifdef __cplusplus
index 7c8e72906d538f14fdd7c9ca0e43352bafd89de9..317db168d0c92904648efcf9056f08af47fd7827 100644 (file)
@@ -31,13 +31,33 @@ extern "C" {
   }
 #endif // _di_controller_rule_action_method_name_
 
+#ifndef _di_controller_rule_find_
+  f_status_t controller_rule_find(const f_string_static_t alias, const controller_rules_t rules, f_array_length_t *at) {
+
+    if (!alias.used) return F_none;
+    if (!rules.used) return F_false;
+
+    for (f_array_length_t i = 0; i < rules.used; ++i) {
+
+      if (fl_string_dynamic_compare(alias, rules.array[i].alias) == F_equal_to) {
+        *at = i;
+        return F_true;
+      }
+    } // for
+
+    return F_false;
+  }
+#endif // _di_controller_rule_find_
+
 #ifndef _di_controller_rule_parameters_read_
   f_status_t controller_rule_parameters_read(const controller_data_t data, const f_string_static_t buffer, f_fss_object_t *object, f_fss_content_t *content, f_string_dynamics_t *parameters) {
+
     f_status_t status = F_none;
 
     parameters->used = 0;
 
     if (object && object->start <= object->start) {
+
       status = f_string_dynamics_increase(parameters);
 
       if (F_status_is_error(status)) {
@@ -65,6 +85,7 @@ extern "C" {
     }
 
     if (content && content->used) {
+
       for (f_array_length_t i = 0; i < content->used; ++i) {
 
         if (content->array[i].start > content->array[i].start) continue;
@@ -181,6 +202,7 @@ extern "C" {
 
 #ifndef _di_controller_rule_action_read_
   f_status_t controller_rule_action_read(const controller_data_t data, const uint8_t type, const uint8_t method, controller_cache_t *cache, controller_rule_item_t *item, controller_rule_actions_t *actions, f_string_range_t *range) {
+
     f_status_t status = F_none;
 
     if (method == controller_rule_action_method_extended_list) {
@@ -217,6 +239,7 @@ extern "C" {
               fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamics_increase", F_true);
             }
             else {
+
               actions->array[actions->used].type = type;
               actions->array[actions->used].line = cache->action.line_action;
               actions->array[actions->used].parameters.used = 0;
@@ -249,17 +272,18 @@ extern "C" {
             fll_error_print(data.error, F_status_set_fine(status), "fll_fss_extended_read", F_true);
           }
           else {
+
             status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_item);
 
             if (F_status_is_error(status)) {
               fll_error_print(data.error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
             }
             else {
+
               f_array_length_t i = 0;
               f_array_length_t j = 0;
 
               for (; i < cache->object_actions.used; ++i) {
-
                 status = controller_rule_actions_increase_by(controller_default_allocation_step, actions);
 
                 if (F_status_is_error(status)) {
@@ -304,6 +328,7 @@ extern "C" {
       }
     }
     else {
+
       cache->content_action.used = 0;
       cache->delimits.used = 0;
 
@@ -333,7 +358,6 @@ extern "C" {
             actions->array[actions->used].status = F_known_not;
 
             for (f_array_length_t i = 0; i < cache->content_action.used; ++i) {
-
               status = f_string_dynamic_partial_mash_nulless(f_string_space_s, f_string_space_length, cache->buffer_item, cache->content_action.array[i], &actions->array[actions->used].parameters.array[0]);
               if (F_status_is_error(status)) break;
             } // for
@@ -360,6 +384,7 @@ extern "C" {
             fll_error_print(data.error, F_status_set_fine(status), "f_fss_count_lines", F_true);
           }
           else {
+
             actions->array[actions->used].type = type;
             actions->array[actions->used].line += ++item->line;
             actions->array[actions->used].parameters.used = 0;
@@ -400,6 +425,7 @@ extern "C" {
 
 #ifndef _di_controller_rule_copy_
   f_status_t controller_rule_copy(const controller_rule_t source, controller_rule_t *destination) {
+
     f_status_t status = F_none;
 
     destination->timeout_kill = source.timeout_kill;
@@ -414,7 +440,7 @@ extern "C" {
     destination->timestamp.seconds = source.timestamp.seconds;
     destination->timestamp.nanoseconds = source.timestamp.nanoseconds;
 
-    destination->id.used = 0;
+    destination->alias.used = 0;
     destination->name.used = 0;
     destination->path.used = 0;
     destination->script.used = 0;
@@ -435,8 +461,8 @@ extern "C" {
 
     destination->items.used = 0;
 
-    if (source.id.used) {
-      status = f_string_dynamic_append(source.id, &destination->id);
+    if (source.alias.used) {
+      status = f_string_dynamic_append(source.alias, &destination->alias);
       if (F_status_is_error(status)) return status;
     }
 
@@ -617,8 +643,8 @@ extern "C" {
 
       if (status == F_control_group || status == F_limit || status == F_processor || status == F_schedule) {
         fprintf(output.to.stream, "%s' failed due to a failure to setup the '", output.context.before->string);
-
         fprintf(output.to.stream, "%s%s", output.context.after->string, output.notable.before->string);
+
         if (status == F_control_group) {
           fprintf(output.to.stream, "%s", controller_string_control_group_s);
         }
@@ -631,6 +657,7 @@ extern "C" {
         else if (status == F_schedule) {
           fprintf(output.to.stream, "%s", controller_string_scheduler_s);
         }
+
         fprintf(output.to.stream, "%s", output.notable.after->string);
         fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
       }
@@ -671,7 +698,8 @@ extern "C" {
 #endif // _di_controller_rule_error_print_need_want_wish_
 
 #ifndef _di_controller_rule_execute_
-  f_status_t controller_rule_execute(const uint8_t type, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) {
+  f_status_t controller_rule_execute(const uint8_t type, const uint8_t options, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) {
+
     f_status_t status = F_none;
     f_status_t success = F_false;
 
@@ -721,7 +749,7 @@ extern "C" {
         status = fll_control_group_prepare(rule->control_group);
 
         if (F_status_is_error(status)) {
-          controller_error_print(thread_data.data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, thread_data.thread);
+          controller_error_print(main.data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, main.thread);
 
           rule->status = F_status_set_error(F_failure);
           return status;
@@ -762,7 +790,7 @@ extern "C" {
     status = fl_environment_load_names(rule->environment, &environment);
 
     if (F_status_is_error(status)) {
-      controller_error_print(thread_data.data->error, F_status_set_fine(status), "fl_environment_load_names", F_true, thread_data.thread);
+      controller_error_print(main.data->error, F_status_set_fine(status), "fl_environment_load_names", F_true, main.thread);
 
       rule->status = F_status_set_error(F_failure);
       return status;
@@ -770,7 +798,7 @@ extern "C" {
 
     for (i = 0; i < rule->items.used; ++i) {
 
-      if (thread_data.thread->signal) {
+      if (main.thread->signal) {
         status = F_signal;
         break;
       }
@@ -779,7 +807,7 @@ extern "C" {
 
       for (j = 0; j < rule->items.array[i].actions.used; ++j) {
 
-        if (thread_data.thread->signal) {
+        if (main.thread->signal) {
           status = F_signal;
           break;
         }
@@ -799,7 +827,7 @@ extern "C" {
             execute_set.parameter.option |= fl_execute_parameter_option_path;
           }
 
-          status = controller_rule_execute_foreground(rule->items.array[i].type, rule->items.array[i].actions.array[j], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, thread_data, rule);
+          status = controller_rule_execute_foreground(rule->items.array[i].type, rule->items.array[i].actions.array[j], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, main, rule);
 
           if (status == F_child) break;
 
@@ -812,13 +840,14 @@ extern "C" {
           success = F_true;
         }
         else if (rule->items.array[i].type == controller_rule_item_type_script) {
+
           execute_set.parameter.data = &rule->items.array[i].actions.array[j].parameters.array[0];
 
           if (rule->script.used && strchr(rule->script.string, f_path_separator_s[0])) {
             execute_set.parameter.option |= fl_execute_parameter_option_path;
           }
 
-          status = controller_rule_execute_foreground(rule->items.array[i].type, rule->items.array[i].actions.array[j], rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, options, &execute_set, thread_data, rule);
+          status = controller_rule_execute_foreground(rule->items.array[i].type, rule->items.array[i].actions.array[j], rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, options, &execute_set, main, rule);
 
           if (status == F_child) break;
 
@@ -836,7 +865,7 @@ extern "C" {
             execute_set.parameter.option |= fl_execute_parameter_option_path;
           }
 
-          status = controller_rule_execute_pid_with(rule->items.array[i].type, rule->items.array[i].actions.array[j], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, thread_data, rule);
+          status = controller_rule_execute_pid_with(rule->items.array[i].type, rule->items.array[i].actions.array[j], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, main, rule);
 
           if (status == F_child) break;
 
@@ -850,15 +879,15 @@ extern "C" {
         }
         else {
 
-          if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-            f_thread_mutex_lock(&thread_data.thread->lock.print);
+          if (main.data->warning.verbosity == f_console_verbosity_debug) {
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-            fprintf(thread_data.data->warning.to.stream, "%c", f_string_eol_s[0]);
-            fprintf(thread_data.data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.prefix ? thread_data.data->warning.prefix : f_string_empty_s, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
+            fprintf(main.data->warning.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(main.data->warning.to.stream, "%s%sAction type is unknown, ignoring.%s%c", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s, main.data->warning.context.after->string, f_string_eol_s[0]);
 
-            controller_rule_error_print(thread_data.data->warning, cache->action, F_true);
+            controller_rule_error_print(main.data->warning, cache->action, F_true);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
           rule->items.array[i].actions.array[j].status = F_ignore;
@@ -897,31 +926,30 @@ extern "C" {
 #endif // _di_controller_rule_execute_
 
 #ifndef _di_controller_rule_execute_foreground_
-  f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_data_t thread_data, controller_rule_t *rule) {
+  f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) {
 
     f_status_t status = F_none;
     int result = 0;
     pid_t id_process = 0;
 
     if (options & controller_rule_option_simulate) {
+      if (main.data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main.thread->lock.print);
 
-      if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-        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, "Simulating execution of '");
-        fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, thread_data.data->context.reset.string);
-        fprintf(thread_data.data->output.stream, "' with the arguments: '%s", thread_data.data->context.important.string);
+        fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+        fprintf(main.data->output.stream, "Simulating execution of '");
+        fprintf(main.data->output.stream, "%s%s%s", main.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, main.data->context.reset.string);
+        fprintf(main.data->output.stream, "' with the arguments: '%s", main.data->context.important.string);
 
         for (f_array_length_t i = program ? 0 : 1; i < arguments.used; ++i) {
-          fprintf(thread_data.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string);
+          fprintf(main.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string);
         } // for
 
-        fprintf(thread_data.data->output.stream, "%s' from '", thread_data.data->context.reset.string);
-        fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->context.reset.string);
-        fprintf(thread_data.data->output.stream, "%s'.%c", thread_data.data->context.reset.string, f_string_eol_s[0]);
+        fprintf(main.data->output.stream, "%s' from '", main.data->context.reset.string);
+        fprintf(main.data->output.stream, "%s%s%s", main.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, main.data->context.reset.string);
+        fprintf(main.data->output.stream, "%s'.%c", main.data->context.reset.string, f_string_eol_s[0]);
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
       }
 
       // sleep for less than a second to better show simulation of synchronous vs asynchronous.
@@ -941,13 +969,13 @@ extern "C" {
       result = 0;
 
       // assign the child process id to the asynchronous thread to allow for the cancel process to send appropriate termination signals to the child process.
-      thread_data.thread->asynchronouss.array[thread_data.id].child = id_process;
+      main.thread->asynchronouss.array[main.id].child = id_process;
 
       // have the parent wait for the child process to finish.
       waitpid(id_process, &result, WUNTRACED | WCONTINUED);
 
       // remove the pid now that waidpid() has returned.
-      thread_data.thread->asynchronouss.array[thread_data.id].child = 0;
+      main.thread->asynchronouss.array[main.id].child = 0;
 
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
@@ -977,19 +1005,19 @@ extern "C" {
     if (F_status_is_error(status)) {
       status = F_status_set_fine(status);
 
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
       if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) {
-        controller_rule_error_print_execute(thread_data.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status);
+        controller_rule_error_print_execute(main.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status);
       }
       else if (status == F_file_found_not) {
-        controller_rule_error_print_execute_not_found(thread_data.data->error, F_false, program);
+        controller_rule_error_print_execute_not_found(main.data->error, F_false, program);
       }
       else {
-        fll_error_print(thread_data.data->error, status, "fll_execute_program", F_true);
+        fll_error_print(main.data->error, status, "fll_execute_program", F_true);
       }
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
 
       status = F_status_set_error(status);
     }
@@ -999,7 +1027,7 @@ extern "C" {
 #endif // _di_controller_rule_execute_foreground_
 
 #ifndef _di_controller_rule_execute_pid_with_
-  f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_data_t thread_data, controller_rule_t *rule) {
+  f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) {
 
     f_status_t status = F_none;
     int result = 0;
@@ -1014,23 +1042,24 @@ extern "C" {
 
     if (options & controller_rule_option_simulate) {
 
-      if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&thread_data.thread->lock.print);
+      if (main.data->error.verbosity != f_console_verbosity_quiet) {
 
-        fprintf(thread_data.data->output.stream, "%c", f_string_eol_s[0]);
-        fprintf(thread_data.data->output.stream, "Simulating execution of '");
-        fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, thread_data.data->context.reset.string);
-        fprintf(thread_data.data->output.stream, "' with the arguments: '%s", thread_data.data->context.important.string);
+        f_thread_mutex_lock(&main.thread->lock.print);
+
+        fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+        fprintf(main.data->output.stream, "Simulating execution of '");
+        fprintf(main.data->output.stream, "%s%s%s", main.data->context.title.string, program ? program : arguments.used && arguments.array[0].used ? arguments.array[0].string : f_string_empty_s, main.data->context.reset.string);
+        fprintf(main.data->output.stream, "' with the arguments: '%s", main.data->context.important.string);
 
         for (f_array_length_t i = program ? 0 : 1; i < arguments.used; ++i) {
-          fprintf(thread_data.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string);
+          fprintf(main.data->output.stream, "%s%s", (program && i || !program && i > 1) ? f_string_space_s : "", arguments.array[i].string);
         } // for
 
-        fprintf(thread_data.data->output.stream, "%s' from '", thread_data.data->context.reset.string);
-        fprintf(thread_data.data->output.stream, "%s%s%s", thread_data.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->context.reset.string);
-        fprintf(thread_data.data->output.stream, "%s'.%c", thread_data.data->context.reset.string, f_string_eol_s[0]);
+        fprintf(main.data->output.stream, "%s' from '", main.data->context.reset.string);
+        fprintf(main.data->output.stream, "%s%s%s", main.data->context.notable.string, rule->name.used ? rule->name.string : f_string_empty_s, main.data->context.reset.string);
+        fprintf(main.data->output.stream, "%s'.%c", main.data->context.reset.string, f_string_eol_s[0]);
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
       }
 
       // sleep for less than a second to better show simulation of synchronous vs asynchronous.
@@ -1050,13 +1079,13 @@ extern "C" {
       result = 0;
 
       // assign the child process id to the asynchronous thread to allow for the cancel process to send appropriate termination signals to the child process.
-      thread_data.thread->asynchronouss.array[thread_data.id].child = id_process;
+      main.thread->asynchronouss.array[main.id].child = id_process;
 
       // have the parent wait for the child process to finish.
       waitpid(id_process, &result, WUNTRACED | WCONTINUED);
 
       // remove the pid now that waidpid() has returned.
-      thread_data.thread->asynchronouss.array[thread_data.id].child = 0;
+      main.thread->asynchronouss.array[main.id].child = 0;
 
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
@@ -1065,6 +1094,7 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
+
       status = F_status_set_fine(status);
 
       if (status == F_child || status == F_capability || status == F_group || status == F_nice || status == F_user) {
@@ -1084,21 +1114,22 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
+
       status = F_status_set_fine(status);
 
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
       if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) {
-        controller_rule_error_print_execute(thread_data.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status);
+        controller_rule_error_print_execute(main.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status);
       }
       else if (status == F_file_found_not) {
-        controller_rule_error_print_execute_not_found(thread_data.data->error, F_false, program);
+        controller_rule_error_print_execute_not_found(main.data->error, F_false, program);
       }
       else {
-        fll_error_print(thread_data.data->error, status, "fll_execute_program", F_true);
+        fll_error_print(main.data->error, status, "fll_execute_program", F_true);
       }
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
 
       return F_status_set_error(status);
     }
@@ -1109,48 +1140,35 @@ 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) {
-
-    f_array_length_t i = thread_data.setting->rules.used;
-
-    for (; i; --i) {
-      if (fl_string_dynamic_compare(rule_id, thread_data.setting->rules.array[i].id) == F_equal_to) return i;
-    } // for
-
-    return thread_data.setting->rules.used;
-  }
-#endif // _di_controller_rule_find_loaded_
-
 #ifndef _di_controller_rule_id_construct_
-  f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *id) {
+  f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *alias) {
+
     f_status_t status = F_none;
 
-    id->used = 0;
+    alias->used = 0;
 
-    status = f_string_dynamic_partial_append_nulless(source, directory, id);
+    status = f_string_dynamic_partial_append_nulless(source, directory, alias);
 
     if (F_status_is_error(status)) {
       fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true);
       return status;
     }
 
-    status = f_string_append(f_path_separator_s, f_path_separator_length, id);
+    status = f_string_append(f_path_separator_s, f_path_separator_length, alias);
 
     if (F_status_is_error(status)) {
       fll_error_print(data.error, F_status_set_fine(status), "f_string_append", F_true);
       return status;
     }
 
-    status = f_string_dynamic_partial_append_nulless(source, basename, id);
+    status = f_string_dynamic_partial_append_nulless(source, basename, alias);
 
     if (F_status_is_error(status)) {
       fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true);
       return status;
     }
 
-    status = f_string_dynamic_terminate_after(id);
+    status = f_string_dynamic_terminate_after(alias);
 
     if (F_status_is_error(status)) {
       fll_error_print(data.error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
@@ -1162,6 +1180,7 @@ extern "C" {
 
 #ifndef _di_controller_rule_item_read_
   f_status_t controller_rule_item_read(const controller_data_t data, controller_cache_t *cache, controller_rule_item_t *item) {
+
     f_status_t status = F_none;
 
     f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_item.used);
@@ -1276,6 +1295,7 @@ extern "C" {
 
       if (multiple) {
         if (type == controller_rule_action_type_create || type == controller_rule_action_type_group || type == controller_rule_action_type_use || type == controller_rule_action_type_user) {
+
           if (data.error.verbosity != f_console_verbosity_quiet) {
             fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
             fprintf(data.error.to.stream, "%s%sFSS Extended List is not allowed for the rule item action '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
@@ -1459,6 +1479,7 @@ extern "C" {
 
 #ifndef _di_controller_rule_path_
   f_status_t controller_rule_path(const controller_data_t data, const controller_setting_t setting, const f_string_static_t path_directory, const f_string_static_t path_name, f_string_dynamic_t *path) {
+
     f_status_t status = F_none;
 
     path->used = 0;
@@ -1528,9 +1549,7 @@ extern "C" {
 #endif // _di_controller_rule_path_
 
 #ifndef _di_controller_rule_process_
-  f_status_t controller_rule_process(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) {
-
-    // @todo need to update accordingly with new parameters "rule" and "at_process".
+  f_status_t controller_rule_process(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) {
 
     switch (action) {
       case controller_rule_action_type_freeze:
@@ -1546,71 +1565,24 @@ extern "C" {
 
       default:
 
-        if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-          f_thread_mutex_lock(&thread_data.thread->lock.print);
+        if (main.data->error.verbosity != f_console_verbosity_quiet) {
+          f_thread_mutex_lock(&main.thread->lock.print);
 
-          fprintf(thread_data.data->error.to.stream, "%c", f_string_eol_s[0]);
-          fprintf(thread_data.data->error.to.stream, "%s%sUnsupported action type '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_rule_action_type_name(action), thread_data.data->error.notable.after->string);
-          fprintf(thread_data.data->error.to.stream, "%s' while attempting to execute rule.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+          fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(main.data->error.to.stream, "%s%sUnsupported action type '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+          fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_rule_action_type_name(action), main.data->error.notable.after->string);
+          fprintf(main.data->error.to.stream, "%s' while attempting to execute rule.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-          controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+          controller_rule_error_print(main.data->error, cache->action, F_true);
 
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
+          f_thread_mutex_unlock(&main.thread->lock.print);
         }
 
         return F_status_set_error(F_parameter);
     }
 
-    if (index >= thread_data.setting->rules.used) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
-
-      fll_error_print(thread_data.data->error, F_parameter, "controller_rule_process", F_true);
-      controller_rule_error_print(thread_data.data->error, cache->action, F_true);
-
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
-
-      return F_status_set_error(F_parameter);
-    }
-
     f_status_t status = F_none;
 
-    f_macro_array_lengths_t_increase_by(status, thread_data.thread->asynchronouss.array[thread_data.id].stack, controller_default_allocation_step)
-
-    if (F_status_is_error(status)) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
-
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true);
-      controller_rule_error_print(thread_data.data->error, cache->action, F_true);
-
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
-
-      return status;
-    }
-
-    f_array_length_t i = 0;
-
-    for (; i < thread_data.thread->asynchronouss.array[thread_data.id].stack.used; ++i) {
-
-      if (thread_data.thread->asynchronouss.array[thread_data.id].stack.array[i] == index) {
-        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, "%c", f_string_eol_s[0]);
-          fprintf(thread_data.data->error.to.stream, "%s%sThe rule '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, thread_data.setting->rules.array[i].name.string, thread_data.data->error.notable.after->string);
-          fprintf(thread_data.data->error.to.stream, "%s' is already on the execution stack, this recursion is prohibited.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
-
-          controller_rule_error_print(thread_data.data->error, cache->action, F_true);
-
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
-        }
-
-        // never continue on recursion errors even in simulate mode.
-        return F_status_set_error(F_recurse);
-      }
-    }
-
     cache->action.name_action.used = 0;
     cache->action.name_item.used = 0;
     cache->action.name_file.used = 0;
@@ -1622,25 +1594,25 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true);
-      controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "f_string_append", F_true);
+      controller_rule_error_print(main.data->error, cache->action, F_true);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
 
-    status = f_string_dynamic_append(thread_data.setting->rules.array[index].id, &cache->action.name_file);
+    status = f_string_dynamic_append(rule.alias, &cache->action.name_file);
 
     if (F_status_is_error(status)) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true);
-      controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_append", F_true);
+      controller_rule_error_print(main.data->error, cache->action, F_true);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
@@ -1652,12 +1624,12 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_append", F_true);
-      controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "f_string_append", F_true);
+      controller_rule_error_print(main.data->error, cache->action, F_true);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
@@ -1665,41 +1637,30 @@ extern "C" {
     status = f_string_dynamic_terminate_after(&cache->action.name_file);
 
     if (F_status_is_error(status)) {
-      f_thread_mutex_lock(&thread_data.thread->lock.print);
+      f_thread_mutex_lock(&main.thread->lock.print);
 
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
-      controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
+      controller_rule_error_print(main.data->error, cache->action, F_true);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.print);
+      f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
 
-    thread_data.thread->asynchronouss.array[thread_data.id].stack.array[thread_data.thread->asynchronouss.array[thread_data.id].stack.used++] = index;
-
-    controller_rule_t *rule = &thread_data.setting->rules.array[index];
-
-    if ((options & controller_rule_option_simulate) && thread_data.data->parameters[controller_parameter_validate].result == f_console_result_found) {
-      // @fixme the cache should probably store a rule type and then that can used instead of calling controller_rule_copy() here.
-      controller_rule_t rule_simulate = controller_rule_t_initialize;
-
-      status = controller_rule_copy(rule, &rule_simulate);
-
-      if (F_status_is_error(status)) {
-        controller_rule_delete_simple(&rule_simulate);
-
-        return status;
-      }
-
-      controller_rule_simulate(controller_rule_action_type_start, options, thread_data, cache, &rule_simulate);
-
-      controller_rule_delete_simple(&rule_simulate);
+    if ((options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) {
+      controller_rule_simulate(rule, controller_rule_action_type_start, options, main, cache);
     }
 
+    f_array_length_t i = 0;
+
     {
       f_array_length_t j = 0;
       f_array_length_t k = 0;
-      f_array_length_t at = 0;
+      f_array_length_t id_rule = 0;
+      f_array_length_t id_process = 0;
+
+      controller_rule_t *rule_other = 0;
+      controller_process_t *process_other = 0;
 
       f_string_dynamics_t * const dynamics[] = {
         &rule->need,
@@ -1713,174 +1674,157 @@ extern "C" {
         "wished for",
       };
 
+      // i==0 is need, i==1 is want, i==2 is wish.
+      // loop through all dependencies: wait for depedency, execute dependency, fail due to missing required dependency, or skip unrequired missing dependencies.
       for (i = 0; i < 3; ++i) {
 
         for (j = 0; j < dynamics[i]->used; ++j) {
-          at = controller_rule_find_loaded(*thread_data.data, *thread_data.setting, dynamics[i]->array[j]);
 
-          if (at == thread_data.setting->rules.used) {
+          f_thread_lock_read(&main.thread->lock.rule);
+
+          status = controller_find_process(dynamics[i]->array[j], *main.thread->processs, &id_process);
+
+          if (status == F_true) {
+            status = controller_rule_find(dynamics[i]->array[j], main.setting->rules, &id_rule);
+          }
+
+          if (status != F_true) {
+            id_rule = main.setting->rules.used;
+
             if (i == 0) {
-              f_thread_mutex_lock(&thread_data.thread->lock.print);
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-              controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "was not found");
+              controller_rule_error_print_need_want_wish(main.data->error, strings[i], dynamics[i]->array[j].string, "was not found");
+              controller_rule_error_print(main.data->error, cache->action, F_true);
+
+              f_thread_mutex_unlock(&main.thread->lock.print);
 
               status = F_status_set_error(F_found_not);
-              controller_rule_error_print(thread_data.data->error, cache->action, F_true);
 
-              f_thread_mutex_unlock(&thread_data.thread->lock.print);
+              if (!(options & controller_rule_option_simulate)) {
+                f_thread_unlock(&main.thread->lock.rule);
 
-              if (!(options & controller_rule_option_simulate)) break;
+                break;
+              }
             }
             else {
-              if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-                f_thread_mutex_lock(&thread_data.thread->lock.print);
+              if (main.data->warning.verbosity == f_console_verbosity_debug) {
+                f_thread_mutex_lock(&main.thread->lock.print);
 
-                controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "was not found");
-                controller_rule_error_print(thread_data.data->warning, cache->action, F_true);
+                controller_rule_error_print_need_want_wish(main.data->warning, strings[i], dynamics[i]->array[j].string, "was not found");
+                controller_rule_error_print(main.data->warning, cache->action, F_true);
 
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
               }
             }
           }
 
-          if (F_status_is_error_not(status) && at < thread_data.setting->rules.used) {
+          if (status == F_true && id_rule < main.setting->rules.used) {
+            f_thread_lock_read(&main.thread->lock.process);
 
-            f_thread_mutex_lock(&thread_data.setting->rules.array[at].lock);
+            process_other = &main.thread->processs->array[id_process];
 
-            while (thread_data.enabled && thread_data.setting->rules.array[at].status == F_known_not) {
-              f_thread_condition_wait(&thread_data.setting->rules.array[at].wait, &thread_data.setting->rules.array[at].lock);
-            } // while
+            f_thread_lock_read(&process_other->active);
+            f_thread_lock_read(&process_other->lock);
 
-            if (!thread_data.enabled) {
-              f_thread_condition_signal(&thread_data.setting->rules.array[at].wait);
-              f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock);
+            if (process_other->status == F_known_not && (process_other->state == controller_process_state_active || process_other->state == controller_process_state_busy)) {
+              f_thread_unlock(&process_other->lock);
+              f_thread_condition_wait(&process_other->wait, &process_other->running);
 
-              status = F_signal;
-              break;
+              // always pass the signal along when done waiting.
+              f_thread_condition_signal(&process->wait);
+              f_thread_mutex_unlock(&process->running);
+            }
+            else {
+              f_thread_unlock(&process_other->lock);
             }
 
-            // when the status is unknown, then the rule has not been executed, so attempt to execute it.
-            if (thread_data.setting->rules.array[at].status == F_known_not) {
-
-              f_macro_array_lengths_t_increase_by(status, thread_data.thread->asynchronouss.array[thread_data.id].stack, controller_default_allocation_step)
-
-              if (F_status_is_error(status)) {
-                f_thread_mutex_lock(&thread_data.thread->lock.print);
-
-                fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_macro_array_lengths_t_increase_by", F_true);
-                controller_rule_error_print(thread_data.data->error, cache->action, F_true);
-
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
-
-                f_thread_condition_signal(&thread_data.setting->rules.array[at].wait);
-                f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock);
-
-                // always exit on memory errors, even in simulate mode.
-                break;
-              }
-
-              // 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;
-              const f_array_length_t cache_line_item = cache->action.line_item;
+            if (!main.thread->enabled) {
+              f_thread_unlock(&main.thread->lock.process);
+              f_thread_unlock(&process_other->active);
+              f_thread_unlock(&main.thread->lock.rule);
 
-              const f_array_length_t cache_name_action_used = cache->action.name_action.used;
-              const f_array_length_t cache_name_item_used = cache->action.name_item.used;
-              const f_array_length_t cache_name_file_used = cache->action.name_file.used;
+              status = F_signal;
+              break;
+            }
 
-              char cache_name_action[cache_name_action_used];
-              char cache_name_item[cache_name_item_used];
-              char cache_name_file[cache_name_file_used];
+            f_thread_unlock(&main.thread->lock.process);
 
-              memcpy(cache_name_action, cache->action.name_action.string, cache->action.name_action.used);
-              memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used);
-              memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used);
+            rule_other = &main.setting->rules.array[id_rule];
 
-              // @fixme the cache should probably store a rule type and then that can used instead of calling controller_rule_copy(), which would need to be copied here just like the other cache properties.
+            // attempt to (synchronously) execute the rule when the status is unknown (the rule has not yet been run).
+            if (rule_other->status == F_known_not) {
 
-              // recursive rule processing is to always be synchronous.
-              status = controller_rule_process(at, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, thread, 0);
+              status = controller_rule_process_begin(F_false, rule_other->alias, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, process->stack, main, cache);
 
               if (status == F_child || status == F_signal) {
-                f_thread_condition_signal(&thread_data.setting->rules.array[at].wait);
-                f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock);
+                f_thread_unlock(&process_other->active);
+                f_thread_unlock(&main.thread->lock.rule);
 
                 break;
               }
 
-              // restore cache.
-              memcpy(cache->action.name_action.string, cache_name_action, cache_name_action_used);
-              memcpy(cache->action.name_item.string, cache_name_item, cache_name_item_used);
-              memcpy(cache->action.name_file.string, cache_name_file, cache_name_file_used);
-
-              cache->action.name_action.string[cache_name_action_used] = 0;
-              cache->action.name_item.string[cache_name_item_used] = 0;
-
-              cache->action.name_action.used = cache_name_action_used;
-              cache->action.name_item.used = cache_name_item_used;
-              cache->action.name_file.used = cache_name_file_used;
-
-              cache->action.line_action = cache_line_action;
-              cache->action.line_item = cache_line_item;
-
               if (F_status_is_error(status)) {
                 if (i == 0 || i == 1 || F_status_set_fine(status) == F_memory_not) {
+                  f_thread_mutex_lock(&main.thread->lock.print);
 
-                  f_thread_mutex_lock(&thread_data.thread->lock.print);
-
-                  controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "failed during execution");
-                  controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+                  controller_rule_error_print_need_want_wish(main.data->error, strings[i], rule_other->alias.string, "failed during execution");
+                  controller_rule_error_print(main.data->error, cache->action, F_true);
 
-                  f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                  f_thread_mutex_unlock(&main.thread->lock.print);
 
                   if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
-                    f_thread_condition_signal(&thread_data.setting->rules.array[at].wait);
-                    f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock);
+                    f_thread_unlock(&process_other->active);
+                    f_thread_unlock(&main.thread->lock.rule);
 
                     break;
                   }
                 }
                 else {
-                  if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-                    f_thread_mutex_lock(&thread_data.thread->lock.print);
+                  if (main.data->warning.verbosity == f_console_verbosity_debug) {
+                    f_thread_mutex_lock(&main.thread->lock.print);
 
-                    controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "failed during execution");
-                    controller_rule_error_print(thread_data.data->warning, cache->action, F_true);
+                    controller_rule_error_print_need_want_wish(main.data->warning, strings[i], rule_other->alias.string, "failed during execution");
+                    controller_rule_error_print(main.data->warning, cache->action, F_true);
 
-                    f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                    f_thread_mutex_unlock(&main.thread->lock.print);
                   }
                 }
               }
             }
 
-            f_thread_condition_signal(&thread_data.setting->rules.array[at].wait);
-            f_thread_mutex_unlock(&thread_data.setting->rules.array[at].lock);
-
-            if (F_status_is_error(thread_data.setting->rules.array[at].status)) {
+            f_thread_unlock(&process_other->active);
 
+            if (F_status_is_error(rule_other->status)) {
               if (i == 0 || i == 1) {
-                f_thread_mutex_lock(&thread_data.thread->lock.print);
+                f_thread_mutex_lock(&main.thread->lock.print);
 
-                controller_rule_error_print_need_want_wish(thread_data.data->error, strings[i], dynamics[i]->array[j].string, "is in a failed state");
+                controller_rule_error_print_need_want_wish(main.data->error, strings[i], rule_other->alias.string, "is in a failed state");
 
                 status = F_status_set_error(F_found_not);
-                controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+                controller_rule_error_print(main.data->error, cache->action, F_true);
 
-                f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
 
-                if (!(options & controller_rule_option_simulate)) break;
+                if (!(options & controller_rule_option_simulate)) {
+                  f_thread_unlock(&main.thread->lock.rule);
+                  break;
+                }
               }
               else {
-                if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-                  f_thread_mutex_lock(&thread_data.thread->lock.print);
+                if (main.data->warning.verbosity == f_console_verbosity_debug) {
+                  f_thread_mutex_lock(&main.thread->lock.print);
 
-                  controller_rule_error_print_need_want_wish(thread_data.data->warning, strings[i], dynamics[i]->array[j].string, "is in a failed state");
-                  controller_rule_error_print(thread_data.data->warning, cache->action, F_true);
+                  controller_rule_error_print_need_want_wish(main.data->warning, strings[i], rule_other->alias.string, "is in a failed state");
+                  controller_rule_error_print(main.data->warning, cache->action, F_true);
 
-                  f_thread_mutex_unlock(&thread_data.thread->lock.print);
+                  f_thread_mutex_unlock(&main.thread->lock.print);
                 }
               }
             }
           }
+
+          f_thread_unlock(&main.thread->lock.rule);
         } // for
 
         if (status == F_child || status == F_signal) break;
@@ -1893,15 +1837,14 @@ extern "C" {
       return status;
     }
 
-    if (!thread_data.enabled) {
+    if (!main.thread->enabled) {
       return F_signal;
     }
 
-    // @fixme changing design, "wait" will be a distinct thing not associated with individual rules. this will be in its own process function.
     if (!(options & controller_rule_option_wait) && F_status_is_error_not(status)) {
-      controller_rule_wait_all(thread);
+      controller_rule_wait_all(main);
 
-      if (!thread_data.enabled) {
+      if (!main.thread->enabled) {
         return F_signal;
       }
     }
@@ -1914,11 +1857,11 @@ extern "C" {
 
         f_array_length_t j = 0;
 
-        for (i = 0; i < rule->items.used; ++i) {
+        for (i = 0; i < rule.items.used; ++i) {
 
-          for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+          for (j = 0; j < rule.items.array[i].actions.used; ++j) {
 
-            if (rule->items.array[i].actions.array[j].type == action) {
+            if (rule.items.array[i].actions.array[j].type == action) {
               missing = F_false;
               break;
             }
@@ -1926,20 +1869,19 @@ extern "C" {
         } // for
 
         if (missing) {
+          if (main.data->error.verbosity != f_console_verbosity_quiet) {
+            f_thread_mutex_lock(&main.thread->lock.print);
 
-          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, "%c", f_string_eol_s[0]);
-            fprintf(thread_data.data->error.to.stream, "%s%sThe rule '", 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%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, rule->name.used ? rule->name.string : f_string_empty_s, thread_data.data->error.notable.after->string);
-            fprintf(thread_data.data->error.to.stream, "%s' has no '", thread_data.data->error.context.before->string);
-            fprintf(thread_data.data->error.to.stream, "%s%s%s%s", thread_data.data->error.context.after->string, thread_data.data->error.notable.before->string, controller_rule_action_type_name(action).string, thread_data.data->error.notable.after->string);
-            fprintf(thread_data.data->error.to.stream, "%s' action to execute.%s%c", thread_data.data->error.context.before->string, thread_data.data->error.context.after->string, f_string_eol_s[0]);
+            fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(main.data->error.to.stream, "%s%sThe rule '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+            fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, rule.name.used ? rule.name.string : f_string_empty_s, main.data->error.notable.after->string);
+            fprintf(main.data->error.to.stream, "%s' has no '", main.data->error.context.before->string);
+            fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, controller_rule_action_type_name(action).string, main.data->error.notable.after->string);
+            fprintf(main.data->error.to.stream, "%s' action to execute.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-            controller_rule_error_print(thread_data.data->error, cache->action, F_true);
+            controller_rule_error_print(main.data->error, cache->action, F_true);
 
-            f_thread_mutex_unlock(&thread_data.thread->lock.print);
+            f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
           status = F_status_set_error(F_parameter);
@@ -1947,37 +1889,23 @@ extern "C" {
       }
 
       if (F_status_is_error_not(status)) {
-        // @fixme the cache should probably store a rule type and then that can used instead of calling controller_rule_copy() here.
-        controller_rule_t rule = controller_rule_t_initialize;
-
-        status = controller_rule_copy(thread_data.setting->rules.array[index], &rule);
-
-        if (F_status_is_error_not(status)) {
-          status = controller_rule_execute(action, options, thread_data, &cache, &rule);
-
-          // @fixme there needs to be a new rule structure for storing the status state and the rule data, for any given execution (this should also be locking and unlocking).
-          thread_data.setting->rules.array[index].status = rule.status;
-        }
-
-        controller_rule_delete_simple(&rule);
+        // @todo make sure to update this function.
+        status = controller_rule_execute(rule, action, options, main, process);
 
         if (status == F_child) {
           return F_child;
         }
 
-        if (!thread_data.enabled) {
+        if (!main.thread->enabled) {
           return F_signal;
         }
 
         if (F_status_is_error(status)) {
-          controller_rule_error_print_locked(thread_data.data->error, cache->action, F_true, thread);
+          controller_rule_error_print_locked(main.data->error, cache->action, F_true, thread);
         }
       }
     }
 
-    // remove this rule off the stack.
-    thread_data.thread->asynchronouss.array[thread_data.id].stack.used--;
-
     if (F_status_is_error(status)) {
       return status;
     }
@@ -1986,178 +1914,290 @@ 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) {
+#ifndef _di_controller_rule_process_begin_
+  f_status_t controller_rule_process_begin(const bool asynchronous, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const f_array_lengths_t stack, const controller_main_t main, controller_cache_t *cache) {
+
+    f_thread_lock_read(&main.thread->lock.process);
+
+    if (!main.thread->enabled) {
+      f_thread_mutex_unlock(&main.thread->lock.process);
+
+      return F_signal;
+    }
+
+    f_status_t status = F_none;
 
-    f_array_length_t at_process = 0;
+    controller_process_t *process = 0;
 
-    f_thread_lock_read(&thread_data.thread->lock.process);
+    {
+      f_array_length_t id_process = 0;
 
-    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);
+      if (controller_find_process(alias_rule, *main.thread->processs, &id_process) != F_true) {
+        status = F_status_set_error(F_found_not);
+      }
 
-      status = controller_processs_increase(thread_data.processs);
+      f_thread_unlock(&main.thread->lock.process);
 
       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);
+
+        if (main.data->error.verbosity != f_console_verbosity_quiet) {
+          f_thread_mutex_lock(&thread_main->thread->lock.print);
+
+          fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+          fprintf(main.data->output.stream, "The entry item rule '");
+          fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, alias_rule.string, main.data->context.set.title.after->string);
+          fprintf(main.data->output.stream, "' is no longer loaded.%c", f_string_eol_s[0]);
+
+          controller_entry_error_print_cache(main.data->error, cache->action);
+
+          f_thread_mutex_unlock(&main.thread->lock.print);
+        }
+
+        return status;
       }
-      else {
-        at_process = thread_data.processs->used;
+
+      f_thread_lock_write(&main.thread->processs->array[id_process].lock);
+
+      process = &main.thread->processs->array[id_process];
+
+      // if the process is already running, then there is nothing to do.
+      if (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
+        f_thread_unlock(&process->lock);
+
+        return F_busy;
       }
+
+      f_thread_lock_read(&process->active);
+
+      // the thread is done, so detach/close the thread.
+      if (process->state == controller_process_state_done) {
+        f_thread_detach(process->id_thread);
+      }
+
+      process->id = id_process;
     }
 
-    f_thread_unlock(&thread_data.thread->lock.process);
+    process->main.data = main.data;
+    process->main.setting = main.setting;
+    process->main.thread = main.thread;
 
-    if (F_status_is_error_not(status)) {
+    process->state = controller_process_state_active;
+    process->action = action;
+    process->options = options;
 
-      // 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;
+    f_macro_time_spec_t_clear(process->cache.timestamp)
+    f_macro_string_range_t_clear(process->cache.range_action)
+
+    process->cache.ats.used = 0;
+    process->cache.stack.used = 0;
+    process->cache.comments.used = 0;
+    process->cache.delimits.used = 0;
+    process->cache.content_action.used = 0;
+    process->cache.content_actions.used = 0;
+    process->cache.content_items.used = 0;
+    process->cache.object_actions.used = 0;
+    process->cache.object_items.used = 0;
+    process->cache.buffer_file.used = 0;
+    process->cache.buffer_item.used = 0;
+    process->cache.buffer_path.used = 0;
+    process->cache.action.used = 0;
+    process->cache.line_action = process_data.thread->cache_action->line_action;
+    process->cache.line_item = process_data.thread->cache_action->line_item;
 
-      status = controller_rule_copy(thread_data.setting->rules.array[at], &rule);
+    process->stack.used = 0;
 
-      f_thread_unlock(&thread_data.thread->lock.rule);
+    process->main_data = (void *) &main->data;
+    process->main_setting = (void *) &main->setting;
+    process->main_thread = (void *) &main->thread;
+
+    if (F_status_is_error_not(status) && stack.used) {
+      if (process->stack.used < stack.used) {
+        status = f_type_array_lengths_resize(process->stack.used, &process->stack);
+      }
 
       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);
+        controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_type_array_lengths_resize", F_true, process_data.thread);
       }
       else {
-        status = controller_rule_process(rule, at_process, controller_rule_action_type_start, rule_options, thread_data, cache);
+        for (f_array_length_t i = 0; i < stack.used; ++i) {
+          process->stack.array[process->stack.used++] = stack.array[i];
+        } // for
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      status = f_string_dynamic_append(process_data.thread->cache_action.name_action, &process->cache.action.name_action);
 
-        controller_rule_delete_simple(&rule);
+      if (F_status_is_error_not(status)) {
+        status = f_string_dynamic_append(process_data.thread->cache_action.name_file, &process->cache.action.name_file);
+      }
 
-        if (F_status_is_error(status)) {
-          f_thread_mutex_lock(&thread_data.thread->lock.print);
+      if (F_status_is_error_not(status)) {
+        status = f_string_dynamic_append(process_data.thread->cache_action.name_item, &process->cache.action.name_item);
+      }
+      else {
+        controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, process_data.thread);
+      }
+    }
 
-          controller_entry_error_print_cache(thread_data.data->error, cache->action);
+    f_thread_unlock(&process->lock);
 
-          f_thread_mutex_unlock(&thread_data.thread->lock.print);
+    if (F_status_is_error_not(status)) {
+      if (asynchronous) {
+        status = f_thread_create(0, &process->id_thread, controller_thread_process, (void *) &process);
+
+        if (F_status_is_error(status)) {
+          controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_thread_create", F_true, process_data.thread);
         }
       }
+      else {
+        status = controller_rule_process_do(F_false, process);
+      }
     }
-  }
-#endif // _di_controller_rule_process_do_
 
-#ifndef _di_controller_rule_process_asynchronous_
-  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_unlock(&process->active);
 
-    f_thread_lock_read(&thread_data.lock.asynchronous);
+    if (F_status_is_error(status)) {
+      return status;
+    }
 
-    if (!thread_data.thread->enabled) {
-      f_thread_mutex_unlock(&thread_data.lock.asynchronous);
+    return F_none;
+  }
+#endif // _di_controller_rule_process_begin_
 
-      return F_signal;
-    }
+#ifndef _di_controller_rule_process_do_
+  f_status_t controller_rule_process_do(const bool asynchronous, controller_process_t *process) {
 
-    f_thread_mutex_unlock(&thread_data.lock.asynchronous);
-    f_thread_lock_write(&thread_data.lock.asynchronous);
+    f_thread_lock_read(&process->lock);
 
-    f_status_t status = controller_asynchronouss_increase(&thread_data.thread->asynchronouss);
+    controller_main_t main = controller_macro_main_t_initialize((controller_data_t *) process->main_data, (controller_setting_t *) process->main_setting(controller_thread_t *) process->main_thread);
 
-    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_lock_read(&main.thread->lock.process);
 
-      f_thread_mutex_unlock(&thread_data.thread->lock.asynchronous);
+    if (!main.thread->enabled) {
+      f_thread_unlock(&process->lock);
+      f_thread_unlock(&main.thread->lock.process);
 
-      return status;
+      return F_signal;
     }
 
-    controller_asynchronous_t *asynchronous = &thread_data.thread->asynchronouss.array[thread_data.thread->asynchronouss.used++];
+    f_thread_unlock(&main.thread->lock.process);
+    f_thread_lock_read(&process->active);
+    f_thread_mutex_lock(&process->running);
 
-    f_thread_lock_read(&thread_data.lock.process);
+    f_status_t status = F_none;
+    f_array_length_t id_rule = 0;
 
-    if (controller_find_process(id_rule, *thread_data.processs, &asynchronous->id_process) == F_true) {
+    f_thread_lock_read(&main.thread->lock.rule);
 
-      // 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 (controller_rule_find(process->alias_rule, main.setting->rules, &id_rule) == F_true) {
+      controller_rule_t rule = controller_rule_t_initialize;
 
-      status = F_status_set_error(F_failure);
+      status = controller_rule_copy(main.setting->rules.array[id_rule], &rule);
 
-      if (thread_data.data->error.verbosity != f_console_verbosity_quiet) {
-        f_thread_mutex_lock(&thread_main->thread->lock.print);
+      f_thread_unlock(&main.thread->lock.rule);
 
-        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]);
+      if (F_status_is_error(status)) {
+        controller_entry_error_print(main.data->error, process->cache->action, F_status_set_fine(status), "controller_rule_copy", F_true, main.thread);
+      }
+      else {
+        for (f_array_length_t i = 0; i < process->stack.used; ++i) {
 
-        controller_entry_error_print_cache(thread_data.data->error, cache->action);
+          if (process->stack.array[i] == id_rule) {
+            if (main.data->error.verbosity != f_console_verbosity_quiet) {
+              f_thread_mutex_lock(&main.thread->lock.print);
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
-      }
-    }
+              fprintf(main.data->error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(main.data->error.to.stream, "%s%sThe rule '", main.data->error.context.before->string, main.data->error.prefix ? main.data->error.prefix : f_string_empty_s);
+              fprintf(main.data->error.to.stream, "%s%s%s%s", main.data->error.context.after->string, main.data->error.notable.before->string, process->alias_rule.string, main.data->error.notable.after->string);
+              fprintf(main.data->error.to.stream, "%s' is already on the execution dependency stack, this recursion is prohibited.%s%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
 
-    f_thread_unlock(&thread_data.lock.process);
+              controller_rule_error_print(main.data->error, cache->action, F_true);
 
-    if (F_status_is_error_not(status)) {
+              f_thread_mutex_unlock(&main.thread->lock.print);
+            }
 
-      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;
+            // never continue on circular recursion errors even in simulate mode.
+            status = F_status_set_error(F_recurse);
 
-      if (F_status_is_error_not(status)) {
-        status = f_string_dynamic_append(thread_data.thread->cache_action->name_action, &asynchronous->cache.name_action);
+            break;
+          }
+        } // for
 
         if (F_status_is_error_not(status)) {
-          status = f_string_dynamic_append(thread_data.thread->cache_action->name_file, &asynchronous->cache.name_file);
-        }
+          f_thread_unlock(&process->lock);
+          f_thread_lock_write(&process->lock);
 
-        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);
+          status = f_type_array_lengths_increase(&process->stack);
+
+          if (F_status_is_error(status)) {
+            controller_entry_error_print(process_data.data->error, process->cache->action, F_status_set_fine(status), "f_type_array_lengths_increase", F_true, process_data.thread);
+          }
+          else {
+            process->stack.array[process->stack.used++] = id_rule;
+          }
+
+          f_thread_unlock(&process->lock);
+          f_thread_lock_read(&process->lock);
         }
       }
 
       if (F_status_is_error_not(status)) {
-        status = f_thread_create(0, &asynchronous->id, controller_thread_asynchronous_process, (void *) asynchronous);
+        status = controller_rule_process(rule, controller_rule_action_type_start, rule_options, main, process);
+
+        if (F_status_is_error(status)) {
+          f_thread_mutex_lock(&main.thread->lock.print);
+
+          controller_entry_error_print_cache(main.data->error, process->cache->action);
+
+          f_thread_mutex_unlock(&main.thread->lock.print);
+        }
       }
     }
+    else {
+      f_thread_unlock(&main.thread->lock.rule);
 
-    if (F_status_is_error(status)) {
-      controller_entry_error_print(thread_data.data->error, asynchronous->cache->action, F_status_set_fine(status), "f_thread_create", F_true, thread_data.thread);
+      status = F_status_set_error(F_found_not);
+
+      if (main.data->error.verbosity != f_console_verbosity_quiet) {
+        f_thread_mutex_lock(&main.thread->lock.print);
 
-      controller_asynchronous_delete_simple(asynchronous);
+        fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+        fprintf(main.data->output.stream, "The entry item rule '");
+        fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, process->alias_rule.string, main.data->context.set.title.after->string);
+        fprintf(main.data->output.stream, "' is no longer loaded.%c", f_string_eol_s[0]);
 
-      thread_data.thread->asynchronouss.used--;
+        controller_entry_error_print_cache(main.data->error, process->cache->action);
+
+        f_thread_mutex_unlock(&main.thread->lock.print);
+      }
     }
 
-    f_thread_unlock(&thread_data->lock.asynchronous);
+    f_thread_unlock(&process->lock);
+    f_thread_lock_write(&process->lock);
 
-    if (F_status_is_error(status)) {
-      return status;
+    if (asynchronous) {
+      process->state = controller_asynchronous_state_done;
+    }
+    else {
+      process->state = controller_asynchronous_state_idle;
     }
 
-    return F_none;
+    --process->stack.used;
+
+    // inform all things waiting that the process has finished running.
+    f_thread_condition_signal(&process->wait);
+    f_thread_mutex_unlock(&process->running);
+
+    f_thread_unlock(&process->active);
+    f_thread_unlock(&process->lock);
+
+    return status;
   }
-#endif // _di_controller_rule_process_asynchronous_
+#endif // _di_controller_rule_process_do_
 
 #ifndef _di_controller_rule_read_
-  f_status_t controller_rule_read(const f_string_static_t rule_id, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) {
+  f_status_t controller_rule_read(const f_string_static_t rule_id, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) {
     f_status_t status = F_none;
 
     bool for_item = F_true;
@@ -2176,7 +2216,7 @@ extern "C" {
 
     f_macro_time_spec_t_clear(rule->timestamp);
 
-    rule->id.used = 0;
+    rule->alias.used = 0;
     rule->name.used = 0;
     rule->path.used = 0;
     rule->script.used = 0;
@@ -2238,19 +2278,20 @@ extern "C" {
     cache->action.name_file.used = 0;
     cache->action.name_item.used = 0;
 
-    status = f_string_dynamic_append_nulless(rule_id, &rule->id);
+    status = f_string_dynamic_append_nulless(rule_id, &rule->alias);
 
     if (F_status_is_error(status)) {
-      fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true);
+      fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true);
     }
     else {
-      status = f_string_dynamic_terminate_after(&rule->id);
+
+      status = f_string_dynamic_terminate_after(&rule->alias);
 
       if (F_status_is_error(status)) {
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
       }
       else {
-        status = controller_file_load(controller_string_rules_s, rule->id, controller_string_rule_s, controller_string_rules_length, controller_string_rule_length, thread_data, cache);
+        status = controller_file_load(controller_string_rules_s, rule->alias, controller_string_rule_s, controller_string_rules_length, controller_string_rule_length, main, cache);
       }
     }
 
@@ -2263,13 +2304,13 @@ extern "C" {
         status = fll_fss_basic_list_read(cache->buffer_file, &range, &cache->object_items, &cache->content_items, &cache->delimits, 0, &cache->comments);
 
         if (F_status_is_error(status)) {
-          fll_error_print(thread_data.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true);
+          fll_error_print(main.data->error, F_status_set_fine(status), "fll_fss_basic_list_read", F_true);
         }
         else {
           status = fl_fss_apply_delimit(cache->delimits, &cache->buffer_file);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true);
           }
         }
       }
@@ -2279,7 +2320,7 @@ extern "C" {
       status = controller_rule_items_increase_by(cache->object_items.used, &rule->items);
 
       if (F_status_is_error(status)) {
-        fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_rule_items_increase_by", F_true);
+        fll_error_print(main.data->error, F_status_set_fine(status), "controller_rule_items_increase_by", F_true);
       }
       else {
         f_array_length_t i = 0;
@@ -2316,7 +2357,7 @@ extern "C" {
           status = f_fss_count_lines(cache->buffer_file, cache->object_items.array[i].start, &cache->action.line_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "f_fss_count_lines", F_true);
             break;
           }
 
@@ -2325,7 +2366,7 @@ extern "C" {
           status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_items.array[i], &cache->action.name_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "controller_string_dynamic_rip_nulless_terminated", F_true);
             break;
           }
 
@@ -2342,14 +2383,14 @@ extern "C" {
             rule->items.array[rule->items.used].type = controller_rule_item_type_service;
           }
           else {
-            if (thread_data.data->warning.verbosity == f_console_verbosity_debug) {
-              fprintf(thread_data.data->warning.to.stream, "%s%sUnknown rule item '", 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.context.after->string, thread_data.data->warning.notable.before->string);
-              f_print_dynamic(thread_data.data->warning.to.stream, cache->action.name_item);
-              fprintf(thread_data.data->warning.to.stream, "%s", thread_data.data->warning.notable.after->string);
-              fprintf(thread_data.data->warning.to.stream, "%s'.%s%c", thread_data.data->warning.context.before->string, thread_data.data->warning.context.after->string, f_string_eol_s[0]);
-
-              controller_rule_error_print(thread_data.data->warning, cache->action, F_true);
+            if (main.data->warning.verbosity == f_console_verbosity_debug) {
+              fprintf(main.data->warning.to.stream, "%s%sUnknown rule item '", main.data->warning.context.before->string, main.data->warning.prefix ? main.data->warning.prefix : f_string_empty_s);
+              fprintf(main.data->warning.to.stream, "%s%s", main.data->warning.context.after->string, main.data->warning.notable.before->string);
+              f_print_dynamic(main.data->warning.to.stream, cache->action.name_item);
+              fprintf(main.data->warning.to.stream, "%s", main.data->warning.notable.after->string);
+              fprintf(main.data->warning.to.stream, "%s'.%s%c", main.data->warning.context.before->string, main.data->warning.context.after->string, f_string_eol_s[0]);
+
+              controller_rule_error_print(main.data->warning, cache->action, F_true);
             }
 
             continue;
@@ -2358,19 +2399,19 @@ extern "C" {
           status = f_string_dynamic_partial_append(cache->buffer_file, cache->content_items.array[i].array[0], &cache->buffer_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_partial_append", F_true);
             break;
           }
 
           status = f_string_dynamic_terminate_after(&cache->buffer_item);
 
           if (F_status_is_error(status)) {
-            fll_error_print(thread_data.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
+            fll_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
             break;
           }
 
           if (rule->items.array[rule->items.used].type) {
-            status = controller_rule_item_read(thread_data, cache, &rule->items.array[rule->items.used]);
+            status = controller_rule_item_read(*main.data, cache, &rule->items.array[rule->items.used]);
             if (F_status_is_error(status)) break;
 
             rule->items.used++;
@@ -2378,7 +2419,7 @@ extern "C" {
           else {
             for_item = F_false;
 
-            status = controller_rule_setting_read(thread_data, cache, rule);
+            status = controller_rule_setting_read(*main.data, *main.setting, cache, rule);
 
             if (F_status_is_error(status)) {
               if (F_status_set_fine(status) == F_memory_not) {
@@ -2391,7 +2432,7 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
-      controller_rule_error_print(thread_data.data->error, cache->action, for_item);
+      controller_rule_error_print(main.data->error, cache->action, for_item);
 
       rule->status = controller_status_simplify(F_status_set_fine(status));
       return F_false;
@@ -2403,6 +2444,7 @@ extern "C" {
 
 #ifndef _di_controller_rule_setting_read_
   f_status_t controller_rule_setting_read(const controller_data_t data, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) {
+
     f_status_t status = F_none;
     f_status_t status_return = F_none;
 
@@ -2608,7 +2650,6 @@ extern "C" {
         // @todo use sched_getaffinity() to get the available cpus and do not add an invalid cpu to the affinity array.
 
         if (!cache->content_actions.array[i].used) {
-
           if (data.error.verbosity != f_console_verbosity_quiet) {
 
             // get the current line number within the settings item.
@@ -2665,8 +2706,8 @@ extern "C" {
             status = F_status_set_fine(status);
 
             if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow) {
-
               if (data.error.verbosity != f_console_verbosity_quiet) {
+
                 if (status == F_number_overflow || status == F_number_underflow) {
                   fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
                   fprintf(data.error.to.stream, "%s%sRule setting has an unsupported number '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
@@ -2719,7 +2760,6 @@ extern "C" {
       if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) {
 
         if (cache->content_actions.array[i].used != 2) {
-
           if (data.error.verbosity != f_console_verbosity_quiet) {
 
             // get the current line number within the settings item.
@@ -2839,7 +2879,6 @@ extern "C" {
       if (type == controller_rule_setting_type_control_group) {
 
         if (cache->content_actions.array[i].used < 2 || rule->has & controller_rule_has_control_group) {
-
           if (data.error.verbosity != f_console_verbosity_quiet) {
             fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
             fprintf(data.error.to.stream, "%s%sRule setting requires two or more Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
@@ -2955,7 +2994,6 @@ extern "C" {
       }
 
       if (type == controller_rule_setting_type_limit) {
-
         if (cache->content_actions.array[i].used != 3) {
 
           if (data.error.verbosity != f_console_verbosity_quiet) {
@@ -3105,6 +3143,7 @@ extern "C" {
         f_number_signed_t number = 0;
 
         for (j = 1; j < 3; ++j, number = 0) {
+
           status = fl_conversion_string_to_number_signed(cache->buffer_item.string, &number, cache->content_actions.array[i].array[j]);
 
           if (F_status_is_error(status)) {
@@ -3172,6 +3211,7 @@ extern "C" {
       }
 
       if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) {
+
         if (type == controller_rule_setting_type_name) {
           setting_value = &rule->name;
         }
@@ -3183,7 +3223,6 @@ extern "C" {
         }
 
         if (setting_value->used || cache->content_actions.array[i].used != 1) {
-
           if (data.error.verbosity != f_console_verbosity_quiet) {
             fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
             fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
@@ -3205,7 +3244,6 @@ extern "C" {
         }
 
         if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
-
           status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
 
           if (F_status_is_error(status)) {
@@ -3234,8 +3272,8 @@ extern "C" {
             status = controller_validate_has_graph(*setting_value);
 
             if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
-              if (status == F_false) {
 
+              if (status == F_false) {
                 if (data.error.verbosity != f_console_verbosity_quiet) {
                   fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
                   fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
@@ -3323,7 +3361,6 @@ extern "C" {
       if (type == controller_rule_setting_type_scheduler) {
 
         if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2 || rule->has & controller_rule_has_scheduler) {
-
           if (data.error.verbosity != f_console_verbosity_quiet) {
             fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
             fprintf(data.error.to.stream, "%s%sRule setting requires either one or two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
@@ -3534,7 +3571,6 @@ extern "C" {
           status = f_capability_from_text(cache->action.generic.string, &rule->capability);
 
           if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) {
-
             if (F_status_set_fine(status) == F_memory_not) {
               fll_error_print(data.error, F_status_set_fine(status), "f_capability_from_text", F_true);
 
@@ -4053,12 +4089,11 @@ extern "C" {
 #endif // _di_controller_rule_setting_read_
 
 #ifndef _di_controller_rule_simulate_
-  void controller_rule_simulate(const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) {
+  void controller_rule_simulate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_cache_t *cache) {
 
-    controller_data_t *data = thread_data.thread->data;
-    controller_setting_t *setting = thread_data.thread->setting;
+    const controller_data_t *data = main.data;
 
-    f_thread_mutex_lock(&thread_data.thread->lock.print);
+    f_thread_mutex_lock(&main.thread->lock.print);
 
     switch (action) {
       case controller_rule_action_type_kill:
@@ -4079,13 +4114,11 @@ extern "C" {
           controller_rule_error_print(data->error, cache->action, F_true);
         }
 
-        f_thread_mutex_unlock(&thread_data.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
 
         return;
     }
 
-    const controller_rule_t *rule = &setting->rules.array[index];
-
     f_array_length_t i = 0;
     f_array_length_t j = 0;
 
@@ -4093,11 +4126,11 @@ extern "C" {
     {
       bool missing = F_true;
 
-      for (; i < rule->items.used; ++i) {
+      for (; i < rule.items.used; ++i) {
 
-        for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+        for (j = 0; j < rule.items.array[i].actions.used; ++j) {
 
-          if (rule->items.array[i].actions.array[j].type == action) {
+          if (rule.items.array[i].actions.array[j].type == action) {
             missing = F_false;
             break;
           }
@@ -4107,7 +4140,7 @@ extern "C" {
       if (missing) {
         fprintf(data->output.stream, "%c", f_string_eol_s[0]);
         fprintf(data->output.stream, "Rule '");
-        fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, rule->name.used ? rule->name.string : f_string_empty_s, data->context.set.title.after->string);
+        fprintf(data->output.stream, "%s%s%s", data->context.set.title.before->string, rule.name.used ? rule.name.string : f_string_empty_s, data->context.set.title.after->string);
         fprintf(data->output.stream, "' has no '");
         fprintf(data->output.stream, "%s%s%s", data->context.set.important.before->string, controller_rule_action_type_name(action).string, data->context.set.important.after->string);
         fprintf(data->output.stream, "' action to execute and would '");
@@ -4119,18 +4152,18 @@ extern "C" {
     }
 
     fprintf(data->output.stream, "%c", f_string_eol_s[0]);
-    fprintf(data->output.stream, "Rule %s%s%s {%c", data->context.set.title.before->string, rule->id.used ? rule->id.string : f_string_empty_s, data->context.set.title.after->string, f_string_eol_s[0]);
-    fprintf(data->output.stream, "  %s%s%s %s%c", data->context.set.important.before->string, controller_string_name_s, data->context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]);
+    fprintf(data->output.stream, "Rule %s%s%s {%c", data->context.set.title.before->string, rule.alias.used ? rule.alias.string : f_string_empty_s, data->context.set.title.after->string, f_string_eol_s[0]);
+    fprintf(data->output.stream, "  %s%s%s %s%c", data->context.set.important.before->string, controller_string_name_s, data->context.set.important.after->string, rule.name.used ? rule.name.string : f_string_empty_s, f_string_eol_s[0]);
     fprintf(data->output.stream, "  %s%s%s %s%c", data->context.set.important.before->string, controller_string_how_s, data->context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous_s, f_string_eol_s[0]);
     fprintf(data->output.stream, "  %s%s%s %s%c", data->context.set.important.before->string, controller_string_wait_s, data->context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no_s, f_string_eol_s[0]);
 
     if (f_capability_supported()) {
       fprintf(data->output.stream, "  %s%s%s ", data->context.set.important.before->string, controller_string_capability_s, data->context.set.important.after->string);
 
-      if (rule->capability) {
+      if (rule.capability) {
         cache->action.generic.used = 0;
 
-        if (F_status_is_error_not(f_capability_to_text(rule->capability, &cache->action.generic))) {
+        if (F_status_is_error_not(f_capability_to_text(rule.capability, &cache->action.generic))) {
           fprintf(data->output.stream, "%s", cache->action.generic.string);
         }
       }
@@ -4143,117 +4176,114 @@ extern "C" {
     }
 
     fprintf(data->output.stream, "  %s%s%s", data->context.set.important.before->string, controller_string_control_group_s, data->context.set.important.after->string);
-    if (rule->has & controller_rule_has_control_group) {
-      fprintf(data->output.stream, " %s", rule->control_group.as_new ? controller_string_new_s : controller_string_existing_s);
 
-      for (i = 0; i < rule->control_group.groups.used; ++i) {
+    if (rule.has & controller_rule_has_control_group) {
+      fprintf(data->output.stream, " %s", rule.control_group.as_new ? controller_string_new_s : controller_string_existing_s);
+
+      for (i = 0; i < rule.control_group.groups.used; ++i) {
 
-        if (rule->control_group.groups.array[i].used) {
+        if (rule.control_group.groups.array[i].used) {
           fprintf(data->output.stream, f_string_space_s);
-          f_print_dynamic(data->output.stream, rule->control_group.groups.array[i]);
+          f_print_dynamic(data->output.stream, rule.control_group.groups.array[i]);
         }
       } // for
     }
-    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
 
+    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
     fprintf(data->output.stream, "  %s%s%s", data->context.set.important.before->string, controller_string_nice_s, data->context.set.important.after->string);
-    if (rule->has & controller_rule_has_nice) {
-      fprintf(data->output.stream, " %i", rule->nice);
+
+    if (rule.has & controller_rule_has_nice) {
+      fprintf(data->output.stream, " %i", rule.nice);
     }
-    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
 
+    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
     fprintf(data->output.stream, "  %s%s%s", data->context.set.important.before->string, controller_string_scheduler_s, data->context.set.important.after->string);
-    if (rule->has & controller_rule_has_scheduler) {
+
+    if (rule.has & controller_rule_has_scheduler) {
       f_string_t policy = "";
 
-      if (rule->scheduler.policy == SCHED_BATCH) {
+      if (rule.scheduler.policy == SCHED_BATCH) {
         policy = controller_string_batch_s;
       }
-      else if (rule->scheduler.policy == SCHED_DEADLINE) {
+      else if (rule.scheduler.policy == SCHED_DEADLINE) {
         policy = controller_string_deadline_s;
       }
-      else if (rule->scheduler.policy == SCHED_FIFO) {
+      else if (rule.scheduler.policy == SCHED_FIFO) {
         policy = controller_string_fifo_s;
       }
-      else if (rule->scheduler.policy == SCHED_IDLE) {
+      else if (rule.scheduler.policy == SCHED_IDLE) {
         policy = controller_string_idle_s;
       }
-      else if (rule->scheduler.policy == SCHED_OTHER) {
+      else if (rule.scheduler.policy == SCHED_OTHER) {
         policy = controller_string_other_s;
       }
-      else if (rule->scheduler.policy == SCHED_RR) {
+      else if (rule.scheduler.policy == SCHED_RR) {
         policy = controller_string_round_robin_s;
       }
 
-      fprintf(data->output.stream, " %s %i", policy, rule->scheduler.priority);
+      fprintf(data->output.stream, " %s %i", policy, rule.scheduler.priority);
     }
-    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
-
-    fprintf(data->output.stream, "  %s%s%s %s%c", data->context.set.important.before->string, controller_string_script_s, data->context.set.important.after->string, rule->script.used ? rule->script.string : f_string_empty_s, f_string_eol_s[0]);
 
+    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
+    fprintf(data->output.stream, "  %s%s%s %s%c", data->context.set.important.before->string, controller_string_script_s, data->context.set.important.after->string, rule.script.used ? rule.script.string : f_string_empty_s, f_string_eol_s[0]);
     fprintf(data->output.stream, "  %s%s%s", data->context.set.important.before->string, controller_string_user_s, data->context.set.important.after->string);
-    if (rule->has & controller_rule_has_user) {
-      fprintf(data->output.stream, " %i", rule->user);
+
+    if (rule.has & controller_rule_has_user) {
+      fprintf(data->output.stream, " %i", rule.user);
     }
-    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
 
+    fprintf(data->output.stream, "%c", f_string_eol_s[0]);
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_affinity_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->affinity.used; ++i) {
-      fprintf(data->output.stream, "    %i%c", rule->affinity.array[i], f_string_eol_s[0]);
+    for (i = 0; i < rule.affinity.used; ++i) {
+      fprintf(data->output.stream, "    %i%c", rule.affinity.array[i], f_string_eol_s[0]);
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_define_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->define.used; ++i) {
+    for (i = 0; i < rule.define.used; ++i) {
 
-      if (rule->define.array[i].name.used && rule->define.array[i].value.used) {
-        fprintf(data->output.stream, "    %s %s=%s %s%c", rule->define.array[i].name.string, data->context.set.important.before->string, data->context.set.important.after->string, rule->define.array[i].value.string, f_string_eol_s[0]);
+      if (rule.define.array[i].name.used && rule.define.array[i].value.used) {
+        fprintf(data->output.stream, "    %s %s=%s %s%c", rule.define.array[i].name.string, data->context.set.important.before->string, data->context.set.important.after->string, rule.define.array[i].value.string, f_string_eol_s[0]);
       }
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_environment_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->environment.used; ++i) {
+    for (i = 0; i < rule.environment.used; ++i) {
 
-      if (rule->environment.array[i].used) {
-        fprintf(data->output.stream, "    %s%c", rule->environment.array[i].string, f_string_eol_s[0]);
+      if (rule.environment.array[i].used) {
+        fprintf(data->output.stream, "    %s%c", rule.environment.array[i].string, f_string_eol_s[0]);
       }
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_group_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    if (rule->has & controller_rule_has_group) {
-      fprintf(data->output.stream, "    %i%c", rule->group, f_string_eol_s[0]);
+    if (rule.has & controller_rule_has_group) {
+      fprintf(data->output.stream, "    %i%c", rule.group, f_string_eol_s[0]);
 
-      for (i = 0; i < rule->groups.used; ++i) {
-        fprintf(data->output.stream, "    %i%c", rule->groups.array[i], f_string_eol_s[0]);
+      for (i = 0; i < rule.groups.used; ++i) {
+        fprintf(data->output.stream, "    %i%c", rule.groups.array[i], f_string_eol_s[0]);
       } // for
     }
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_limit_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->limits.used; ++i) {
-
-      fprintf(data->output.stream, "    %s %s=%s %llu %llu%c", controller_rule_setting_limit_type_name(rule->limits.array[i].type).string, data->context.set.important.before->string, data->context.set.important.after->string, rule->limits.array[i].value.rlim_cur, rule->limits.array[i].value.rlim_max, f_string_eol_s[0]);
+    for (i = 0; i < rule.limits.used; ++i) {
+      fprintf(data->output.stream, "    %s %s=%s %llu %llu%c", controller_rule_setting_limit_type_name(rule.limits.array[i].type).string, data->context.set.important.before->string, data->context.set.important.after->string, rule.limits.array[i].value.rlim_cur, rule.limits.array[i].value.rlim_max, f_string_eol_s[0]);
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_need_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->need.used; ++i) {
+    for (i = 0; i < rule.need.used; ++i) {
 
-      if (rule->need.array[i].used) {
-        fprintf(data->output.stream, "    %s%c", rule->need.array[i].string, f_string_eol_s[0]);
+      if (rule.need.array[i].used) {
+        fprintf(data->output.stream, "    %s%c", rule.need.array[i].string, f_string_eol_s[0]);
       }
     } // for
 
@@ -4261,38 +4291,36 @@ extern "C" {
 
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_parameter_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->parameter.used; ++i) {
+    for (i = 0; i < rule.parameter.used; ++i) {
 
-      if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) {
-        fprintf(data->output.stream, "    %s %s=%s %s%c", rule->parameter.array[i].name.string, data->context.set.important.before->string, data->context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]);
+      if (rule.parameter.array[i].name.used && rule.parameter.array[i].value.used) {
+        fprintf(data->output.stream, "    %s %s=%s %s%c", rule.parameter.array[i].name.string, data->context.set.important.before->string, data->context.set.important.after->string, rule.parameter.array[i].value.string, f_string_eol_s[0]);
       }
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_want_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->want.used; ++i) {
+    for (i = 0; i < rule.want.used; ++i) {
 
-      if (rule->want.array[i].used) {
-        fprintf(data->output.stream, "    %s%c", rule->want.array[i].string, f_string_eol_s[0]);
+      if (rule.want.array[i].used) {
+        fprintf(data->output.stream, "    %s%c", rule.want.array[i].string, f_string_eol_s[0]);
       }
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
-
     fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_wish_s, data->context.set.important.after->string, f_string_eol_s[0]);
 
-    for (i = 0; i < rule->wish.used; ++i) {
+    for (i = 0; i < rule.wish.used; ++i) {
 
-      if (rule->wish.array[i].used) {
-        fprintf(data->output.stream, "    %s%c", rule->wish.array[i].string, f_string_eol_s[0]);
+      if (rule.wish.array[i].used) {
+        fprintf(data->output.stream, "    %s%c", rule.wish.array[i].string, f_string_eol_s[0]);
       }
     } // for
 
     fprintf(data->output.stream, "  }%c", f_string_eol_s[0]);
 
-    if (rule->items.used) {
+    if (rule.items.used) {
       controller_rule_action_t *action = 0;
       controller_rule_item_t *item = 0;
       f_string_dynamic_t *parameter = 0;
@@ -4300,12 +4328,11 @@ extern "C" {
       f_array_length_t j = 0;
       f_array_length_t k = 0;
 
-      for (i = 0; i < rule->items.used; ++i) {
+      for (i = 0; i < rule.items.used; ++i) {
 
-        item = &rule->items.array[i];
+        item = &rule.items.array[i];
 
         fprintf(data->output.stream, "  %s%s%s {%c", data->context.set.important.before->string, controller_string_item_s, data->context.set.important.after->string, f_string_eol_s[0]);
-
         fprintf(data->output.stream, "    %s%s%s %s%c", data->context.set.important.before->string, controller_string_type_s, data->context.set.important.after->string, controller_rule_item_type_name(item->type).string, f_string_eol_s[0]);
 
         for (j = 0; j < item->actions.used; ++j) {
@@ -4313,7 +4340,6 @@ extern "C" {
           action = &item->actions.array[j];
 
           fprintf(data->output.stream, "    %s%s%s {%c", data->context.set.important.before->string, controller_string_action_s, data->context.set.important.after->string, f_string_eol_s[0]);
-
           fprintf(data->output.stream, "      %s%s%s %s%c", data->context.set.important.before->string, controller_string_type_s, data->context.set.important.after->string, controller_rule_action_type_name(action->type).string, f_string_eol_s[0]);
 
           if (item->type == controller_rule_item_type_script) {
@@ -4353,53 +4379,68 @@ extern "C" {
 
     fprintf(data->output.stream, "}%c", f_string_eol_s[0]);
 
-    setting->rules.array[index].status = F_complete;
+    main.setting->rules.array[index].status = F_complete;
 
-    f_thread_mutex_unlock(&thread_data.thread->lock.print);
+    f_thread_mutex_unlock(&main.thread->lock.print);
   }
 #endif // _di_controller_rule_simulate_
 
 #ifndef _di_controller_rule_wait_all_
-  void controller_rule_wait_all(controller_thread_t *thread) {
+  void controller_rule_wait_all(const controller_main_t main) {
 
-    for (f_array_length_t i = 0; i < thread->asynchronouss.used && thread->enabled; ++i) {
+    f_thread_lock_read(&main.thread->lock.process);
 
-      // do not need to wait when state is 0 or joined.
-      if (!thread->asynchronouss.array[i].state || thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) {
-        continue;
-      }
+    controller_process_t *process = 0;
 
-      if (thread->asynchronouss.array[i].index >= thread->setting->rules.used) {
-        continue;
-      }
+    for (f_array_length_t i = 0; i < main.thread->processs.used && main.thread->enabled; ++i) {
 
-      f_thread_mutex_lock(&thread->setting->rules.array[thread->asynchronouss.array[i].index].lock);
+      process = &main.thread->processs.array[i];
 
-      while (thread->enabled && thread->setting->rules.array[thread->asynchronouss.array[i].index].status == F_known_not) {
-        f_thread_condition_wait(&thread->setting->rules.array[thread->asynchronouss.array[i].index].wait, &thread->setting->rules.array[thread->asynchronouss.array[i].index].lock);
-      } // while
+      f_thread_lock_read(&process->active);
+      f_thread_lock_read(&process->lock);
 
-      f_thread_mutex_unlock(&thread->setting->rules.array[thread->asynchronouss.array[i].index].lock);
+      if (process->state == controller_process_state_idle || process->state == controller_process_state_done) {
 
-      if (!thread->enabled) break;
+        if (process->state == controller_process_state_done) {
+          f_thread_unlock(&process->lock);
+          f_thread_lock_write(&process->lock);
 
-      if (f_thread_mutex_lock_try(&thread->lock.asynchronous) == F_none) {
+          if (process->state == controller_process_state_done) {
+            f_thread_join(process->id_thread, 0);
 
-        if (thread->asynchronouss.array[i].state != controller_asynchronous_state_joined) {
-          f_thread_join(thread->asynchronouss.array[i].id, 0);
+            process->state = controller_process_state_idle;
+          }
         }
 
-        if (thread->enabled && thread->asynchronouss.array[i].state) {
-          if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) {
-            thread->asynchronouss.array[i].state = controller_asynchronous_state_joined;
-          }
+        f_thread_unlock(&process->active);
+        f_thread_unlock(&process->lock);
 
-          controller_macro_cache_action_t_clear(thread->asynchronouss.array[i].cache);
-        }
+        continue;
+      }
+
+      f_thread_condition_wait(&process->wait, &process->running);
+
+      if (process->state == controller_process_state_done) {
+        f_thread_unlock(&process->lock);
+        f_thread_lock_write(&process->lock);
 
-        f_thread_mutex_unlock(&thread->lock.asynchronous);
+        if (process->state == controller_process_state_done) {
+          f_thread_join(process->id_thread, 0);
+
+          process->state = controller_process_state_idle;
+        }
       }
+
+      f_thread_unlock(&process->lock);
+
+      // always pass the signal along when done waiting.
+      f_thread_condition_signal(&process->wait);
+      f_thread_mutex_unlock(&process->running);
+
+      f_thread_unlock(&process->active);
     } // for
+
+    f_thread_unlock(&main.thread->lock.process);
   }
 #endif // _di_controller_rule_wait_all_
 
index 76b203ba1f5c1d19d2457dcb765c67df73f773d8..49fd2d51e3f7fa8a99b77f0159ad301d68d4f009 100644 (file)
@@ -27,6 +27,25 @@ extern "C" {
 #endif // _di_controller_rule_action_method_name_
 
 /**
+ * Find the location of the Rule by the Rule alias.
+ *
+ * @param alias
+ *   The Rule alias to find.
+ * @param rules
+ *   The rules to search through.
+ * @param at
+ *   The index the rule was found at.
+ *
+ * @return
+ *   F_none on success, but the id.used is 0.
+ *   F_true on success and rule was found, index is updated.
+ *   F_false on success and rule was not found.
+ */
+#ifndef _di_controller_rule_find_
+  extern f_status_t controller_rule_find(const f_string_static_t alias, const controller_rules_t rules, f_array_length_t *at) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_find_
+
+/**
  * Read the parameters for some rule action.
  *
  * The object and content ranges are merged together (in that order) as the action parameters.
@@ -275,8 +294,8 @@ extern "C" {
  * @param options
  *   A number using bits to represent specific boolean options.
  *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   A structure for containing and caching relevant data.
  * @param rule
@@ -292,7 +311,7 @@ extern "C" {
  *   On failure, the individual status for the rule is set to an appropriate error status.
  */
 #ifndef _di_controller_rule_execute_
-  extern f_status_t controller_rule_execute(const uint8_t type, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_execute(const uint8_t type, const uint8_t options, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_
 
 /**
@@ -318,8 +337,8 @@ extern "C" {
  *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
  * @param execute_set
  *   The execute parameter and as settings.
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param rule
  *   The rule to process.
  *
@@ -333,7 +352,7 @@ extern "C" {
  * @see fll_execute_program()
  */
 #ifndef _di_controller_rule_execute_foreground_
-  extern f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_data_t thread_data, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_foreground_
 
 /**
@@ -362,8 +381,8 @@ extern "C" {
  *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
  * @param execute_set
  *   The execute parameter and as settings.
- * @param thread
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param asynchronous
  *   Holds the current asynchronous thread information if this is being run from within one.
  *   Set to NULL when this is not being called from within an asynchronous thread.
@@ -379,33 +398,10 @@ extern "C" {
  * @see fll_execute_program()
  */
 #ifndef _di_controller_rule_execute_pid_with_
-  extern f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_thread_data_t thread_data, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_main_t main, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_pid_with_
 
 /**
- * Search the already loaded rules to see if one is found.
- *
- * Looks up the rules starting from the end so that the latest loaded version of any given rule is found and used first.
- * The rule thread should be locked before calling this to ensure the rule is not loaded after this search.
- *
- * This does not do any locking or unlocking, be sure to lock appropriately before and after calling this.
- *
- * @param rule_id
- *   The string identifying the rule.
- *   This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
- *   "/etc/controller/rules/example/my.rule" would have a rule id of "example/my".
- * @param thread_data
- *   The thread data.
- *
- * @return
- *   If found, a valid location within the setting.rules array.
- *   If not found, then setting.rules.used is returned.
- */
-#ifndef _di_controller_rule_find_loaded_
-  extern f_array_length_t controller_rule_find_loaded(const f_string_static_t rule_id, controller_thread_data_t thread_data) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_rule_find_loaded_
-
-/**
  * Construct an id from two distinct strings found within a single given source.
  *
  * @param data
@@ -416,8 +412,8 @@ extern "C" {
  *   A range within the source representing the directory part of a rule id.
  * @param basename
  *   A range within the source representing the basename part of a rule id.
- * @param id
- *   The constructed id.
+ * @param alias
+ *   The constructed alias.
  *
  * @return
  *   F_none on success.
@@ -430,7 +426,7 @@ extern "C" {
  * @see f_string_dynamic_terminate_after()
  */
 #ifndef _di_controller_rule_id_construct_
-  extern f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *id) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_id_construct(const controller_data_t data, const f_string_static_t source, const f_string_range_t directory, const f_string_range_t basename, f_string_dynamic_t *alias) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_id_construct_
 
 /**
@@ -546,17 +542,16 @@ extern "C" {
 #endif // _di_controller_rule_path_
 
 /**
- * Synchronously process and execute the given rule by the rule id.
+ * Process and execute the given rule.
  *
- * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings.
+ * Any dependent rules are processed and executed as per "need", "want", and "wish" rule settings.
  * All dependent rules must be already loaded, this function will not load any rules.
  *
+ * @fixme recursion is no longer happening is it?
  * 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 rule
  *   The rule information at the time the rule process started.
- * @param at_process
- *   The position within the processs array representing this rule process.
  * @param action
  *   The action to perform based on the action type codes.
  *
@@ -571,10 +566,10 @@ extern "C" {
  *   If no bits set, then operate normally in a synchronous manner.
  *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
  *   If bit controller_rule_option_asynchronous, then run asynchronously.
- * @param thread_data
- *   The thread data.
- * @param cache
- *   A structure for containing and caching relevant data.
+ * @param main
+ *   The main data.
+ * @param process
+ *   The process data for processing this rule.
  *
  * @return
  *   F_none on success.
@@ -582,49 +577,81 @@ extern "C" {
  *   F_signal on (exit) signal received.
  */
 #ifndef _di_controller_rule_process_
-  extern f_status_t controller_rule_process(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_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_process(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_process_
 
 /**
- * Asynchronously process and execute the given rule by the rule id.
+ * Synchronously or Asynchronously begin processing some rule.
  *
- * Any dependent rules are loaded and executed as per "need", "want", and "wish" rule settings.
- * All dependent rules must be already loaded, this function will not load any rules.
- *
- * 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 id_rule
- *   The ID of the rule, such as "boot/init".
+ * @param asynchronous
+ *   If TRUE, then asynchronously execute a process.
+ *   If FALSE, then synchronously execute a process.
+ * @param alias_rule
+ *   The alias of the rule, such as "boot/init".
  * @param action
  *   The action to perform based on the action type codes.
- *
- *   Only subset of the action type codes are supported:
- *   - controller_rule_action_type_kill
- *   - controller_rule_action_type_reload
- *   - controller_rule_action_type_restart
- *   - controller_rule_action_type_start
- *   - controller_rule_action_type_stop
  * @param options
  *   A number using bits to represent specific boolean options.
- *   If no bits set, then operate normally in a synchronous manner.
- *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
- *   If bit controller_rule_option_asynchronous, then run asynchronously.
- * @param thread_data
- *   The thread data.
+ * @param stack
+ *   A stack representing the processes already running in this rule process dependency tree.
+ *   This is used to prevent circular dependencies.
+ * @param main
+ *   The main data.
  * @param cache
  *   A structure for containing and caching relevant data.
  *
  * @return
  *   F_none on success.
+ *   F_busy on success and the process was found to already be running (nothing to do).
  *   F_signal on (exit) signal received.
  *
- *   Errors (with error bit) from: controller_asynchronouss_increase().
+ *   F_found_not (with error bit) if unable to for a process for the given rule id.
+ *   F_recurse (with error bit) on recursion error (the process is already on the process stack).
+ *
+ *   Status from: controller_rule_process().
+ *
+ *   Errors (with error bit) from: controller_rule_process().
  *   Errors (with error bit) from: f_string_dynamic_append().
  *   Errors (with error bit) from: f_thread_create().
+ *
+ * @see controller_rule_process()
+ * @see f_string_dynamic_append()
+ * @see f_thread_create()
  */
-#ifndef _di_controller_rule_process_asynchronous_
-  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_
+#ifndef _di_controller_rule_process_begin_
+  extern f_status_t controller_rule_process_begin(const bool asynchronous, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const f_array_lengths_t stack, const controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_process_begin_
+
+/**
+ * Helper for calling controller_rule_process().
+ *
+ * This does all the preparation work that needs to be synchronously performed within the same thread.
+ *
+ * @param asynchronous
+ *   If TRUE, designates that this function is being asynchronously executed.
+ *   If FALSE, designates that this function is being synchronously executed.
+ * @param process
+ *   The process data.
+ *
+ * @return
+ *   F_none on success.
+ *   F_found on success and the process was found to already be running (nothing to do).
+ *   F_signal on (exit) signal received.
+ *
+ *   F_found_not (with error bit) if unable to for a process for the given rule id.
+ *
+ *   Status from: controller_rule_process().
+ *
+ *   Errors (with error bit) from: controller_rule_copy().
+ *   Errors (with error bit) from: controller_rule_process().
+ *
+ * @see controller_rule_copy()
+ * @see controller_rule_process()
+ * @see controller_rule_process_begin()
+ */
+#ifndef _di_controller_rule_process_do_
+  extern f_status_t controller_rule_process_do(const bool asynchronous, controller_process_t *process) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_rule_process_do_
 
 /**
  * Read the rule file, extracting all valid items.
@@ -633,8 +660,8 @@ extern "C" {
  *   The string identifying the rule.
  *   This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
  *   "/etc/controller/rules/example/my.rule" would have a rule id of "example/my".
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   A structure for containing and caching relevant data.
  * @param rule
@@ -657,7 +684,7 @@ extern "C" {
  * @see fll_fss_basic_list_read().
  */
 #ifndef _di_controller_rule_read_
-  extern f_status_t controller_rule_read(const f_string_static_t rule_id, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_read(const f_string_static_t rule_id, controller_main_t main, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_read_
 
 /**
@@ -706,6 +733,8 @@ extern "C" {
  *
  * This automatically sets the rule's status to F_complete.
  *
+ * @param rule
+ *   The rule to process.
  * @param action
  *   The action to perform based on the action type codes.
  *
@@ -720,25 +749,23 @@ extern "C" {
  *   If no bits set, then operate normally in a synchronous manner.
  *   If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
  *   If bit controller_rule_option_asynchronous, then run asynchronously.
- * @param thread_data
- *   The thread data.
+ * @param main
+ *   The main data.
  * @param cache
  *   A structure for containing and caching relevant data.
- * @param rule
- *   The rule to process.
  */
 #ifndef _di_controller_rule_simulate_
-  extern void controller_rule_simulate(const uint8_t action, const uint8_t options, controller_thread_data_t thread_data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern void controller_rule_simulate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_cache_t *cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_simulate_
 
 /**
- * Wait until all currently running asynchronous execution threads are complete.
+ * Wait until all currently running Rule processes are complete.
  *
- * @param thread
- *   The thread data.
+ * @param main
+ *   The main data.
  */
 #ifndef _di_controller_rule_wait_all_
-  extern void controller_rule_wait_all(controller_thread_t *thread) f_gcc_attribute_visibility_internal;
+  extern void controller_rule_wait_all(const controller_main_t main) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_wait_all_
 
 #ifdef __cplusplus
index e9be5607cb94e6ca3544ebb81aa9f67f658c6fe2..81675f3989923fb0adb3fb0fcc615ed2624de87a 100644 (file)
 extern "C" {
 #endif
 
-#ifndef _di_controller_thread_asynchronous_process_
-  void * controller_thread_asynchronous_process(void *arguments) {
-
-    controller_asynchronous_t *asynchronous = (controller_asynchronous_t *) arguments;
-    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);
-
-      return 0;
-    }
-
-    f_thread_unlock(&main->lock.asynchronous);
-
-    f_array_length_t at_process = 0;
-
-    f_thread_lock_read(&main->thread->lock.process);
-
-    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++;
-      }
-    }
-
-    // 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.
-
-    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_process_
-
-#ifndef _di_controller_thread_asynchronous_cancel_
-  void controller_thread_asynchronous_cancel(controller_thread_t *thread) {
-
-    thread->enabled = F_false;
-
-    f_thread_mutex_lock(&thread->lock.asynchronous);
+#ifndef _di_controller_thread_cleanup_
+  void * controller_thread_cleanup(void *arguments) {
 
-    for (f_array_length_t i = 0; i < thread->asynchronouss.used; ++i) {
+    const controller_main_t *main = (controller_main_t *) arguments;
 
-      if (!thread->asynchronouss.array[i].state) continue;
+    const unsigned int interval = main->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cache_cleanup_interval_short : controller_thread_cache_cleanup_interval_long;
 
-      if (f_thread_mutex_lock_try(&thread->asynchronouss.array[i].lock) == F_none) {
-        f_thread_cancel(thread->asynchronouss.array[i].id);
-        f_thread_detach(thread->asynchronouss.array[i].id);
-        f_thread_mutex_unlock(&thread->asynchronouss.array[i].lock);
-      }
-      else {
-        if (thread->asynchronouss.array[i].child > 0) {
-          f_signal_send(F_signal_termination, thread->asynchronouss.array[i].child);
-        }
-        else {
-          f_thread_cancel(thread->asynchronouss.array[i].id);
-        }
+    while (main->thread->enabled) {
 
-        // the cancel make take time so detach the process to allow it to exit on its own.
-        f_thread_detach(thread->asynchronouss.array[i].id);
-      }
-    } // for
+      sleep(interval);
 
-    thread->asynchronouss.used = 0;
+      if (f_thread_lock_write_try(&main->thread->lock.process) == F_none) {
+        controller_process_t *process = 0;
 
-    f_thread_unlock(&thread->lock.asynchronous);
-  }
-#endif // _di_controller_thread_asynchronous_cancel_
+        // index 0 is reserved for "main thread".
+        f_array_length_t i = 1;
 
-#ifndef _di_controller_thread_cleanup_
-  void * controller_thread_cleanup(void *arguments) {
+        for (; j < main->thread->processs.used; ++i) {
 
-    controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments;
+          process = &main->thread->processs.array[i];
 
-    const unsigned int interval = thread_data->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cache_cleanup_interval_short : controller_thread_cache_cleanup_interval_long;
-
-    f_array_length_t i = 0;
+          if (f_thread_lock_write_try(&process->active) != F_none) {
+            continue;
+          }
 
-    for (; thread_data->thread->enabled; ) {
-      sleep(interval);
+          if (f_thread_lock_write_try(&process->lock) != F_none) {
+            f_thread_unlock(&process->active);
 
-      /*
-      if (f_thread_lock_write_try(&thread_data->thread->lock.asynchronous) == F_none) {
-        controller_thread_t *thread = &thread_data->thread;
+            continue;
+          }
 
-        if (thread->asynchronouss.used) {
-          for (i = 0; i < thread->asynchronouss.used; ++i) {
+          if (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
+            f_thread_unlock(&process->active);
+            f_thread_unlock(&process->lock);
 
-            if (!thread->enabled) break;
-            if (!thread->asynchronouss.array[i].state) continue;
+            continue;
+          }
 
-            if (f_thread_lock_write_try(&thread->asynchronouss.array[i].lock) != F_none) continue;
+          if (process->state == controller_process_state_done) {
+            f_thread_detach(process->id_thread);
+            process->state = controller_process_state_idle;
+          }
 
-            if (f_thread_lock_write_try(&thread_data->setting->rules.array[thread->asynchronouss.array[i].index].lock) == F_none) {
+          // deallocate dynamic portions of the structure that are only ever needed while the process is running.
+          controller_cache_delete_simple(&process->cache);
+          f_type_array_lengths_resize(0, &process->stack);
 
-              if (thread->asynchronouss.array[i].state == controller_asynchronous_state_done) {
-                f_thread_join(thread->asynchronouss.array[i].id, 0);
-                thread->asynchronouss.array[i].state = controller_asynchronous_state_joined;
-              }
+          f_thread_unlock(&process->active);
+          f_thread_unlock(&process->lock);
+        } // for
 
-              if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) {
-                controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]);
+        for (i = main->thread->processs.used - 1; main->thread->processs.used; --i, --main->thread->processs.used) {
 
-                thread->asynchronouss.array[i].state = 0;
-              }
+          process = &main->thread->processs.array[i];
 
-              f_thread_condition_signal(&thread_data->setting->rules.array[thread->asynchronouss.array[i].index].wait);
-              f_thread_mutex_unlock(&thread_data->setting->rules.array[thread->asynchronouss.array[i].index].lock);
-            }
+          if (f_thread_lock_write_try(&process->active) != F_none) {
+            break;
+          }
 
-            f_thread_mutex_unlock(&thread->asynchronouss.array[i].lock);
-          } // for
+          if (f_thread_lock_write_try(&process->lock) != F_none) {
+            f_thread_unlock(&process->active);
 
-          for (i = thread->asynchronouss.used - 1; thread->asynchronouss.used; --i, --thread->asynchronouss.used) {
+            break;
+          }
 
-            if (!thread->enabled) break;
+          if (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
+            f_thread_unlock(&process->active);
+            f_thread_unlock(&process->lock);
 
-            if (f_thread_mutex_lock_try(&thread->asynchronouss.array[i].lock) != F_none) break;
+            break;
+          }
 
-            if (thread->asynchronouss.array[i].state == controller_asynchronous_state_joined) {
-              controller_macro_asynchronous_t_delete_simple(thread->asynchronouss.array[i]);
+          if (process->state == controller_process_state_done) {
+            f_thread_detach(process->id_thread);
+            process->state = controller_process_state_idle;
+          }
 
-              thread->asynchronouss.array[i].state = 0;
-            }
-            else if (thread->asynchronouss.array[i].state) {
-              f_thread_unlock(&thread->asynchronouss.array[i].lock);
-              break;
-            }
+          // deallocate dynamic portions of the structure that are only ever needed while the process is running.
+          controller_cache_delete_simple(&process->cache);
+          f_type_array_lengths_resize(0, &process->stack);
 
-            f_thread_unlock(&thread->asynchronouss.array[i].lock);
-          } // for
-        }
+          --main->thread->processs.used;
 
-        if (thread->enabled && thread->asynchronouss.used < thread->asynchronouss.size) {
-          controller_asynchronouss_resize(thread->asynchronouss.used, &thread->asynchronouss);
-        }
+          f_thread_unlock(&process->active);
+          f_thread_unlock(&process->lock);
+        } // for
 
-        f_thread_unlock(&thread->lock.asynchronous);
+        f_thread_unlock(&main->thread->lock.process);
       }
-      */
-    } // for
+    } // while
 
     return 0;
   }
@@ -192,7 +107,7 @@ extern "C" {
 #ifndef _di_controller_thread_control_
   void * controller_thread_control(void *arguments) {
 
-    controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments;
+    controller_main_t *main = (controller_main_t *) arguments;
 
     // @todo
 
@@ -206,27 +121,40 @@ extern "C" {
     f_status_t status = F_none;
 
     controller_thread_t thread = controller_thread_t_initialize;
-    controller_processs_t processs = controller_processs_t_initialize;
-    controller_thread_data_t thread_data = controller_macro_thread_data_t_initialize(0, data, setting, &processs, &thread);
+    controller_main_t main = controller_macro_main_t_initialize(data, setting, &thread);
 
-    status = controller_asynchronouss_increase(&thread.asynchronouss);
+    // the main locks must be initialized, but only once, so initialize immediately upon allocation.
+    status = controller_lock_create(&thread.lock);
 
-    if (F_status_is_error_not(status)) {
-      status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &thread_data);
+    if (F_status_is_error(status)) {
+      if (data->error.verbosity != f_console_verbosity_quiet) {
+        fll_error_print(data->error, status, "controller_lock_create", F_true);
+      }
     }
+    else {
+      status = controller_processs_increase(&thread.processs);
+
+      if (F_status_is_error(status)) {
+        controller_error_print(data->error, F_status_set_fine(status), "controller_processs_increase", F_true, &thread);
+      }
+    }
+
+    if (F_status_is_error_not(status)) {
+      status = f_thread_create(0, &thread.id_signal, &controller_thread_signal, (void *) &main);
 
-    if (F_status_is_error(status)) {
       if (data->error.verbosity != f_console_verbosity_quiet) {
         controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread);
       }
     }
-    else {
+
+    if (F_status_is_error_not(status)) {
       if (data->parameters[controller_parameter_daemon].result == f_console_result_found) {
 
         setting->ready = controller_setting_ready_done;
 
         if (f_file_exists(setting->path_pid.string) == F_true) {
           if (data->error.verbosity != f_console_verbosity_quiet) {
+
             f_thread_mutex_lock(&thread.lock.print);
 
             fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
@@ -244,22 +172,24 @@ extern "C" {
       else {
 
         // index 0 is reserved for running the main thread cache.
-        thread.asynchronouss.used = 1;
+        thread.processs.used = 1;
 
-        status = controller_entry_read(entry_name, thread_data, &thread.asynchronouss.array[0].cache);
+        status = controller_entry_read(entry_name, main, &thread.processs.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(thread_data, &thread.asynchronouss.array[0].cache);
+          status = controller_preprocess_entry(main, &thread.processs.array[0].cache);
         }
 
         if (F_status_is_error_not(status) && status != F_signal && status != F_child) {
+
           if (data->parameters[controller_parameter_validate].result == f_console_result_none || data->parameters[controller_parameter_test].result == f_console_result_found) {
 
             if (f_file_exists(setting->path_pid.string) == F_true) {
               if (data->error.verbosity != f_console_verbosity_quiet) {
+
                 f_thread_mutex_lock(&thread.lock.print);
 
                 fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
@@ -274,7 +204,7 @@ extern "C" {
               status = F_status_set_error(F_available_not);
             }
             else {
-              status = controller_process_entry(thread_data, &thread.asynchronouss.array[0].cache);
+              status = controller_process_entry(main, &thread.processs.array[0].cache);
 
               if (F_status_is_error(status)) {
                 setting->ready = controller_setting_ready_fail;
@@ -301,20 +231,16 @@ extern "C" {
       status = F_signal;
     }
 
-    // only make the rule and control threads available once any/all pre-processing and is completed.
+    // only make the rule and control threads available once any/all pre-processing and are completed.
     if (F_status_is_error_not(status) && status != F_signal && status != F_child) {
 
       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 *) &thread_data);
+        controller_rule_wait_all(main);
 
-        if (F_status_is_error_not(status)) {
-          status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &thread_data);
-        }
+        status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &main);
 
         if (F_status_is_error_not(status)) {
-          status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &thread_data);
+          status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &main);
         }
 
         if (F_status_is_error(status)) {
@@ -343,19 +269,15 @@ extern "C" {
     }
 
     if (thread.enabled) {
-      controller_thread_asynchronous_cancel(&thread);
+      controller_thread_process_cancel(main);
     }
 
-    // @todo when cancelling, make sure that whatever has a lock, no longer has any lock.
     f_thread_cancel(thread.id_cleanup);
     f_thread_cancel(thread.id_control);
-    f_thread_cancel(thread.id_rule);
 
-    f_thread_join(thread.id_cleanup, 0);
-    f_thread_join(thread.id_control, 0);
-    f_thread_join(thread.id_rule, 0);
+    f_thread_detach(thread.id_cleanup);
+    f_thread_detach(thread.id_control);
 
-    controller_processs_delete_simple(&processs);
     controller_thread_delete_simple(&thread);
 
     if (F_status_is_error(status)) {
@@ -370,33 +292,91 @@ extern "C" {
   }
 #endif // _di_controller_thread_main_
 
-#ifndef _di_controller_thread_rule_
-  void * controller_thread_rule(void *arguments) {
-
-    controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments;
+#ifndef _di_controller_thread_process_
+  void * controller_thread_process(void *arguments) {
 
-    // @todo
-    // f_thread_mutex_lock(&thread_data->lock.rule);
-    // f_thread_mutex_unlock(&thread_data->lock.rule);
+    controller_rule_process_do(F_true, (controller_process_t *) arguments);
 
     return 0;
   }
-#endif // _di_controller_thread_rule_
+#endif // _di_controller_thread_process_
+
+#ifndef _di_controller_thread_process_cancel_
+  void controller_thread_process_cancel(const controller_main_t main) {
+
+    // this must be set, regardless of lock state and only this function changes this.
+    main.thread->enabled = F_false;
+
+    f_thread_lock_write(&main.thread->lock.process);
+
+    if (!main.thread->processs.used) {
+      f_thread_unlock(&main.thread->lock.process);
+
+      return;
+    }
+
+    controller_process_t *process = 0;
+
+    bool locked = 0;
+
+    //pid_t[main.thread->processs.used] pids;
+    //memset(&pids, 0, sizeof(pid_t) * main.thread->processs.used);
+
+    // index 0 is reserved for running the main thread cache.
+    for (f_array_length_t i = 1; i < main.thread->processs.used; ++i) {
+
+      process = &main.thread->processs.array[i];
+
+      locked = f_thread_lock_write_try(&process->lock) == F_none;
+
+      if (!locked) {
+        locked = f_thread_lock_read_try(&process->lock) == F_none;
+      }
+
+      if (locked) {
+        if (process->child > 0) {
+          f_signal_send(F_signal_quit, process->child);
+        }
+
+        if (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
+          f_thread_cancel(process->id_thread);
+          f_thread_detach(process->id_thread);
+        }
+        else if (process->state == controller_process_state_done) {
+          f_thread_detach(process->id_thread);
+        }
+
+        f_thread_unlock(&process->lock);
+      }
+    } // for
+
+    main.thread->processs.used = 0;
+
+    // @todo: sleep a little, check to see if child processes quit, and if not then sen F_signal_quit_termination.
+    //        this will likely need to be done by:
+    //        1) create an array of child process ids from above loop.
+    //        2) search through loop at this location in the code and if the process id is found, sleep a little.
+    //        3) check again to see if the child process quit and if not, then send the F_signal_quit_termination.
+    //        4) continue to next child until entire array is processed.
+
+    f_thread_unlock(&main.thread->lock.process);
+  }
+#endif // _di_controller_thread_process_cancel_
 
 #ifndef _di_controller_thread_signal_
   void * controller_thread_signal(void *arguments) {
 
-    controller_thread_data_t *thread_data = (controller_thread_data_t *) arguments;
+    controller_main_t *main = (controller_main_t *) arguments;
 
-    for (int signal = 0; thread_data->thread->enabled; ) {
+    for (int signal = 0; main->thread->enabled; ) {
 
-      sigwait(&thread_data->data->signal.set, &signal);
+      sigwait(&main->data->signal.set, &signal);
 
-      if (thread_data->data->parameters[controller_parameter_interruptable].result == f_console_result_found) {
+      if (main->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->thread->signal = signal;
+          main->thread->signal = signal;
 
-          controller_thread_asynchronous_cancel(thread_data->thread);
+          controller_thread_process_cancel(*main);
           break;
         }
       }
index 22051b38ecc180ac0405b6a5658b843935e07453..f0c12e2298d0388dc3ef9f0784c1f73a5e08f7ce 100644 (file)
@@ -13,35 +13,11 @@ extern "C" {
 #endif
 
 /**
- * Asynchronously execute a process.
- *
- * @param arguments
- *   The thread arguments.
- *   Must be of type controller_asynchronous_t.
- *
- * @return
- *   0, always.
- */
-#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.
- *
- * @param thread
- *   The thread data.
- */
-#ifndef _di_controller_thread_asynchronous_cancel_
-  void controller_thread_asynchronous_cancel(controller_thread_t *thread) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_thread_asynchronous_cancel_
-
-/**
  * Thread for periodically cleanup data when not busy.
  *
  * @param arguments
  *   The thread arguments.
- *   Must be of type controller_thread_data_t.
+ *   Must be of type controller_main_t.
  *
  * @return
  *   0, always.
@@ -55,7 +31,7 @@ extern "C" {
  *
  * @param arguments
  *   The thread arguments.
- *   Must be of type controller_thread_data_t.
+ *   Must be of type controller_main_t.
  *
  * @return
  *   0, always.
@@ -85,18 +61,30 @@ extern "C" {
 #endif // _di_controller_thread_main_
 
 /**
- * Thread for handling loading of rules into memory.
+ * Asynchronously execute a Rule process.
  *
  * @param arguments
  *   The thread arguments.
- *   Must be of type controller_thread_data_t.
+ *   Must be of type controller_process_t.
  *
  * @return
  *   0, always.
+ *
+ * @see controller_rule_process_do()
+ */
+#ifndef _di_controller_thread_process_
+  extern void * controller_thread_process(void *arguments) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_thread_process_
+
+/**
+ * Cancel all process threads.
+ *
+ * @param main
+ *   The main thread data.
  */
-#ifndef _di_controller_thread_rule_
-  extern void * controller_thread_rule(void *arguments) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_thread_rule_
+#ifndef _di_controller_thread_process_cancel_
+  void controller_thread_process_cancel(const controller_main_t main) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_thread_process_cancel_
 
 /**
  * Thread for handling signals/interrupts.
@@ -105,7 +93,7 @@ extern "C" {
  *
  * @param arguments
  *   The thread arguments.
- *   Must be of type controller_thread_data_t.
+ *   Must be of type controller_main_t.
  *
  * @return
  *   0, always.