]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Wed, 31 Mar 2021 04:54:28 +0000 (23:54 -0500)
committerKevin Day <thekevinday@gmail.com>
Wed, 31 Mar 2021 04:54:28 +0000 (23:54 -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-rule.c
level_3/controller/c/private-rule.h
level_3/controller/c/private-thread.c

index 319f9112ad9b957b0a99d85006857732c28d7e0a..335e2c215390c29fe0046585829a1f1b88706e4f 100644 (file)
@@ -100,9 +100,6 @@ extern "C" {
     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;
 
@@ -118,7 +115,6 @@ extern "C" {
 
     f_thread_mutex_delete(&lock->print);
 
-    f_thread_lock_delete(&lock->entry);
     f_thread_lock_delete(&lock->process);
     f_thread_lock_delete(&lock->rule);
   }
index ebab445247514e0c38c14d0ba7fdac04d97d3257..a4a4fc3389024121b631c764e678d2415f888a1e 100644 (file)
@@ -448,7 +448,6 @@ extern "C" {
   typedef struct {
     f_thread_mutex_t print;
 
-    f_thread_lock_t entry;
     f_thread_lock_t process;
     f_thread_lock_t rule;
   } controller_lock_t;
@@ -457,7 +456,6 @@ extern "C" {
     f_thread_mutex_t_initialize, \
     f_thread_lock_t_initialize, \
     f_thread_lock_t_initialize, \
-    f_thread_lock_t_initialize, \
   }
 #endif // _di_controller_mutex_t_
 
@@ -593,6 +591,7 @@ extern "C" {
  * timeout_kill:     The timeout to wait relating to using a kill signal.
  * timeout_start:    The timeout to wait relating to starting a process.
  * timeout_stop:     The timeout to wait relating to stopping a process.
+ * status:           A status associated with the loading of the rule (not the execution of the rule).
  * has:              Bitwise set of "has" codes representing what the Rule has.
  * nice:             The niceness value if the Rule "has" nice.
  * user:             The User ID if the Rule "has" a user.
@@ -651,6 +650,8 @@ extern "C" {
   #define controller_rule_has_user          0x10
 
   typedef struct {
+    f_status_t status;
+
     f_number_unsigned_t timeout_kill;
     f_number_unsigned_t timeout_start;
     f_number_unsigned_t timeout_stop;
@@ -686,6 +687,7 @@ extern "C" {
   } controller_rule_t;
 
   #define controller_rule_t_initialize { \
+    F_known_not, \
     0, \
     0, \
     0, \
@@ -1047,8 +1049,6 @@ extern "C" {
  *
  * This is essentially data shared globally between threads, about threads.
  *
- * As a special case, index 0 of processs is reserved for use the main thread and is not used by any Rule Processes.
- *
  * 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.
@@ -1060,6 +1060,9 @@ extern "C" {
  * processs:   All Rule Process thread data.
  */
 #ifndef _di_controller_thread_t_
+  #define controller_thread_cleanup_interval_long  3600 // 1 hour in seconds.
+  #define controller_thread_cleanup_interval_short 180  // 3 minutes in seconds.
+
   typedef struct {
     bool enabled;
     int signal;
@@ -1092,10 +1095,6 @@ extern "C" {
  * thread:   All thread related data.
  */
 #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.
-
   typedef struct {
     controller_data_t *data;
     controller_setting_t *setting;
index 8938ca33309ba174a14e8d806707cd941eb6f355..cd1e7a3903b84f02b6baa7d5ecd84908d0b1bf52 100644 (file)
@@ -260,7 +260,7 @@ extern "C" {
     for (f_array_length_t i = 0; i < processs.used; ++i) {
 
       if (fl_string_dynamic_compare(alias, processs.array[i].alias_rule) == F_equal_to) {
-        *at = i;
+        if (at) *at = i;
         return F_true;
       }
     } // for
@@ -696,8 +696,6 @@ extern "C" {
       f_thread_mutex_unlock(&main.thread->lock.print);
     }
 
-    f_thread_lock_read(&main.thread->lock.entry);
-
     for (;;) {
 
       entry_actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions;
@@ -719,8 +717,6 @@ extern "C" {
         if (F_status_is_error(status)) {
           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;
         }
 
@@ -771,8 +767,6 @@ extern "C" {
                 f_thread_mutex_unlock(&main.thread->lock.print);
               }
 
-              f_thread_unlock(&main.thread->lock.entry);
-
               return F_status_is_error(F_require);
             }
             else if (main.data->warning.verbosity == f_console_verbosity_debug) {
@@ -859,11 +853,7 @@ extern "C" {
             else {
               controller_perform_ready(main, cache);
 
-              if (F_status_is_error(status)) {
-                f_thread_unlock(&main.thread->lock.entry);
-
-                return status;
-              }
+              if (F_status_is_error(status)) return status;
             }
 
             main.setting->ready = controller_setting_ready_yes;
@@ -897,8 +887,6 @@ extern "C" {
               f_thread_mutex_unlock(&main.thread->lock.print);
             }
 
-            f_thread_unlock(&main.thread->lock.entry);
-
             return F_status_is_error(F_critical);
           }
 
@@ -907,8 +895,6 @@ extern "C" {
           if (F_status_is_error(status)) {
             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;
           }
 
@@ -932,8 +918,6 @@ extern "C" {
           if (F_status_is_error(status)) {
             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;
           }
 
@@ -962,8 +946,6 @@ extern "C" {
           if (F_status_is_error(status)) {
             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;
           }
 
@@ -979,7 +961,9 @@ extern "C" {
 
           f_thread_lock_read(&main.thread->lock.rule);
 
-          at = controller_rule_find_loaded(alias_rule, main);
+          status = controller_rule_find(alias_rule, main.setting->rules, &at);
+
+          f_thread_unlock(&main.thread->lock.rule);
 
           if (simulate) {
             f_thread_mutex_lock(&main.thread->lock.print);
@@ -993,9 +977,7 @@ extern "C" {
           }
 
           // the rule is not yet loaded, ensure that it is loaded.
-          if (at == main.setting->rules.used) {
-
-            f_thread_unlock(&main.thread->lock.rule);
+          if (status != F_true) {
 
             // 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;
@@ -1054,9 +1036,44 @@ extern "C" {
             }
 
             f_thread_unlock(&main.thread->lock.rule);
-          }
-          else {
-            f_thread_unlock(&main.thread->lock.rule);
+
+            // ensure that a process exists for the added rule.
+            if (F_status_is_error_not(status)) {
+              f_thread_lock_read(&main.thread->lock.process);
+
+              if (controller_find_process(alias_rule, main.thread->processs, 0) == F_false) {
+
+                f_thread_unlock(&main.thread->lock.process);
+                f_thread_lock_write(&main.thread->lock.process);
+
+                status = controller_processs_increase(&main.thread->processs);
+
+                if (F_status_is_error(status)) {
+                  controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "controller_processs_increase", F_true, main.thread);
+                }
+                else {
+                  controller_process_t *process = &main.thread->processs.array[main.thread->processs.used];
+
+                  status = f_string_dynamic_append(alias_rule, &process->alias_rule);
+
+                  if (F_status_is_error(status)) {
+                    controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, main.thread);
+                  }
+                  else {
+                    status = f_string_dynamic_terminate_after(&process->alias_rule);
+
+                    if (F_status_is_error(status)) {
+                      controller_entry_error_print(main.data->error, cache->action, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, main.thread);
+                    }
+                    else {
+                      process->id = main.thread->processs.used++;
+                    }
+                  }
+                }
+              }
+
+              f_thread_unlock(&main.thread->lock.process);
+            }
           }
 
           if (F_status_is_error_not(status) && entry_action->type == controller_entry_action_type_rule) {
@@ -1078,7 +1095,7 @@ extern "C" {
               rule_options |= controller_rule_option_asynchronous;
             }
 
-            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);
+            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;
@@ -1142,8 +1159,6 @@ extern "C" {
               f_thread_mutex_unlock(&main.thread->lock.print);
             }
 
-            f_thread_unlock(&main.thread->lock.entry);
-
             return F_status_is_error(F_critical);
           }
           else {
@@ -1206,8 +1221,6 @@ extern "C" {
       }
     } // for
 
-    f_thread_unlock(&main.thread->lock.entry);
-
     if (status == F_child || status == F_signal) {
       return status;
     }
index 7e59ddd148ce469107548f076fd8f6438eda8ef7..fda8df9bae0e7cbfd6146c6e18ec11217d80bb00 100644 (file)
@@ -170,6 +170,7 @@ extern "C" {
  *   The array of processes to.
  * @param at
  *   The location within processs the id was found.
+ *   (optional) Set to NULL to disable.
  *
  * @return
  *   F_none if not given a valid id to search.
index 317db168d0c92904648efcf9056f08af47fd7827..56ee6ae4b6d55571403ceea5d1e282b507c6783f 100644 (file)
@@ -2,6 +2,7 @@
 #include "private-common.h"
 #include "private-controller.h"
 #include "private-rule.h"
+#include "private-entry.h"
 #include "private-thread.h"
 
 #ifdef __cplusplus
@@ -40,7 +41,7 @@ extern "C" {
     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;
+        if (at) *at = i;
         return F_true;
       }
     } // for
@@ -517,7 +518,15 @@ extern "C" {
     }
 
     status = f_capability_copy(source.capability, &destination->capability);
-    if (F_status_is_error(status)) return status;
+
+    if (F_status_is_error(status)) {
+
+      // F_parameter is returned when source.capability is not used or when destination->capability is 0.
+      // check to see why the error happens, such that source.capability not being used is not an error.
+      if (F_status_set_fine(status) != F_parameter || !&destination->capability) {
+        return status;
+      }
+    }
 
     status = f_control_group_copy(source.control_group, &destination->control_group);
     if (F_status_is_error(status)) return status;
@@ -697,8 +706,20 @@ extern "C" {
   }
 #endif // _di_controller_rule_error_print_need_want_wish_
 
+#ifndef _di_controller_rule_error_print_rule_not_loaded_
+  void controller_rule_error_print_rule_not_loaded(const fll_error_print_t output, const f_string_t alias) {
+
+    if (output.verbosity != f_console_verbosity_quiet) {
+      fprintf(output.to.stream, "%c", f_string_eol_s[0]);
+      fprintf(output.to.stream, "%s%sThe rule '", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s);
+      fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, alias, output.notable.after->string);
+      fprintf(output.to.stream, "%s' is no longer loaded.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
+    }
+  }
+#endif // _di_controller_rule_error_print_rule_not_loaded_
+
 #ifndef _di_controller_rule_execute_
-  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 controller_rule_execute(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) {
 
     f_status_t status = F_none;
     f_status_t success = F_false;
@@ -707,7 +728,7 @@ extern "C" {
     f_array_length_t j = 0;
     f_array_length_t k = 0;
 
-    // child processes should receive all signals, without blocking.
+    // child processes should receive all signals and handle the signals as they see fit.
     f_signal_how_t signals = f_signal_how_t_initialize;
     f_signal_set_empty(&signals.block);
     f_signal_set_fill(&signals.block_not);
@@ -718,101 +739,101 @@ extern "C" {
 
     controller_execute_set_t execute_set = controller_macro_execute_set_t_initialize(0, &environment, &signals, 0, fl_execute_as_t_initialize);
 
-    // when using pointers in threads and calling the exec functions, invalid reads and writes may occure.
-    // make local copies and have the pointers reference these to avoid invalid reads and writes.
+    // @todo now that "rule' is a (local) copy, this workaround might no longer be necessary.
+    // when using pointers in threads and calling the exec functions, invalid reads and writes may occur.
+    // this problem might be happening due to a compiler optimization/decision, so make local copies and have the pointers reference these to avoid invalid reads and writes.
     int local_nice;
     uid_t local_id_user;
     gid_t local_id_group;
 
-    // @todo now that "rule' is a (local) copy, this workaround might no longer be necessary.
     f_int32s_t local_affinity;
     f_control_group_t local_control_group;
     f_int32s_t local_id_groups;
     f_limit_sets_t local_limits;
     f_execute_scheduler_t local_scheduler;
 
-    if (rule->affinity.used) {
-      local_affinity = rule->affinity;
+    if (rule.affinity.used) {
+      local_affinity = rule.affinity;
       execute_set.as.affinity = &local_affinity;
     }
 
-    if (rule->capability) {
-      execute_set.as.capability = rule->capability;
+    if (rule.capability) {
+      execute_set.as.capability = rule.capability;
     }
 
-    if (rule->has & controller_rule_has_control_group) {
-      local_control_group = rule->control_group;
+    if (rule.has & controller_rule_has_control_group) {
+      local_control_group = rule.control_group;
       execute_set.as.control_group = &local_control_group;
 
       // make sure all required cgroup directories exist.
-      if (rule->status == F_known_not) {
-        status = fll_control_group_prepare(rule->control_group);
+      if (process->status == F_known_not) {
+        status = fll_control_group_prepare(rule.control_group);
 
         if (F_status_is_error(status)) {
           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);
+          process->status = F_status_set_error(F_failure);
           return status;
         }
       }
     }
 
-    if (rule->has & controller_rule_has_group) {
-      local_id_group = rule->group;
+    if (rule.has & controller_rule_has_group) {
+      local_id_group = rule.group;
       execute_set.as.id_group = &local_id_group;
 
-      if (rule->groups.used) {
-        local_id_groups = rule->groups;
+      if (rule.groups.used) {
+        local_id_groups = rule.groups;
         execute_set.as.id_groups = &local_id_groups;
       }
     }
 
-    if (rule->limits.used) {
-      local_limits = rule->limits;
+    if (rule.limits.used) {
+      local_limits = rule.limits;
       execute_set.as.limits = &local_limits;
     }
 
-    if (rule->has & controller_rule_has_scheduler) {
-      local_scheduler = rule->scheduler;
+    if (rule.has & controller_rule_has_scheduler) {
+      local_scheduler = rule.scheduler;
       execute_set.as.scheduler = &local_scheduler;
     }
 
-    if (rule->has & controller_rule_has_nice) {
-      local_nice = rule->nice;
+    if (rule.has & controller_rule_has_nice) {
+      local_nice = rule.nice;
       execute_set.as.nice = &local_nice;
     }
 
-    if (rule->has & controller_rule_has_user) {
-      local_id_user = rule->user;
+    if (rule.has & controller_rule_has_user) {
+      local_id_user = rule.user;
       execute_set.as.id_user = &local_id_user;
     }
 
-    status = fl_environment_load_names(rule->environment, &environment);
+    status = fl_environment_load_names(rule.environment, &environment);
 
     if (F_status_is_error(status)) {
       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);
+      process->status = F_status_set_error(F_failure);
       return status;
     }
 
-    for (i = 0; i < rule->items.used; ++i) {
+    for (i = 0; i < rule.items.used; ++i) {
 
       if (main.thread->signal) {
         status = F_signal;
         break;
       }
 
-      if (rule->items.array[i].type == controller_rule_item_type_setting) continue;
+      if (rule.items.array[i].type == controller_rule_item_type_setting) continue;
 
-      for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+      for (j = 0; j < rule.items.array[i].actions.used; ++j) {
 
         if (main.thread->signal) {
           status = F_signal;
           break;
         }
 
-        if (rule->items.array[i].actions.array[j].type != type) continue;
+        if (rule.items.array[i].actions.array[j].type != action) continue;
 
         execute_set.parameter.data = 0;
         execute_set.parameter.option = fl_execute_parameter_option_threadsafe;
@@ -821,56 +842,56 @@ extern "C" {
           execute_set.parameter.option |= fl_execute_parameter_option_return;
         }
 
-        if (rule->items.array[i].type == controller_rule_item_type_command) {
+        if (rule.items.array[i].type == controller_rule_item_type_command) {
 
-          if (strchr(rule->items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) {
+          if (strchr(rule.items.array[i].actions.array[j].parameters.array[0].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], 0, rule->items.array[i].actions.array[j].parameters, options, &execute_set, main, rule);
+          status = controller_rule_execute_foreground(rule, rule.items.array[i].type, rule.items.array[i].actions.array[j], 0, rule.items.array[i].actions.array[j].parameters, options, main, &execute_set, process);
 
           if (status == F_child) break;
 
           if (F_status_is_error(status)) {
-            rule->items.array[i].actions.array[j].status = F_status_set_error(F_failure);
+            rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
 
             if (!(options & controller_rule_option_simulate)) break;
           }
 
           success = F_true;
         }
-        else if (rule->items.array[i].type == controller_rule_item_type_script) {
+        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];
+          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])) {
+          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, main, rule);
+          status = controller_rule_execute_foreground(rule, 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, main, &execute_set, process);
 
           if (status == F_child) break;
 
           if (F_status_is_error(status)) {
-            rule->items.array[i].actions.array[j].status = F_status_set_error(F_failure);
+            rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
 
             if (!(options & controller_rule_option_simulate)) break;
           }
 
           success = F_true;
         }
-        else if (rule->items.array[i].type == controller_rule_item_type_service) {
+        else if (rule.items.array[i].type == controller_rule_item_type_service) {
 
-          if (strchr(rule->items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) {
+          if (strchr(rule.items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) {
             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, main, rule);
+          status = controller_rule_execute_pid_with(rule, rule.items.array[i].type, rule.items.array[i].actions.array[j], 0, rule.items.array[i].actions.array[j].parameters, options, main, &execute_set, process);
 
           if (status == F_child) break;
 
           if (F_status_is_error(status)) {
-            rule->items.array[i].actions.array[j].status = F_status_set_error(F_failure);
+            rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
 
             if (!(options & controller_rule_option_simulate)) break;
           }
@@ -885,12 +906,12 @@ extern "C" {
             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(main.data->warning, cache->action, F_true);
+            controller_rule_error_print(main.data->warning, process->cache.action, F_true);
 
             f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
-          rule->items.array[i].actions.array[j].status = F_ignore;
+          rule.items.array[i].actions.array[j].status = F_ignore;
 
           if (success != F_true) {
             success = F_ignore;
@@ -912,21 +933,21 @@ extern "C" {
     }
 
     if (F_status_is_error(status) || success == F_false) {
-      rule->status = F_status_set_error(F_failure);
+      process->status = F_status_set_error(F_failure);
     }
     else if (success == F_ignore || success == F_busy) {
-      rule->status = success;
+      process->status = success;
     }
     else {
-      rule->status = F_none;
+      process->status = F_none;
     }
 
-    return rule->status;
+    return process->status;
   }
 #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_main_t main, controller_rule_t *rule) {
+  f_status_t controller_rule_execute_foreground(const controller_rule_t rule, 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, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) {
 
     f_status_t status = F_none;
     int result = 0;
@@ -946,7 +967,7 @@ extern "C" {
         } // for
 
         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%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(&main.thread->lock.print);
@@ -968,14 +989,14 @@ extern "C" {
     if (status == F_parent) {
       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.
-      main.thread->asynchronouss.array[main.id].child = id_process;
+      // assign the child process id to allow for the cancel process to send appropriate termination signals to the child process.
+      process->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.
-      main.thread->asynchronouss.array[main.id].child = 0;
+      process->child = 0;
 
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
@@ -1027,7 +1048,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_main_t main, controller_rule_t *rule) {
+  f_status_t controller_rule_execute_pid_with(const controller_rule_t rule, 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, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) {
 
     f_status_t status = F_none;
     int result = 0;
@@ -1056,7 +1077,7 @@ extern "C" {
         } // for
 
         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%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(&main.thread->lock.print);
@@ -1078,14 +1099,14 @@ extern "C" {
     if (status == F_parent) {
       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.
-      main.thread->asynchronouss.array[main.id].child = id_process;
+      // assign the child process id to allow for the cancel process to send appropriate termination signals to the child process.
+      process->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.
-      main.thread->asynchronouss.array[main.id].child = 0;
+      process->child = 0;
 
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
@@ -1549,7 +1570,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 uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) {
+  f_status_t controller_rule_process(const uint8_t action, const uint8_t options, const controller_main_t main, controller_rule_t rule, controller_process_t *process) {
 
     switch (action) {
       case controller_rule_action_type_freeze:
@@ -1573,7 +1594,7 @@ extern "C" {
           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(main.data->error, cache->action, F_true);
+          controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
           f_thread_mutex_unlock(&main.thread->lock.print);
         }
@@ -1583,64 +1604,64 @@ extern "C" {
 
     f_status_t status = F_none;
 
-    cache->action.name_action.used = 0;
-    cache->action.name_item.used = 0;
-    cache->action.name_file.used = 0;
+    process->cache.action.name_action.used = 0;
+    process->cache.action.name_item.used = 0;
+    process->cache.action.name_file.used = 0;
 
-    status = f_string_append(controller_string_rules_s, controller_string_rules_length, &cache->action.name_file);
+    status = f_string_append(controller_string_rules_s, controller_string_rules_length, &process->cache.action.name_file);
 
     if (F_status_is_error_not(status)) {
-      status = f_string_append(f_path_separator_s, f_path_separator_length, &cache->action.name_file);
+      status = f_string_append(f_path_separator_s, f_path_separator_length, &process->cache.action.name_file);
     }
 
     if (F_status_is_error(status)) {
       f_thread_mutex_lock(&main.thread->lock.print);
 
       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);
+      controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
       f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
 
-    status = f_string_dynamic_append(rule.alias, &cache->action.name_file);
+    status = f_string_dynamic_append(rule.alias, &process->cache.action.name_file);
 
     if (F_status_is_error(status)) {
       f_thread_mutex_lock(&main.thread->lock.print);
 
       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);
+      controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
       f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
 
-    status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &cache->action.name_file);
+    status = f_string_append(f_path_extension_separator, f_path_extension_separator_length, &process->cache.action.name_file);
 
     if (F_status_is_error_not(status)) {
-      status = f_string_append(controller_string_rule_s, controller_string_rule_length, &cache->action.name_file);
+      status = f_string_append(controller_string_rule_s, controller_string_rule_length, &process->cache.action.name_file);
     }
 
     if (F_status_is_error(status)) {
       f_thread_mutex_lock(&main.thread->lock.print);
 
       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);
+      controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
       f_thread_mutex_unlock(&main.thread->lock.print);
 
       return status;
     }
 
-    status = f_string_dynamic_terminate_after(&cache->action.name_file);
+    status = f_string_dynamic_terminate_after(&process->cache.action.name_file);
 
     if (F_status_is_error(status)) {
       f_thread_mutex_lock(&main.thread->lock.print);
 
       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);
+      controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
       f_thread_mutex_unlock(&main.thread->lock.print);
 
@@ -1648,7 +1669,7 @@ extern "C" {
     }
 
     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);
+      controller_rule_simulate(rule, controller_rule_action_type_start, options, main, &process->cache);
     }
 
     f_array_length_t i = 0;
@@ -1663,9 +1684,9 @@ extern "C" {
       controller_process_t *process_other = 0;
 
       f_string_dynamics_t * const dynamics[] = {
-        &rule->need,
-        &rule->want,
-        &rule->wish,
+        &rule.need,
+        &rule.want,
+        &rule.wish,
       };
 
       const f_string_t strings[] = {
@@ -1682,7 +1703,7 @@ extern "C" {
 
           f_thread_lock_read(&main.thread->lock.rule);
 
-          status = controller_find_process(dynamics[i]->array[j], *main.thread->processs, &id_process);
+          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);
@@ -1695,7 +1716,7 @@ extern "C" {
               f_thread_mutex_lock(&main.thread->lock.print);
 
               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);
+              controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
               f_thread_mutex_unlock(&main.thread->lock.print);
 
@@ -1712,7 +1733,7 @@ extern "C" {
                 f_thread_mutex_lock(&main.thread->lock.print);
 
                 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);
+                controller_rule_error_print(main.data->warning, process->cache.action, F_true);
 
                 f_thread_mutex_unlock(&main.thread->lock.print);
               }
@@ -1722,7 +1743,7 @@ extern "C" {
           if (status == F_true && id_rule < main.setting->rules.used) {
             f_thread_lock_read(&main.thread->lock.process);
 
-            process_other = &main.thread->processs->array[id_process];
+            process_other = &main.thread->processs.array[id_process];
 
             f_thread_lock_read(&process_other->active);
             f_thread_lock_read(&process_other->lock);
@@ -1753,9 +1774,9 @@ extern "C" {
             rule_other = &main.setting->rules.array[id_rule];
 
             // 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) {
+            if (process_other->status == F_known_not) {
 
-              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);
+              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, process->cache);
 
               if (status == F_child || status == F_signal) {
                 f_thread_unlock(&process_other->active);
@@ -1769,7 +1790,7 @@ extern "C" {
                   f_thread_mutex_lock(&main.thread->lock.print);
 
                   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);
+                  controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
                   f_thread_mutex_unlock(&main.thread->lock.print);
 
@@ -1785,7 +1806,7 @@ extern "C" {
                     f_thread_mutex_lock(&main.thread->lock.print);
 
                     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);
+                    controller_rule_error_print(main.data->warning, process->cache.action, F_true);
 
                     f_thread_mutex_unlock(&main.thread->lock.print);
                   }
@@ -1795,14 +1816,14 @@ extern "C" {
 
             f_thread_unlock(&process_other->active);
 
-            if (F_status_is_error(rule_other->status)) {
+            if (F_status_is_error(process_other->status)) {
               if (i == 0 || i == 1) {
                 f_thread_mutex_lock(&main.thread->lock.print);
 
                 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(main.data->error, cache->action, F_true);
+                controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
                 f_thread_mutex_unlock(&main.thread->lock.print);
 
@@ -1816,7 +1837,7 @@ extern "C" {
                   f_thread_mutex_lock(&main.thread->lock.print);
 
                   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);
+                  controller_rule_error_print(main.data->warning, process->cache.action, F_true);
 
                   f_thread_mutex_unlock(&main.thread->lock.print);
                 }
@@ -1879,7 +1900,7 @@ extern "C" {
             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(main.data->error, cache->action, F_true);
+            controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
             f_thread_mutex_unlock(&main.thread->lock.print);
           }
@@ -1889,7 +1910,6 @@ extern "C" {
       }
 
       if (F_status_is_error_not(status)) {
-        // @todo make sure to update this function.
         status = controller_rule_execute(rule, action, options, main, process);
 
         if (status == F_child) {
@@ -1901,7 +1921,7 @@ extern "C" {
         }
 
         if (F_status_is_error(status)) {
-          controller_rule_error_print_locked(main.data->error, cache->action, F_true, thread);
+          controller_rule_error_print_locked(main.data->error, process->cache.action, F_true, main.thread);
         }
       }
     }
@@ -1915,13 +1935,9 @@ extern "C" {
 #endif // _di_controller_rule_process_
 
 #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);
+  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, const controller_cache_t cache) {
 
     if (!main.thread->enabled) {
-      f_thread_mutex_unlock(&main.thread->lock.process);
-
       return F_signal;
     }
 
@@ -1930,9 +1946,9 @@ extern "C" {
     controller_process_t *process = 0;
 
     {
-      f_array_length_t id_process = 0;
+      f_array_length_t at = 0;
 
-      if (controller_find_process(alias_rule, *main.thread->processs, &id_process) != F_true) {
+      if (controller_find_process(alias_rule, main.thread->processs, &at) != F_true) {
         status = F_status_set_error(F_found_not);
       }
 
@@ -1941,14 +1957,10 @@ extern "C" {
       if (F_status_is_error(status)) {
 
         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]);
+          f_thread_mutex_lock(&main.thread->lock.print);
 
-          controller_entry_error_print_cache(main.data->error, cache->action);
+          controller_rule_error_print_rule_not_loaded(main.data->error, alias_rule.string);
+          controller_rule_error_print(main.data->error, cache.action, F_false);
 
           f_thread_mutex_unlock(&main.thread->lock.print);
         }
@@ -1956,9 +1968,9 @@ extern "C" {
         return status;
       }
 
-      f_thread_lock_write(&main.thread->processs->array[id_process].lock);
+      f_thread_lock_write(&main.thread->processs.array[at].lock);
 
-      process = &main.thread->processs->array[id_process];
+      process = &main.thread->processs.array[at];
 
       // 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) {
@@ -1971,16 +1983,13 @@ extern "C" {
 
       // the thread is done, so detach/close the thread.
       if (process->state == controller_process_state_done) {
-        f_thread_detach(process->id_thread);
+        f_thread_cancel(process->id_thread);
+        f_thread_join(process->id_thread, 0);
       }
 
-      process->id = id_process;
+      process->id = at;
     }
 
-    process->main.data = main.data;
-    process->main.setting = main.setting;
-    process->main.thread = main.thread;
-
     process->state = controller_process_state_active;
     process->action = action;
     process->options = options;
@@ -2000,15 +2009,18 @@ extern "C" {
     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;
+    process->cache.action.line_action = cache.action.line_action;
+    process->cache.action.line_item = cache.action.line_item;
+    process->cache.action.name_action.used = 0;
+    process->cache.action.name_file.used = 0;
+    process->cache.action.name_item.used = 0;
+    process->cache.action.generic.used = 0;
 
     process->stack.used = 0;
 
-    process->main_data = (void *) &main->data;
-    process->main_setting = (void *) &main->setting;
-    process->main_thread = (void *) &main->thread;
+    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) {
@@ -2016,7 +2028,7 @@ extern "C" {
       }
 
       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_resize", F_true, process_data.thread);
+        controller_entry_error_print(main.data->error, cache.action, F_status_set_fine(status), "f_type_array_lengths_resize", F_true, main.thread);
       }
       else {
         for (f_array_length_t i = 0; i < stack.used; ++i) {
@@ -2026,17 +2038,17 @@ extern "C" {
     }
 
     if (F_status_is_error_not(status)) {
-      status = f_string_dynamic_append(process_data.thread->cache_action.name_action, &process->cache.action.name_action);
+      status = f_string_dynamic_append(cache.action.name_action, &process->cache.action.name_action);
 
       if (F_status_is_error_not(status)) {
-        status = f_string_dynamic_append(process_data.thread->cache_action.name_file, &process->cache.action.name_file);
+        status = f_string_dynamic_append(cache.action.name_file, &process->cache.action.name_file);
       }
 
       if (F_status_is_error_not(status)) {
-        status = f_string_dynamic_append(process_data.thread->cache_action.name_item, &process->cache.action.name_item);
+        status = f_string_dynamic_append(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(main.data->error, cache.action, F_status_set_fine(status), "f_string_dynamic_append", F_true, main.thread);
       }
     }
 
@@ -2047,7 +2059,7 @@ extern "C" {
         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);
+          controller_entry_error_print(main.data->error, cache.action, F_status_set_fine(status), "f_thread_create", F_true, main.thread);
         }
       }
       else {
@@ -2070,18 +2082,14 @@ extern "C" {
 
     f_thread_lock_read(&process->lock);
 
-    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);
-
-    f_thread_lock_read(&main.thread->lock.process);
+    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 (!main.thread->enabled) {
       f_thread_unlock(&process->lock);
-      f_thread_unlock(&main.thread->lock.process);
 
       return F_signal;
     }
 
-    f_thread_unlock(&main.thread->lock.process);
     f_thread_lock_read(&process->active);
     f_thread_mutex_lock(&process->running);
 
@@ -2098,7 +2106,7 @@ extern "C" {
       f_thread_unlock(&main.thread->lock.rule);
 
       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);
+        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) {
@@ -2112,7 +2120,7 @@ extern "C" {
               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]);
 
-              controller_rule_error_print(main.data->error, cache->action, F_true);
+              controller_rule_error_print(main.data->error, process->cache.action, F_true);
 
               f_thread_mutex_unlock(&main.thread->lock.print);
             }
@@ -2131,7 +2139,7 @@ extern "C" {
           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);
+            controller_entry_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "f_type_array_lengths_increase", F_true, main.thread);
           }
           else {
             process->stack.array[process->stack.used++] = id_rule;
@@ -2143,12 +2151,14 @@ extern "C" {
       }
 
       if (F_status_is_error_not(status)) {
-        status = controller_rule_process(rule, controller_rule_action_type_start, rule_options, main, process);
+        const uint8_t rule_options = asynchronous ? controller_rule_option_asynchronous : 0;
+
+        status = controller_rule_process(controller_rule_action_type_start, rule_options, main, rule, 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);
+          controller_entry_error_print_cache(main.data->error, process->cache.action);
 
           f_thread_mutex_unlock(&main.thread->lock.print);
         }
@@ -2162,12 +2172,8 @@ extern "C" {
       if (main.data->error.verbosity != f_console_verbosity_quiet) {
         f_thread_mutex_lock(&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, 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]);
-
-        controller_entry_error_print_cache(main.data->error, process->cache->action);
+        controller_rule_error_print_rule_not_loaded(main.data->error, process->alias_rule.string);
+        controller_rule_error_print(main.data->error, process->cache.action, F_false);
 
         f_thread_mutex_unlock(&main.thread->lock.print);
       }
@@ -2177,10 +2183,10 @@ extern "C" {
     f_thread_lock_write(&process->lock);
 
     if (asynchronous) {
-      process->state = controller_asynchronous_state_done;
+      process->state = controller_process_state_done;
     }
     else {
-      process->state = controller_asynchronous_state_idle;
+      process->state = controller_process_state_idle;
     }
 
     --process->stack.used;
@@ -4379,8 +4385,6 @@ extern "C" {
 
     fprintf(data->output.stream, "}%c", f_string_eol_s[0]);
 
-    main.setting->rules.array[index].status = F_complete;
-
     f_thread_mutex_unlock(&main.thread->lock.print);
   }
 #endif // _di_controller_rule_simulate_
index 49fd2d51e3f7fa8a99b77f0159ad301d68d4f009..2aacd7a83f53c550d8829e5a84e1bbf90cbe8b5d 100644 (file)
@@ -35,6 +35,7 @@ extern "C" {
  *   The rules to search through.
  * @param at
  *   The index the rule was found at.
+ *   (optional) Set to NULL to disable.
  *
  * @return
  *   F_none on success, but the id.used is 0.
@@ -280,7 +281,9 @@ extern "C" {
 /**
  * Perform an execution of the given rule.
  *
- * @param type
+ * @param rule
+ *   The rule being executed.
+ * @param action
  *   The action to perform based on the action type codes.
  *
  *   Only subset of the action type codes are supported:
@@ -296,10 +299,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 main
  *   The main data.
- * @param cache
- *   A structure for containing and caching relevant data.
- * @param rule
- *   The rule to process.
+ * @param process
+ *   The process data for processing this rule.
  *
  * @return
  *   F_none on success.
@@ -311,12 +312,14 @@ 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_main_t main, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_execute(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_execute_
 
 /**
  * Perform an execution of the given rule in the foreground.
  *
+ * @param rule
+ *   The rule being executed.
  * @param type
  *   The item type code.
  * @param action
@@ -335,12 +338,12 @@ 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 execute_set
- *   The execute parameter and as settings.
  * @param main
  *   The main data.
- * @param rule
- *   The rule to process.
+ * @param execute_set
+ *   The execute parameter and as settings.
+ * @param process
+ *   The process data for processing this rule.
  *
  * @return
  *   F_none on success.
@@ -352,7 +355,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_main_t main, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_execute_foreground(const controller_rule_t rule, 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, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_foreground_
 
 /**
@@ -361,6 +364,8 @@ extern "C" {
  * When this is synchronous, this will wait for the PID file to be generated before continuing.
  * When this is asynchronous, this will continue on adding the rule id and action to the asynchronous list.
  *
+ * @param rule
+ *   The rule being executed.
  * @param type
  *   The item type code.
  * @param action
@@ -379,13 +384,12 @@ 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 execute_set
- *   The execute parameter and as settings.
  * @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.
+ * @param execute_set
+ *   The execute parameter and as settings.
+ * @param process
+ *   The process data for processing this rule.
  *
  * @return
  *   F_none on success.
@@ -398,7 +402,7 @@ 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_main_t main, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_execute_pid_with(const controller_rule_t rule, 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, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_pid_with_
 
 /**
@@ -550,8 +554,6 @@ extern "C" {
  * @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 action
  *   The action to perform based on the action type codes.
  *
@@ -568,6 +570,8 @@ extern "C" {
  *   If bit controller_rule_option_asynchronous, then run asynchronously.
  * @param main
  *   The main data.
+ * @param rule
+ *   The rule information at the time the rule process started.
  * @param process
  *   The process data for processing this rule.
  *
@@ -577,7 +581,7 @@ 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 uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
+  extern f_status_t controller_rule_process(const uint8_t action, const uint8_t options, const controller_main_t main, controller_rule_t rule, controller_process_t *process) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_process_
 
 /**
@@ -619,7 +623,7 @@ extern "C" {
  * @see f_thread_create()
  */
 #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;
+  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, const controller_cache_t cache) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_process_begin_
 
 /**
index 81675f3989923fb0adb3fb0fcc615ed2624de87a..652c7ecf8512cadd0dac7e8768c9cecd54b63532 100644 (file)
@@ -14,19 +14,18 @@ extern "C" {
 
     const controller_main_t *main = (controller_main_t *) arguments;
 
-    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;
+    const unsigned int interval = main->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cleanup_interval_short : controller_thread_cleanup_interval_long;
 
     while (main->thread->enabled) {
 
       sleep(interval);
 
-      if (f_thread_lock_write_try(&main->thread->lock.process) == F_none) {
+      if (main->thread->enabled && f_thread_lock_write_try(&main->thread->lock.process) == F_none) {
         controller_process_t *process = 0;
 
-        // index 0 is reserved for "main thread".
-        f_array_length_t i = 1;
+        f_array_length_t i = 0;
 
-        for (; j < main->thread->processs.used; ++i) {
+        for (; i < main->thread->processs.used && main->thread->enabled; ++i) {
 
           process = &main->thread->processs.array[i];
 
@@ -60,41 +59,43 @@ extern "C" {
           f_thread_unlock(&process->lock);
         } // for
 
-        for (i = main->thread->processs.used - 1; main->thread->processs.used; --i, --main->thread->processs.used) {
+        if (main->thread->processs.used) {
+          for (i = main->thread->processs.used - 1; main->thread->processs.used && main->thread->enabled; --i) {
 
-          process = &main->thread->processs.array[i];
+            process = &main->thread->processs.array[i];
 
-          if (f_thread_lock_write_try(&process->active) != F_none) {
-            break;
-          }
+            if (f_thread_lock_write_try(&process->active) != F_none) {
+              break;
+            }
 
-          if (f_thread_lock_write_try(&process->lock) != F_none) {
-            f_thread_unlock(&process->active);
+            if (f_thread_lock_write_try(&process->lock) != F_none) {
+              f_thread_unlock(&process->active);
 
-            break;
-          }
+              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 (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
+              f_thread_unlock(&process->active);
+              f_thread_unlock(&process->lock);
 
-            break;
-          }
+              break;
+            }
 
-          if (process->state == controller_process_state_done) {
-            f_thread_detach(process->id_thread);
-            process->state = controller_process_state_idle;
-          }
+            if (process->state == controller_process_state_done) {
+              f_thread_detach(process->id_thread);
+              process->state = controller_process_state_idle;
+            }
 
-          // 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);
+            // deallocate dynamic portions of the structure that are only ever needed while the rule is being processed.
+            controller_cache_delete_simple(&process->cache);
+            f_type_array_lengths_resize(0, &process->stack);
 
-          --main->thread->processs.used;
+            --main->thread->processs.used;
 
-          f_thread_unlock(&process->active);
-          f_thread_unlock(&process->lock);
-        } // for
+            f_thread_unlock(&process->active);
+            f_thread_unlock(&process->lock);
+          } // for
+        }
 
         f_thread_unlock(&main->thread->lock.process);
       }
@@ -141,13 +142,14 @@ extern "C" {
 
     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);
       }
     }
-
-    if (F_status_is_error_not(status)) {
+    else {
       if (data->parameters[controller_parameter_daemon].result == f_console_result_found) {
 
         setting->ready = controller_setting_ready_done;
@@ -170,17 +172,15 @@ extern "C" {
         }
       }
       else {
+        controller_cache_t cache = controller_cache_t_initialize;
 
-        // index 0 is reserved for running the main thread cache.
-        thread.processs.used = 1;
-
-        status = controller_entry_read(entry_name, main, &thread.processs.array[0].cache);
+        status = controller_entry_read(entry_name, main, &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(main, &thread.processs.array[0].cache);
+          status = controller_preprocess_entry(main, &cache);
         }
 
         if (F_status_is_error_not(status) && status != F_signal && status != F_child) {
@@ -204,7 +204,7 @@ extern "C" {
               status = F_status_set_error(F_available_not);
             }
             else {
-              status = controller_process_entry(main, &thread.processs.array[0].cache);
+              status = controller_process_entry(main, &cache);
 
               if (F_status_is_error(status)) {
                 setting->ready = controller_setting_ready_fail;
@@ -219,6 +219,8 @@ extern "C" {
           }
         }
 
+        controller_cache_delete_simple(&cache);
+
         if (status == F_child) {
           controller_thread_delete_simple(&thread);
 
@@ -227,7 +229,7 @@ extern "C" {
       }
     }
 
-    if (status != F_signal && setting->signal) {
+    if (status != F_signal && thread.signal) {
       status = F_signal;
     }
 
@@ -257,7 +259,6 @@ extern "C" {
       return F_child;
     }
 
-    // @todo consider f_thread_detach() over f_thread_join() when exiting.
     if (F_status_is_error_not(status) && status != F_signal && (data->parameters[controller_parameter_validate].result == f_console_result_none || data->parameters[controller_parameter_test].result == f_console_result_found)) {
 
       // wait until signal thread exits, which happens on any termination signal.
@@ -275,8 +276,8 @@ extern "C" {
     f_thread_cancel(thread.id_cleanup);
     f_thread_cancel(thread.id_control);
 
-    f_thread_detach(thread.id_cleanup);
-    f_thread_detach(thread.id_control);
+    f_thread_join(thread.id_cleanup, 0);
+    f_thread_join(thread.id_control, 0);
 
     controller_thread_delete_simple(&thread);
 
@@ -322,8 +323,7 @@ extern "C" {
     //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) {
+    for (f_array_length_t i = 0; i < main.thread->processs.used; ++i) {
 
       process = &main.thread->processs.array[i];
 
@@ -338,12 +338,9 @@ extern "C" {
           f_signal_send(F_signal_quit, process->child);
         }
 
-        if (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
+        if (process->state == controller_process_state_active || process->state == controller_process_state_busy || process->state == controller_process_state_done) {
           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_join(process->id_thread, 0);
         }
 
         f_thread_unlock(&process->lock);