]> Kevux Git Server - fll/commitdiff
Progress: controller program.
authorKevin Day <thekevinday@gmail.com>
Sun, 4 Apr 2021 16:10:35 +0000 (11:10 -0500)
committerKevin Day <thekevinday@gmail.com>
Sun, 4 Apr 2021 16:10:35 +0000 (11:10 -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/data/settings/example/rules/script/fail.rule

index f5f20ddcfa37d6412674f64f830bb484f7f8b5ed..b38b5390221d2c088ed1ae14d1eaf250ebb8e8ea 100644 (file)
@@ -112,26 +112,64 @@ extern "C" {
   }
 #endif // _di_controller_lock_create_
 
+#ifndef _di_controller_lock_delete_mutex_
+  void controller_lock_delete_mutex(f_thread_mutex_t *mutex) {
+
+    const f_status_t status = f_thread_mutex_delete(mutex);
+
+    if (F_status_is_error(status)) {
+      if (F_status_set_fine(status) == F_busy) {
+        f_thread_mutex_lock(mutex);
+        f_thread_mutex_unlock(mutex);
+
+        if (f_thread_mutex_delete(mutex) == F_none) {
+          mutex = 0;
+        }
+      }
+    }
+    else {
+      mutex = 0;
+    }
+  }
+#endif // _di_controller_lock_delete_mutex_
+
+#ifndef _di_controller_lock_delete_rw_
+  void controller_lock_delete_rw(f_thread_lock_t *lock) {
+
+    const f_status_t status = f_thread_lock_delete(lock);
+
+    if (F_status_is_error(status)) {
+      if (F_status_set_fine(status) == F_busy) {
+        f_thread_lock_write(lock);
+        f_thread_unlock(lock);
+
+        if (f_thread_lock_delete(lock) == F_none) {
+          lock = 0;
+        }
+      }
+    }
+    else {
+      lock = 0;
+    }
+  }
+#endif // _di_controller_lock_delete_rw_
+
 #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->process);
-    f_thread_lock_delete(&lock->rule);
+    controller_lock_delete_mutex(&lock->print);
+    controller_lock_delete_rw(&lock->process);
+    controller_lock_delete_rw(&lock->rule);
   }
 #endif // _di_controller_lock_delete_simple_
 
 #ifndef _di_controller_process_delete_simple_
   void controller_process_delete_simple(controller_process_t *process) {
 
-    f_thread_lock_delete(&process->lock);
-    f_thread_lock_delete(&process->active);
-
-    f_thread_mutex_lock(&process->wait_lock);
-    f_thread_condition_signal_all(&process->wait);
-    f_thread_mutex_unlock(&process->wait_lock);
-    f_thread_mutex_delete(&process->wait_lock);
+    controller_lock_delete_rw(&process->lock);
+    controller_lock_delete_rw(&process->active);
+    controller_lock_delete_mutex(&process->wait_lock);
+    f_thread_condition_delete(&process->wait);
 
     controller_cache_delete_simple(&process->cache);
     controller_rule_delete_simple(&process->rule);
@@ -179,7 +217,7 @@ extern "C" {
 
     status = f_memory_resize(processs->size, length, sizeof(controller_process_t), (void **) & processs->array);
 
-    if (F_status_is_error_not(status)) {
+    if (F_status_is_error_not(status) && length) {
 
       // the lock must be initialized, but only once, so initialize immediately upon allocation.
       for (; processs->size < length; ++processs->size) {
@@ -257,7 +295,9 @@ extern "C" {
     f_macro_int32s_t_delete_simple(rule->groups)
     f_macro_limit_sets_t_delete_simple(rule->limits)
 
-    f_capability_delete(&rule->capability);
+    if (rule->capability) {
+      f_capability_delete(&rule->capability);
+    }
 
     controller_rule_items_delete_simple(&rule->items);
   }
index 3082b4c5ed5650ba8c8861c142bc53bf926999cb..a90a8021af836d8de750d29683ab47276aa41f1c 100644 (file)
@@ -425,8 +425,8 @@ extern "C" {
     fl_execute_as_t_initialize \
   }
 
-  #define controller_macro_execute_set_t_initialize(option, environment, signals, data, as) { \
-    fl_macro_execute_parameter_t_initialize(option, environment, signals, data), \
+  #define controller_macro_execute_set_t_initialize(option, wait, environment, signals, data, as) { \
+    fl_macro_execute_parameter_t_initialize(option, wait, environment, signals, data), \
     as, \
   }
 #endif // _di_controller_execute_set_t_
@@ -588,6 +588,7 @@ extern "C" {
 /**
  * A Rule.
  *
+ * status:           The status of the rule as the result of processing/execution.
  * 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.
@@ -743,6 +744,9 @@ 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.
  *
+ * The "cache" should only be used by the function processing/executing the process and as such should not require a write lock on the "process".
+ * There should only be a single thread running any given Rule process at a time, guaranteeing the cache to not need read/write locks.
+ *
  * Process States:
  * - idle:   No process is running for this rule.
  * - busy:   A process is actively using this, and is running synchronously.
@@ -750,7 +754,7 @@ extern "C" {
  * - 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.
- * status:       The last execution status of the Rule.
+ * status:       The last execution status of the process.
  * state:        The state of the process.
  * action:       The action being performed.
  * options:      Configuration options for this asynchronous thread.
@@ -1067,7 +1071,8 @@ extern "C" {
   #define controller_thread_cleanup_interval_long  3600 // 1 hour in seconds.
   #define controller_thread_cleanup_interval_short 180  // 3 minutes in seconds.
   //#define controller_thread_exit_force_timeout 60  // 1 minute in seconds.
-  #define controller_thread_exit_force_timeout 5
+  #define controller_thread_exit_process_force_timeout 2000000 // 2 seconds in microseconds.
+  #define controller_thread_exit_main_force_timeout 100000 // 0.1 seconds in microseconds.
 
   typedef struct {
     bool enabled;
@@ -1271,6 +1276,28 @@ extern "C" {
 #endif // _di_controller_lock_create_
 
 /**
+ * Delete the mutex lock and if the mutex lock is busy, forcibly unlock it and then delete it.
+ *
+ * @param mutex
+ *   The mutex lock to delete.
+ *   Will be set to NULLif delete succeeded.
+ */
+#ifndef _di_controller_lock_delete_mutex_
+  extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_lock_delete_mutex_
+
+/**
+ * Delete the r/w lock and if the r/w lock is busy, forcibly unlock it and then delete it.
+ *
+ * @param lock
+ *   The r/w lock to delete.
+ *   Will be set to NULL if delete succeeded.
+ */
+#ifndef _di_controller_lock_delete_rw_
+  extern void controller_lock_delete_rw(f_thread_lock_t *lock) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_lock_delete_rw_
+
+/**
  * Fully deallocate all memory for the given lock without caring about return status.
  *
  * @param lock
index 02ef4f92dea4f0e2c00ff37b720fb1a7af928f44..7222dcabae2bfb1069398d1d7b368d61a944dfc4 100644 (file)
@@ -441,11 +441,7 @@ extern "C" {
 
       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 (main.thread->signal) {
-          return F_signal;
-        }
+      for (; cache->ats.array[at_j] < actions->used && main.thread->enabled; ++cache->ats.array[at_j]) {
 
         cache->action.line_action = actions->array[cache->ats.array[at_j]].line;
         cache->action.name_action.used = 0;
@@ -678,26 +674,23 @@ extern "C" {
     }
 
     if (simulate) {
-      f_thread_mutex_lock(&main.thread->lock.print);
+      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, "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]);
+        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, 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(&main.thread->lock.print);
+        f_thread_mutex_unlock(&main.thread->lock.print);
+      }
     }
 
     for (;;) {
 
       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 (main.thread->signal) {
-          status = F_signal;
-          break;
-        }
+      for (; cache->ats.array[at_j] < entry_actions->used && main.thread->enabled; ++cache->ats.array[at_j]) {
 
         entry_action = &entry_actions->array[cache->ats.array[at_j]];
 
@@ -713,26 +706,26 @@ extern "C" {
         }
 
         if (F_status_is_error(entry_action->status)) {
-
           if (entry_action->type == controller_entry_action_type_rule) {
-
             if (simulate) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+              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 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);
+                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(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);
-              }
+                if (entry_action->parameters.used) {
+                  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(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]);
+                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(&main.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
+              }
             }
             else if (entry_action->code & controller_entry_rule_code_require) {
 
@@ -786,22 +779,24 @@ extern "C" {
           }
           else {
             if (simulate) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+              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 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);
+                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(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);
-              }
+                if (entry_action->parameters.used) {
+                  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(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]);
+                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(&main.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
+              }
             }
             else if (main.data->warning.verbosity == f_console_verbosity_debug) {
               f_thread_mutex_lock(&main.thread->lock.print);
@@ -833,14 +828,16 @@ extern "C" {
           if (main.setting->ready == controller_setting_ready_wait) {
 
             if (simulate) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+              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, "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]);
+                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(&main.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
+              }
             }
             else {
               controller_perform_ready(main, cache);
@@ -851,14 +848,16 @@ extern "C" {
             main.setting->ready = controller_setting_ready_yes;
           }
           else if (simulate) {
-            f_thread_mutex_lock(&main.thread->lock.print);
+            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, "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]);
+              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(&main.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
+            }
           }
         }
         else if (entry_action->type == controller_entry_action_type_item) {
@@ -914,14 +913,16 @@ extern "C" {
           }
 
           if (simulate) {
-            f_thread_mutex_lock(&main.thread->lock.print);
+            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, "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]);
+              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(&main.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
+            }
           }
 
           // exit inner loop to force restarting and start processing the requested item.
@@ -957,14 +958,16 @@ extern "C" {
           f_thread_unlock(&main.thread->lock.rule);
 
           if (simulate) {
-            f_thread_mutex_lock(&main.thread->lock.print);
+            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, "%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]);
+              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(&main.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
+            }
           }
 
           // the rule is not yet loaded, ensure that it is loaded.
@@ -1096,7 +1099,7 @@ extern "C" {
 
             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) {
+            if (F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal) {
               break;
             }
           }
@@ -1116,18 +1119,20 @@ extern "C" {
               code = controller_string_stop_s;
             }
 
-            f_thread_mutex_lock(&main.thread->lock.print);
+            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, "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]);
+              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(&main.thread->lock.print);
+              f_thread_mutex_unlock(&main.thread->lock.print);
+            }
           }
 
           if (entry_action->code == controller_entry_timeout_code_kill) {
@@ -1165,22 +1170,24 @@ extern "C" {
             main.setting->failsafe_rule_id = entry_action->number;
 
             if (simulate) {
-              f_thread_mutex_lock(&main.thread->lock.print);
+              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, "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]);
+                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(&main.thread->lock.print);
+                f_thread_mutex_unlock(&main.thread->lock.print);
+              }
             }
           }
         }
       } // for
 
-      if (main.thread->signal || !main.thread->enabled) {
+      if (!main.thread->enabled) {
         status = F_signal;
       }
 
@@ -1236,8 +1243,8 @@ extern "C" {
   }
 #endif // _di_controller_process_entry_
 
-#ifndef _di_controller_status_simplify_
-  f_status_t controller_status_simplify(const f_status_t status) {
+#ifndef _di_controller_status_simplify_error_
+  f_status_t controller_status_simplify_error(const f_status_t status) {
 
     if (status == F_memory_not) {
       return F_status_set_error(F_memory);
@@ -1263,9 +1270,13 @@ extern "C" {
       return F_status_set_error(status);
     }
 
+    if (status == F_failure) {
+      return F_status_set_error(F_failure);
+    }
+
     return F_status_set_error(F_valid_not);
   }
-#endif // _di_controller_status_simplify_
+#endif // _di_controller_status_simplify_error_
 
 #ifndef _di_controller_validate_define_name_
   f_status_t controller_validate_environment_name(const f_string_static_t name) {
index fda8df9bae0e7cbfd6146c6e18ec11217d80bb00..8149c96b7978a8286c0d694eff0ae4b7539d10b6 100644 (file)
@@ -311,7 +311,7 @@ extern "C" {
 #endif // _di_controller_process_entry_
 
 /**
- * Given a wide range of status codes, simplify them down to a small subset.
+ * Given a wide range of status codes (that are errors), simplify them down to a small subset.
  *
  * @param status
  *   The status code (without the error bit set) to simplify.
@@ -319,9 +319,9 @@ extern "C" {
  * @return
  *   A subset of status codes with error bit.
  */
-#ifndef _di_controller_status_simplify_
-  extern f_status_t controller_status_simplify(const f_status_t status) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_status_simplify_
+#ifndef _di_controller_status_simplify_error_
+  extern f_status_t controller_status_simplify_error(const f_status_t status) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_status_simplify_error_
 
 /**
  * Validate that the given string is a valid environment variable name.
index 754c2376d9661b4ecda146107b85f22852b4e7ce..381611851ccce80b4519c9ec18cde7f5238f892f 100644 (file)
@@ -507,7 +507,7 @@ extern "C" {
                   action->status = F_status_set_error(F_number);
                 }
                 else {
-                  action->status = controller_status_simplify(F_status_set_fine(status));
+                  action->status = controller_status_simplify_error(F_status_set_fine(status));
                 }
 
                 if (F_status_set_fine(status) == F_memory_not) {
@@ -697,9 +697,9 @@ extern "C" {
         f_array_length_t i = 0;
         f_array_length_t j = 0;
 
-        for (; i < cache->object_items.used; ++i) {
+        for (; i < cache->object_items.used && main.thread->enabled; ++i) {
 
-          if (main.thread->signal) {
+          if (!main.thread->enabled) {
             return F_signal;
           }
 
@@ -850,7 +850,7 @@ extern "C" {
 
               for (j = 0; j < main.setting->entry.items.array[i].actions.used; ++j) {
 
-                if (main.thread->signal) {
+                if (!main.thread->enabled) {
                   return F_signal;
                 }
 
@@ -900,10 +900,10 @@ extern "C" {
                     }
 
                     action->number = 0;
-                    action->status = controller_status_simplify(F_found_not);
+                    action->status = controller_status_simplify_error(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);
+                    //main.setting->entry.status = controller_status_simplify_error(F_found_not);
 
                     cache->action.name_action.used = 0;
                     cache->action.name_item.used = 0;
@@ -928,7 +928,7 @@ extern "C" {
     if (F_status_is_error(status)) {
       controller_entry_error_print_cache(main.data->error, cache->action);
 
-      main.setting->entry.status = controller_status_simplify(F_status_set_fine(status));
+      main.setting->entry.status = controller_status_simplify_error(F_status_set_fine(status));
     }
     else {
       main.setting->entry.status = F_none;
index 1fb516c1c3a125873fa7496efc5341824a831024..c861d8c3c57cf58422f126dc5aefe3dc91c6ad96 100644 (file)
@@ -182,7 +182,7 @@ extern "C" {
  *   Errors (with error bit) from: controller_entry_actions_read().
  *   Errors (with error bit) from: controller_entry_items_increase_by().
  *   Errors (with error bit) from: controller_file_load().
- *   Errors (with error bit) from: controller_status_simplify().
+ *   Errors (with error bit) from: controller_status_simplify_error().
  *   Errors (with error bit) from: controller_string_dynamic_append_terminated().
  *   Errors (with error bit) from: controller_string_dynamic_partial_append_terminated().
  *   Errors (with error bit) from: f_fss_count_lines().
@@ -195,7 +195,7 @@ extern "C" {
  * @see controller_entry_actions_read()
  * @see controller_entry_items_increase_by()
  * @see controller_file_load()
- * @see controller_status_simplify()
+ * @see controller_status_simplify_error()
  * @see controller_string_dynamic_append_terminated()
  * @see controller_string_dynamic_partial_append_terminated()
  * @see f_fss_count_lines()
index 34437342d35c1fa4de3157ef2e93ebc2a3546b45..4a0e1b2287821dad5b6ad4c1b28f79063415b7a2 100644 (file)
@@ -315,13 +315,13 @@ extern "C" {
                 if (F_status_is_error(status)) {
                   controller_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamics_increase", F_true, main.thread);
 
-                  actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+                  actions->array[actions->used].status = controller_status_simplify_error(F_status_set_fine(status));
                   break;
                 }
 
                 status = controller_rule_parameters_read(main, cache->buffer_item, &cache->object_actions.array[i], &cache->content_actions.array[i], &actions->array[actions->used].parameters);
 
-                actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+                actions->array[actions->used].status = controller_status_simplify_error(F_status_set_fine(status));
                 actions->used++;
               } // for
 
@@ -402,7 +402,7 @@ extern "C" {
             if (F_status_is_error(status)) {
               controller_error_print(main.data->error, F_status_set_fine(status), "controller_rule_parameters_read", F_true, main.thread);
 
-              actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+              actions->array[actions->used].status = controller_status_simplify_error(F_status_set_fine(status));
             }
             else {
               actions->array[actions->used].status = status;
@@ -439,6 +439,12 @@ extern "C" {
 
     f_status_t status = F_none;
 
+    // delete the third party structures.
+    f_macro_control_group_t_delete_simple(destination->control_group)
+    f_capability_delete(&destination->capability);
+
+    destination->status = source.status;
+
     destination->timeout_kill = source.timeout_kill;
     destination->timeout_start = source.timeout_start;
     destination->timeout_stop = source.timeout_stop;
@@ -756,7 +762,7 @@ extern "C" {
 
     const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize;
 
-    controller_execute_set_t execute_set = controller_macro_execute_set_t_initialize(0, &environment, &signals, 0, fl_execute_as_t_initialize);
+    controller_execute_set_t execute_set = controller_macro_execute_set_t_initialize(0, 0, &environment, &signals, 0, fl_execute_as_t_initialize);
 
     // 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.
@@ -790,7 +796,6 @@ extern "C" {
         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);
 
-          process->status = F_status_set_error(F_failure);
           return status;
         }
       }
@@ -831,13 +836,12 @@ extern "C" {
     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);
 
-      process->status = F_status_set_error(F_failure);
       return status;
     }
 
     for (i = 0; i < process->rule.items.used; ++i) {
 
-      if (main.thread->signal) {
+      if (!main.thread->enabled) {
         status = F_signal;
         break;
       }
@@ -846,7 +850,7 @@ extern "C" {
 
       for (j = 0; j < process->rule.items.array[i].actions.used; ++j) {
 
-        if (main.thread->signal) {
+        if (!main.thread->enabled) {
           status = F_signal;
           break;
         }
@@ -874,9 +878,12 @@ extern "C" {
             process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
 
             if (!(options & controller_rule_option_simulate)) break;
-          }
 
-          success = F_true;
+            success = F_status_set_error(F_failure);
+          }
+          else if (success == F_false || success == F_ignore) {
+            success = F_true;
+          }
         }
         else if (process->rule.items.array[i].type == controller_rule_item_type_script) {
 
@@ -894,9 +901,12 @@ extern "C" {
             process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
 
             if (!(options & controller_rule_option_simulate)) break;
-          }
 
-          success = F_true;
+            success = F_status_set_error(F_failure);
+          }
+          else if (success == F_false || success == F_ignore) {
+            success = F_true;
+          }
         }
         else if (process->rule.items.array[i].type == controller_rule_item_type_service) {
 
@@ -912,9 +922,12 @@ extern "C" {
             process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
 
             if (!(options & controller_rule_option_simulate)) break;
-          }
 
-          success = F_true;
+            success = F_status_set_error(F_failure);
+          }
+          else if (success == F_false || success == F_ignore) {
+            success = F_true;
+          }
         }
         else {
 
@@ -929,9 +942,7 @@ extern "C" {
             f_thread_mutex_unlock(&main.thread->lock.print);
           }
 
-          process->rule.items.array[i].actions.array[j].status = F_ignore;
-
-          if (success != F_true) {
+          if (success == F_false) {
             success = F_ignore;
           }
 
@@ -951,16 +962,14 @@ extern "C" {
     }
 
     if (F_status_is_error(status) || success == F_false) {
-      process->status = F_status_set_error(F_failure);
+      return F_status_set_error(F_failure);
     }
-    else if (success == F_ignore || success == F_busy) {
-      process->status = success;
-    }
-    else {
-      process->status = F_none;
+
+    if (success == F_ignore) {
+      return F_ignore;
     }
 
-    return process->status;
+    return F_none;
   }
 #endif // _di_controller_rule_execute_
 
@@ -996,7 +1005,7 @@ extern "C" {
 
       const f_string_static_t simulated_program = f_macro_string_static_t_initialize(f_string_empty_s, 0);
       const f_string_statics_t simulated_arguments = f_string_statics_t_initialize;
-      fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
+      fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.wait, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
 
       status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, simulated_parameter.option & fl_execute_parameter_option_return ? (void *) &result : (void *) &id_process);
     }
@@ -1007,15 +1016,27 @@ extern "C" {
     if (status == F_parent) {
       result = 0;
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_write(&process->lock);
+
       // assign the child process id to allow for the cancel process to send appropriate termination signals to the child process.
       process->child = id_process;
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_read(&process->lock);
+
       // have the parent wait for the child process to finish.
-      waitpid(id_process, &result, WUNTRACED | WCONTINUED);
+      waitpid(id_process, &result, 0);
+
+      f_thread_unlock(&process->lock);
+      f_thread_lock_write(&process->lock);
 
       // remove the pid now that waidpid() has returned.
       process->child = 0;
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_read(&process->lock);
+
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
         status = F_status_set_error(F_failure);
@@ -1106,7 +1127,7 @@ extern "C" {
 
       const f_string_static_t simulated_program = f_macro_string_static_t_initialize(f_string_empty_s, 0);
       const f_string_statics_t simulated_arguments = f_string_statics_t_initialize;
-      fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
+      fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.wait, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
 
       status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, simulated_parameter.option & fl_execute_parameter_option_return ? (void *) &result : (void *) &id_process);
     }
@@ -1117,15 +1138,27 @@ extern "C" {
     if (status == F_parent) {
       result = 0;
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_write(&process->lock);
+
       // assign the child process id to allow for the cancel process to send appropriate termination signals to the child process.
       process->child = id_process;
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_read(&process->lock);
+
       // have the parent wait for the child process to finish.
-      waitpid(id_process, &result, WUNTRACED | WCONTINUED);
+      waitpid(id_process, &result, 0);
+
+      f_thread_unlock(&process->lock);
+      f_thread_lock_write(&process->lock);
 
       // remove the pid now that waidpid() has returned.
       process->child = 0;
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_read(&process->lock);
+
       // this must explicitly check for 0 (as opposed to checking (!result)).
       if (!WIFEXITED(result)) {
         status = F_status_set_error(F_failure);
@@ -1527,7 +1560,7 @@ extern "C" {
 #endif // _di_controller_rule_setting_limit_type_name_
 
 #ifndef _di_controller_rule_process_
-  f_status_t controller_rule_process(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 controller_main_t main, controller_process_t *process) {
 
     switch (action) {
       case controller_rule_action_type_freeze:
@@ -1605,8 +1638,8 @@ extern "C" {
       return status;
     }
 
-    if ((options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) {
-      controller_rule_simulate(process->rule, controller_rule_action_type_start, options, main, &process->cache);
+    if ((process->options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) {
+      controller_rule_simulate(process->rule, controller_rule_action_type_start, process->options, main, &process->cache);
     }
 
     f_array_length_t i = 0;
@@ -1616,6 +1649,7 @@ extern "C" {
       f_array_length_t k = 0;
       f_array_length_t id_rule = 0;
       f_array_length_t id_process = 0;
+      bool found = F_false;
 
       controller_process_t *process_other = 0;
 
@@ -1649,12 +1683,15 @@ extern "C" {
             status = controller_rule_find(dynamics[i]->array[j], main.setting->rules, &id_rule);
 
             f_thread_unlock(&main.thread->lock.rule);
+
+            found = F_true;
           }
 
           if (status != F_true) {
-            f_thread_lock_read(&main.thread->lock.rule);
+            found = F_false;
+            id_rule = 0;
 
-            id_rule = main.setting->rules.used;
+            f_thread_lock_read(&main.thread->lock.rule);
 
             if (i == 0) {
               f_thread_mutex_lock(&main.thread->lock.print);
@@ -1666,7 +1703,7 @@ extern "C" {
 
               status = F_status_set_error(F_found_not);
 
-              if (!(options & controller_rule_option_simulate)) {
+              if (!(process->options & controller_rule_option_simulate)) {
                 f_thread_unlock(&main.thread->lock.rule);
 
                 break;
@@ -1688,7 +1725,7 @@ extern "C" {
 
           f_thread_lock_read(&main.thread->lock.rule);
 
-          if (status == F_true && id_rule < main.setting->rules.used) {
+          if (status == F_true && found) {
             f_thread_unlock(&main.thread->lock.rule);
             f_thread_lock_read(&main.thread->lock.process);
 
@@ -1729,11 +1766,11 @@ extern "C" {
             f_thread_unlock(&main.thread->lock.rule);
 
             // attempt to (synchronously) execute the rule when the status is unknown (the rule has not yet been run).
-            if (process_other->status == F_known_not) {
+            if (main.setting->rules.array[id_rule].status == F_known_not) {
 
               const f_string_static_t alias_other = f_macro_string_static_t_initialize(alias_other_buffer, main.setting->rules.array[id_rule].alias.used);
 
-              status = controller_rule_process_begin(F_false, alias_other, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, process->stack, main, process->cache);
+              status = controller_rule_process_begin(F_false, alias_other, action, process->options & controller_rule_option_asynchronous ? process->options - controller_rule_option_asynchronous : process->options, process->stack, main, process->cache);
 
               if (status == F_child || status == F_signal) {
                 f_thread_unlock(&process_other->active);
@@ -1750,7 +1787,7 @@ extern "C" {
 
                   f_thread_mutex_unlock(&main.thread->lock.print);
 
-                  if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
+                  if (!(process->options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
                     f_thread_unlock(&process_other->active);
 
                     break;
@@ -1769,9 +1806,10 @@ extern "C" {
               }
             }
 
+            f_thread_lock_read(&main.thread->lock.rule);
             f_thread_unlock(&process_other->active);
 
-            if (F_status_is_error(process_other->status)) {
+            if (F_status_is_error(main.setting->rules.array[id_rule].status)) {
               if (i == 0 || i == 1) {
                 f_thread_mutex_lock(&main.thread->lock.print);
 
@@ -1782,7 +1820,7 @@ extern "C" {
 
                 f_thread_mutex_unlock(&main.thread->lock.print);
 
-                if (!(options & controller_rule_option_simulate)) {
+                if (!(process->options & controller_rule_option_simulate)) {
                   f_thread_unlock(&main.thread->lock.rule);
                   break;
                 }
@@ -1798,6 +1836,8 @@ extern "C" {
                 }
               }
             }
+
+            f_thread_unlock(&main.thread->lock.rule);
           }
           else {
             f_thread_unlock(&main.thread->lock.rule);
@@ -1806,7 +1846,7 @@ extern "C" {
 
         if (status == F_child || status == F_signal) break;
 
-        if (F_status_is_error(status) && !(options & controller_rule_option_simulate)) break;
+        if (F_status_is_error(status) && !(process->options & controller_rule_option_simulate)) break;
       } // for
     }
 
@@ -1818,7 +1858,7 @@ extern "C" {
       return F_signal;
     }
 
-    if (!(options & controller_rule_option_wait) && F_status_is_error_not(status)) {
+    if (!(process->options & controller_rule_option_wait) && F_status_is_error_not(status)) {
       controller_rule_wait_all(main, process);
 
       if (!main.thread->enabled) {
@@ -1826,10 +1866,10 @@ extern "C" {
       }
     }
 
-    if (!(options & controller_rule_option_validate) && F_status_is_error_not(status)) {
+    if (!(process->options & controller_rule_option_validate) && F_status_is_error_not(status)) {
 
       // find at least one of the requested action when the rule is required.
-      if (options & controller_rule_option_require) {
+      if (process->options & controller_rule_option_require) {
         bool missing = F_true;
 
         f_array_length_t j = 0;
@@ -1866,10 +1906,10 @@ extern "C" {
       }
 
       if (F_status_is_error_not(status)) {
-        status = controller_rule_execute(action, options, main, process);
+        status = controller_rule_execute(action, process->options, main, process);
 
-        if (status == F_child) {
-          return F_child;
+        if (status == F_child || status == F_signal) {
+          return status;
         }
 
         if (!main.thread->enabled) {
@@ -1882,11 +1922,36 @@ extern "C" {
       }
     }
 
+    f_array_length_t id_rule = 0;
+
+    f_thread_unlock(&process->lock);
+    f_thread_lock_write(&process->lock);
+
     if (F_status_is_error(status)) {
-      return status;
+      process->rule.status = controller_status_simplify_error(F_status_set_fine(status));
+    }
+    else {
+      process->rule.status = status;
     }
 
-    return F_none;
+    f_thread_lock_write(&main.thread->lock.rule);
+
+    status = controller_rule_find(process->rule.alias, main.setting->rules, &id_rule);
+
+    if (F_status_is_error(status)) {
+      controller_rule_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "controller_rule_find", F_true, F_true, main.thread);
+    }
+    else {
+      main.setting->rules.array[id_rule].status = process->rule.status;
+
+      // @fixme the rule item action status needs to be copied over from the local rule to the old one but there is no way to map the two (the structure could have changeed).
+    }
+
+    f_thread_unlock(&main.thread->lock.rule);
+    f_thread_unlock(&process->lock);
+    f_thread_lock_read(&process->lock);
+
+    return process->rule.status;
   }
 #endif // _di_controller_rule_process_
 
@@ -1898,21 +1963,19 @@ extern "C" {
     }
 
     f_status_t status = F_none;
-
     controller_process_t *process = 0;
 
+    f_thread_lock_read(&main.thread->lock.process);
+
     {
       f_array_length_t at = 0;
 
-      f_thread_lock_read(&main.thread->lock.process);
-
       if (controller_find_process(alias_rule, main.thread->processs, &at) != F_true) {
         status = F_status_set_error(F_found_not);
       }
 
-      f_thread_unlock(&main.thread->lock.process);
-
       if (F_status_is_error(status)) {
+        f_thread_unlock(&main.thread->lock.process);
 
         if (main.data->error.verbosity != f_console_verbosity_quiet) {
           f_thread_mutex_lock(&main.thread->lock.print);
@@ -1926,21 +1989,22 @@ extern "C" {
         return status;
       }
 
-      f_thread_lock_read(&main.thread->lock.process);
-      f_thread_lock_write(&main.thread->processs.array[at].lock);
-      f_thread_unlock(&main.thread->lock.process);
-
       process = &main.thread->processs.array[at];
 
+      f_thread_lock_read(&process->active);
+      f_thread_lock_write(&process->lock);
+
+      // once a write lock on the process is achieved, it is safe to unlock the main process read lock.
+      f_thread_unlock(&main.thread->lock.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);
+        f_thread_unlock(&process->active);
 
         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_cancel(process->id_thread);
@@ -1950,6 +2014,9 @@ extern "C" {
       process->id = at;
     }
 
+    f_thread_unlock(&process->lock);
+    f_thread_lock_write(&process->lock);
+
     process->state = controller_process_state_active;
     process->action = action;
     process->options = options;
@@ -1983,8 +2050,8 @@ extern "C" {
     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 (process->stack.size < stack.used) {
+        status = f_type_array_lengths_resize(stack.used, &process->stack);
       }
 
       if (F_status_is_error(status)) {
@@ -1992,8 +2059,10 @@ extern "C" {
       }
       else {
         for (f_array_length_t i = 0; i < stack.used; ++i) {
-          process->stack.array[process->stack.used++] = stack.array[i];
+          process->stack.array[i] = stack.array[i];
         } // for
+
+        process->stack.used = stack.used;
       }
     }
 
@@ -2041,14 +2110,14 @@ extern "C" {
   f_status_t controller_rule_process_do(const bool asynchronous, controller_process_t *process) {
 
     // the process lock shall be held for the duration of this processing (aside from switching between read to/from write).
-    f_thread_lock_read(&process->active);
-    f_thread_lock_write(&process->lock);
+    if (asynchronous) f_thread_lock_read(&process->active);
+    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);
 
     if (!main.thread->enabled) {
       f_thread_unlock(&process->lock);
-      f_thread_unlock(&process->active);
+      if (asynchronous) f_thread_unlock(&process->active);
 
       return F_signal;
     }
@@ -2057,13 +2126,22 @@ extern "C" {
     f_array_length_t id_rule = 0;
 
     const f_array_length_t used_original_stack = process->stack.used;
+    const bool simulate = main.data->parameters[controller_parameter_test].result == f_console_result_found;
 
     f_thread_lock_read(&main.thread->lock.rule);
 
     if (controller_rule_find(process->rule.alias, main.setting->rules, &id_rule) == F_true) {
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_write(&process->lock);
+
+      controller_rule_delete_simple(&process->rule);
+
       status = controller_rule_copy(main.setting->rules.array[id_rule], &process->rule);
 
+      f_thread_unlock(&process->lock);
+      f_thread_lock_read(&process->lock);
+
       f_thread_unlock(&main.thread->lock.rule);
 
       if (F_status_is_error(status)) {
@@ -2100,15 +2178,19 @@ extern "C" {
             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 {
+            f_thread_unlock(&process->lock);
+            f_thread_lock_write(&process->lock);
+
             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) && main.thread->enabled) {
-        const uint8_t rule_options = asynchronous ? controller_rule_option_asynchronous : 0;
-
-        status = controller_rule_process(controller_rule_action_type_start, rule_options, main, process);
+        status = controller_rule_process(controller_rule_action_type_start, main, process);
       }
     }
     else {
@@ -2126,6 +2208,17 @@ extern "C" {
       }
     }
 
+    f_thread_lock_write(&main.thread->lock.rule);
+
+    if (controller_rule_find(process->rule.alias, main.setting->rules, &id_rule) == F_true) {
+      main.setting->rules.array[id_rule].status = status;
+    }
+
+    f_thread_unlock(&main.thread->lock.rule);
+
+    f_thread_unlock(&process->lock);
+    f_thread_lock_write(&process->lock);
+
     if (asynchronous) {
       process->state = controller_process_state_done;
     }
@@ -2136,7 +2229,7 @@ extern "C" {
     process->stack.used = used_original_stack;
 
     f_thread_unlock(&process->lock);
-    f_thread_unlock(&process->active);
+    if (asynchronous) f_thread_unlock(&process->active);
 
     if (main.thread->enabled) {
 
@@ -2396,7 +2489,7 @@ extern "C" {
     if (F_status_is_error(status)) {
       controller_rule_item_error_print(main.data->error, cache->action, for_item, main.thread);
 
-      rule->status = controller_status_simplify(F_status_set_fine(status));
+      rule->status = controller_status_simplify_error(F_status_set_fine(status));
       return F_false;
     }
 
index 6077584ddf2db011ea5c5830095b231418fc7e60..5d8e467435c6ebc9f514f51950d5f1326d37f65f 100644 (file)
@@ -323,6 +323,8 @@ extern "C" {
 /**
  * Perform an execution of the given rule.
  *
+ * This requires that a read lock be set on process->lock before being called.
+ *
  * @param action
  *   The action to perform based on the action type codes.
  *
@@ -358,6 +360,8 @@ extern "C" {
 /**
  * Perform an execution of the given rule in the foreground.
  *
+ * This requires that a read lock be set on process->lock before being called.
+ *
  * @param type
  *   The item type code.
  * @param action
@@ -399,6 +403,8 @@ extern "C" {
 /**
  * Perform an execution of the given rule in the foreground or background and creating a PID file.
  *
+ * This requires that a read lock be set on process->lock before being called.
+ *
  * 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.
  *
@@ -553,9 +559,12 @@ extern "C" {
  * 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 requires that a read lock be set on process->lock before being called.
+ *
  * 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.
  *
+ * The rule status will be updated by this function.
+ *
  * @param action
  *   The action to perform based on the action type codes.
  *
@@ -565,11 +574,6 @@ extern "C" {
  *   - 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 main
  *   The main data.
  * @param process
@@ -581,7 +585,7 @@ extern "C" {
  *   F_signal on (exit) signal received.
  */
 #ifndef _di_controller_rule_process_
-  extern f_status_t controller_rule_process(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 controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_process_
 
 /**
index e38171f938293ed0e25bcb90d8454aec1469a41a..a862844c73686b6bbfa231eacc79f543fd72ed74 100644 (file)
@@ -14,6 +14,8 @@ extern "C" {
 
     const controller_main_t *main = (controller_main_t *) arguments;
 
+    if (!main->thread->enabled) f_thread_exit(0);
+
     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) {
@@ -48,8 +50,13 @@ extern "C" {
 
           if (process->id_thread) {
             f_thread_join(process->id_thread, 0);
+
+            f_thread_lock_write(&process->lock);
+
             process->state = controller_process_state_idle;
             process->id_thread = 0;
+
+            f_thread_unlock(&process->lock);
           }
 
           // deallocate dynamic portions of the structure that are only ever needed while the process is running.
@@ -84,8 +91,13 @@ extern "C" {
 
             if (process->id_thread) {
               f_thread_join(process->id_thread, 0);
+
+              f_thread_lock_write(&process->lock);
+
               process->state = controller_process_state_idle;
               process->id_thread = 0;
+
+              f_thread_unlock(&process->lock);
             }
 
             // deallocate dynamic portions of the structure that are only ever needed while the rule is being processed.
@@ -103,7 +115,7 @@ extern "C" {
       }
     } // while
 
-    return 0;
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_cleanup_
 
@@ -112,7 +124,9 @@ extern "C" {
 
     controller_main_t *main = (controller_main_t *) arguments;
 
-    return 0;
+    if (!main->thread->enabled) f_thread_exit(0);
+
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_control_
 
@@ -121,19 +135,33 @@ extern "C" {
 
     controller_main_t *main = (controller_main_t *) arguments;
 
-    sleep(controller_thread_exit_force_timeout);
+    f_thread_lock_read(&main->thread->lock.process);
 
-    for (f_array_length_t i = 0; i < main->thread->processs.used; ++i) {
+    // @todo redesign this to use timed waits, that include a counter and a max wait such that when max wait is reached, send kill signals.
+    //       this would, in theory, allow faster exits without as much waiting when there is nothing to wait for.
 
-      if (main->thread->processs.array[i].child > 0) {
-        f_signal_send(F_signal_kill, main->thread->processs.array[i].child);
-      }
+    if (main->thread->processs.used) {
+      f_thread_unlock(&main->thread->lock.process);
 
-      if (main->thread->processs.array[i].id_thread) {
-        f_thread_signal(main->thread->processs.array[i].id_thread, F_signal_kill);
-      }
-    } // for
+      usleep(controller_thread_exit_process_force_timeout);
 
+      f_thread_lock_read(&main->thread->lock.process);
+
+      for (f_array_length_t i = 0; i < main->thread->processs.used; ++i) {
+
+        if (main->thread->processs.array[i].child > 0) {
+          f_signal_send(F_signal_kill, main->thread->processs.array[i].child);
+        }
+
+        if (main->thread->processs.array[i].id_thread) {
+          f_thread_signal(main->thread->processs.array[i].id_thread, F_signal_kill);
+        }
+      } // for
+    }
+
+    f_thread_unlock(&main->thread->lock.process);
+
+    usleep(controller_thread_exit_main_force_timeout);
 
     if (main->thread->id_cleanup) {
       f_thread_signal(main->thread->id_cleanup, F_signal_kill);
@@ -143,15 +171,11 @@ extern "C" {
       f_thread_signal(main->thread->id_control, F_signal_kill);
     }
 
-    if (main->thread->id_signal) {
-      f_thread_signal(main->thread->id_signal, F_signal_kill);
-    }
-
     if (main->thread->id_rule) {
       f_thread_signal(main->thread->id_rule, F_signal_kill);
     }
 
-    return 0;
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_exit_force_
 
@@ -184,6 +208,8 @@ extern "C" {
     }
 
     if (F_status_is_error(status)) {
+      thread.id_signal = 0;
+
       if (data->error.verbosity != f_console_verbosity_quiet) {
         controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread);
       }
@@ -213,6 +239,7 @@ extern "C" {
       else {
         const controller_main_entry_t entry = controller_macro_main_entry_t_initialize(&entry_name, &main, setting);
 
+        // the entry processing runs using the rule thread.
         status = f_thread_create(0, &thread.id_rule, &controller_thread_entry, (void *) &entry);
 
         if (F_status_is_error(status)) {
@@ -223,6 +250,7 @@ extern "C" {
         else {
           f_thread_join(thread.id_rule, 0);
 
+          thread.id_rule = 0;
           status = thread.status;
         }
 
@@ -234,23 +262,32 @@ extern "C" {
       }
     }
 
-    if (status != F_signal && thread.signal) {
-      status = F_signal;
-    }
-
     // 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 (F_status_is_error_not(status) && status != F_signal && status != F_child && thread.enabled) {
+
+      if (data->parameters[controller_parameter_validate].result == f_console_result_none && thread.id_rule) {
+
+        // wait for the entry thread to complete before starting the rule thread.
+        f_thread_join(thread.id_rule, 0);
+
+        thread.id_rule = 0;
 
-      if (data->parameters[controller_parameter_validate].result == f_console_result_none) {
-        controller_rule_wait_all(main, 0);
+        if (thread.enabled) {
+          status = f_thread_create(0, &thread.id_rule, &controller_thread_rule, (void *) &main);
+        }
 
         status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &main);
 
-        if (F_status_is_error_not(status)) {
+        if (F_status_is_error(status)) {
+          thread.id_control = 0;
+        }
+        else {
           status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &main);
         }
 
         if (F_status_is_error(status)) {
+          thread.id_cleanup = 0;
+
           if (data->error.verbosity != f_console_verbosity_quiet) {
             controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread);
           }
@@ -265,24 +302,26 @@ extern "C" {
     }
 
     if (F_status_is_error(status) || status == F_signal || !(data->parameters[controller_parameter_validate].result == f_console_result_none || data->parameters[controller_parameter_test].result == f_console_result_found)) {
-      f_thread_cancel(thread.id_signal);
-      f_thread_create(0, &thread.id_exit, &controller_thread_exit_force, (void *) &main);
-    }
 
-    // wait until signal thread exits, which happens on any termination signal.
-    f_thread_join(thread.id_signal, 0);
+      if (status != F_signal && thread.id_signal) {
+        f_thread_cancel(thread.id_signal);
+      }
 
-    if (thread.enabled) {
       controller_thread_process_cancel(&main);
     }
 
-    f_thread_cancel(thread.id_cleanup);
-    f_thread_cancel(thread.id_control);
-    f_thread_cancel(thread.id_rule);
+    // wait until signal thread exits, which happens on any termination signal.
+    if (thread.id_signal) f_thread_join(thread.id_signal, 0);
 
-    f_thread_join(thread.id_cleanup, 0);
-    f_thread_join(thread.id_control, 0);
-    f_thread_join(thread.id_rule, 0);
+    controller_thread_process_cancel(&main);
+
+    if (thread.id_cleanup) f_thread_cancel(thread.id_cleanup);
+    if (thread.id_control) f_thread_cancel(thread.id_control);
+    if (thread.id_rule) f_thread_cancel(thread.id_rule);
+
+    if (thread.id_cleanup) f_thread_join(thread.id_cleanup, 0);
+    if (thread.id_control) f_thread_join(thread.id_control, 0);
+    if (thread.id_rule) f_thread_join(thread.id_rule, 0);
 
     // if made it here, then the threads no longer need to be killed.
     f_thread_join(thread.id_exit, 0);
@@ -310,23 +349,35 @@ extern "C" {
 #ifndef _di_controller_thread_process_
   void * controller_thread_process(void *arguments) {
 
-    controller_rule_process_do(F_true, (controller_process_t *) arguments);
+    controller_process_t *process = (controller_process_t *) arguments;
+
+    {
+      controller_thread_t *thread = (controller_thread_t *) process->main_thread;
+
+      if (!thread->enabled) f_thread_exit(0);
+    }
+
+    controller_rule_process_do(F_true, process);
 
-    return 0;
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_process_
 
 #ifndef _di_controller_thread_process_cancel_
   void controller_thread_process_cancel(controller_main_t *main) {
 
+    f_thread_lock_read(&main->thread->lock.process);
+
     // only cancel when enabled.
-    if (!main->thread->enabled) return;
+    if (!main->thread->enabled || main->thread->id_exit) {
+      f_thread_unlock(&main->thread->lock.process);
+
+      return;
+    }
 
     // this must be set, regardless of lock state and only this function changes this.
     main->thread->enabled = F_false;
 
-    f_thread_lock_read(&main->thread->lock.process);
-
     f_thread_create(0, &main->thread->id_exit, &controller_thread_exit_force, (void *) main);
 
     controller_process_t *process = 0;
@@ -337,27 +388,40 @@ extern "C" {
 
       process = &main->thread->processs.array[i];
 
+      f_thread_lock_read(&process->lock);
+
       if (process->child > 0) {
         f_signal_send(F_signal_termination, process->child);
       }
 
+      f_thread_unlock(&process->lock);
+    } // for
+
+    for (i = 0; i < main->thread->processs.used; ++i) {
+
+      process = &main->thread->processs.array[i];
+
+      f_thread_lock_read(&process->lock);
+
       if (process->id_thread) {
         f_thread_cancel(process->id_thread);
-        f_thread_join(process->id_thread, 0);
-
-        process->id_thread = 0;
       }
+
+      f_thread_unlock(&process->lock);
     } // for
 
-    for (; i < main->thread->processs.size; ++i) {
+    for (i = 0; i < main->thread->processs.size; ++i) {
 
       process = &main->thread->processs.array[i];
 
       if (process->id_thread) {
-        f_thread_cancel(process->id_thread);
         f_thread_join(process->id_thread, 0);
 
+        f_thread_lock_write(&process->lock);
+
         process->id_thread = 0;
+
+        f_thread_unlock(&process->lock);
       }
     } // for
 
@@ -374,6 +438,9 @@ extern "C" {
   void * controller_thread_entry(void *arguments) {
 
     controller_main_entry_t *entry = (controller_main_entry_t *) arguments;
+
+    if (!entry->main->thread->enabled) f_thread_exit(0);
+
     controller_data_t *data = entry->main->data;
     controller_cache_t *cache = &entry->main->thread->cache;
     f_status_t *status = &entry->main->thread->status;
@@ -423,7 +490,7 @@ extern "C" {
       }
     }
 
-    return 0;
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_entry_
 
@@ -432,7 +499,9 @@ extern "C" {
 
     controller_main_t *main = (controller_main_t *) arguments;
 
-    return 0;
+    if (!main->thread->enabled) f_thread_exit(0);
+
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_rule_
 
@@ -441,13 +510,15 @@ extern "C" {
 
     controller_main_t *main = (controller_main_t *) arguments;
 
+    if (!main->thread->enabled) f_thread_exit(0);
+
     for (int signal = 0; main->thread->enabled; ) {
 
       sigwait(&main->data->signal.set, &signal);
 
       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) {
-          main->thread->signal = signal;
+          main->thread->signal = signal; // @todo determine if I need signal saved anymore.
 
           controller_thread_process_cancel(main);
           break;
@@ -455,7 +526,7 @@ extern "C" {
       }
     } // for
 
-    return 0;
+    f_thread_exit(0);
   }
 #endif // _di_controller_thread_signal_
 
index bfc0f0b722fb3e49f90dfad4305fed89f93f35ab..059a7f7e923da980184fc68aecb36896cf699375 100644 (file)
@@ -8,7 +8,7 @@ script:
   start {
     \#!/bin/bash
     my_function() {
-      echo "Hello this is the second script."
+      echo "Hello this is the last script."
       return 1;
     \}