]> Kevux Git Server - controller/commitdiff
Progress: Continue changes to locking.
authorKevin Day <Kevin@kevux.org>
Mon, 3 Nov 2025 04:03:04 +0000 (22:03 -0600)
committerKevin Day <Kevin@kevux.org>
Mon, 3 Nov 2025 04:03:04 +0000 (22:03 -0600)
Change the rules array to be an array of pointers.
This better allows for locking and unlocking individual rules without having to hold locks on the rules array.
The rules array locks can now be shorter lived.

The stack itself needs to be an array of rule pointers now.
The index location is no longer needed or used.
This further allows for avouding needing locks on the rules array.

This refactoring is very much incomplete and controller probably does not work yet.

There are no locks available on individual rules yet.
This needs to happen!
I have added an explicit `@todo` in at least one location describing this.

Utilize the more granular error codes from the `f_thread_mutex_full_delete()` to handle the attibute delete even if the mutex delete itself fails.
I do not know how that should be handled.
There are still long term plans to make this program ever-running.
In such cases, all error states must be as recoverable as possible.
I doubt that I will get to this anytime soon.

25 files changed:
sources/c/program/controller/main/common/print.c
sources/c/program/controller/main/common/print.h
sources/c/program/controller/main/common/type/cache.c
sources/c/program/controller/main/common/type/cache.h
sources/c/program/controller/main/common/type/defs.h
sources/c/program/controller/main/common/type/instance.c
sources/c/program/controller/main/common/type/instance.h
sources/c/program/controller/main/common/type/lock.c
sources/c/program/controller/main/common/type/lock.h
sources/c/program/controller/main/common/type/process.c
sources/c/program/controller/main/common/type/rule.c
sources/c/program/controller/main/common/type/rule.h
sources/c/program/controller/main/controller.h
sources/c/program/controller/main/entry/process.c
sources/c/program/controller/main/file.c
sources/c/program/controller/main/instance.c
sources/c/program/controller/main/instance.h
sources/c/program/controller/main/lock.c
sources/c/program/controller/main/lock.h
sources/c/program/controller/main/rule.c
sources/c/program/controller/main/rule.h
sources/c/program/controller/main/rule/instance.c
sources/c/program/controller/main/rule/instance.h
sources/c/program/controller/main/rule/read.c
sources/c/program/controller/main/thread/cleanup.c

index 0c1ef4cf5c562e2bcbe98d0ec144811be57b1663..53d54a77115af76efb3f76f0ece535b5d905ae5c 100644 (file)
@@ -35,6 +35,7 @@ extern "C" {
     "f_memory_array_increase_by",
     "f_memory_array_resize",
     "f_memory_arrays_resize",
+    "f_memory_new",
     "f_path_current",
     "f_rip_dynamic_partial",
     "f_rip_dynamic_partial_nulless",
index 8931bdb6e8459943c7987abc5272bfc7d40d39d7..6efe2e435040a6eb6ed377f21d7dda028b7c610f 100644 (file)
@@ -68,6 +68,7 @@ extern "C" {
     controller_f_f_memory_array_increase_by_e,
     controller_f_f_memory_array_resize_e,
     controller_f_f_memory_arrays_resize_e,
+    controller_f_f_memory_new_e,
     controller_f_f_path_current_e,
     controller_f_f_rip_dynamic_partial_e,
     controller_f_f_rip_dynamic_partial_nulless_e,
index f478ce4462c064fb8456695b78ee9724079302f8..52826bdf1c3849d8c8c7b81af27c1872fbf0c8fc 100644 (file)
@@ -28,6 +28,8 @@ extern "C" {
     f_memory_arrays_resize(0, sizeof(f_ranges_t), (void **) &cache->content_actions.array, &cache->content_actions.used, &cache->content_actions.size, &f_rangess_delete_callback);
     f_memory_arrays_resize(0, sizeof(f_ranges_t), (void **) &cache->content_items.array, &cache->content_items.used, &cache->content_items.size, &f_rangess_delete_callback);
 
+    f_memory_array_resize(0, sizeof(controller_rule_t *), (void **) &cache->stack.array, &cache->stack.used, &cache->stack.size);
+
     controller_cache_action_delete(&cache->action);
   }
 #endif // _di_controller_cache_delete_
index 37f4f1f33892120ed23b7119546162acf637324c..20f0bde7e4a68283d1527403663994b793a4aea2 100644 (file)
@@ -61,17 +61,17 @@ extern "C" {
 /**
  * A cache intended for re-using memory while loading and processing rules whenever possible.
  *
+ * The stack rule pointers must not be directly freed.
+ * They will be de-allocated from the main rules array.
+ *
  * Properties:
  *   - timestamp: The timestamp.
  *
  *   - range_action: The Range for some Action.
- *
- *   - ats:   Locations.
- *   - stack: Locations within a items history used as a history stack for circular recursion prevention.
- *
- *   - close:   Close positions associated with a buffer string.
- *   - comments: Comments associated with a buffer string.
- *   - delimits: Delimits associated with a buffer string.
+ *   - close:        Close positions associated with a buffer string.
+ *   - comments:     Comments associated with a buffer string.
+ *   - ats:          Locations.
+ *   - delimits:     Delimits associated with a buffer string.
  *
  *   - content_action:  The specific Content for some Action.
  *   - content_actions: Content for some Action.
@@ -87,18 +87,16 @@ extern "C" {
  *   - expanded: An array of expanded strings, generally used by the execute functions.
  *
  *   - action: A cache for some Action, often used by error printing for reporting where an error happened.
+ *   - stack:  Locations within an items history used as a history stack for circular recursion prevention.
  */
 #ifndef _di_controller_cache_t_
-  typedef struct {
+  struct controller_cache_t_ {
     f_time_simple_t timestamp;
 
     f_range_t range_action;
-
-    f_number_unsigneds_t ats;
-    f_number_unsigneds_t stack;
-
     f_range_t close;
     f_ranges_t comments;
+    f_number_unsigneds_t ats;
     f_number_unsigneds_t delimits;
 
     f_ranges_t content_action;
@@ -115,17 +113,17 @@ extern "C" {
     f_string_dynamics_t expanded;
 
     controller_cache_action_t action;
-  } controller_cache_t;
+    controller_rules_t stack;
+  };
 
   #define controller_cache_t_initialize \
     { \
       f_time_simple_t_initialize, \
       f_range_t_initialize, \
-      f_number_unsigneds_t_initialize, \
-      f_number_unsigneds_t_initialize, \
       f_range_t_initialize, \
       f_ranges_t_initialize, \
       f_number_unsigneds_t_initialize, \
+      f_number_unsigneds_t_initialize, \
       f_ranges_t_initialize, \
       f_rangess_t_initialize, \
       f_rangess_t_initialize, \
@@ -137,6 +135,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamics_t_initialize, \
       controller_cache_action_t_initialize, \
+      controller_rules_t_initialize, \
     }
 #endif // _di_controller_cache_t_
 
index c5c083bd0274a42198805ec0009ef7884e5fdbdb..29bc7979c5c25031c62bd8eb2d3b269dba0e235d 100644 (file)
@@ -24,6 +24,13 @@ extern "C" {
 #endif // _di_fake_main_t_typedef_
 
 /**
+ * The controller cache typedef.
+ */
+ #ifndef _di_controller_cache_t_typedef_
+  typedef struct controller_cache_t_ controller_cache_t;
+#endif // _di_controller_cache_t_typedef_
+
+/**
  * The controller instance typedef.
  */
  #ifndef _di_controller_instance_t_typedef_
@@ -45,6 +52,20 @@ extern "C" {
 #endif // _di_controller_process_t_typedef_
 
 /**
+ * The controller rule typedef.
+ */
+ #ifndef _di_controller_rule_t_typedef_
+  typedef struct controller_rule_t_ controller_rule_t;
+#endif // _di_controller_rule_t_typedef_
+
+/**
+ * The controller rules typedef.
+ */
+ #ifndef _di_controller_rules_t_typedef_
+  typedef struct controller_rules_t_ controller_rules_t;
+#endif // _di_controller_rules_t_typedef_
+
+/**
  * The controller thread typedef.
  */
  #ifndef _di_controller_thread_t_typedef_
index c40c01a94cdc1628bdd901ed35c2bd13d1ca1bdd..bebfbdd582643d4ca82a8ddb1df8601213099b89 100644 (file)
@@ -19,41 +19,22 @@ extern "C" {
     f_thread_condition_delete(&instance->wait_condition);
     f_thread_lock_delete(&instance->use);
     f_thread_lock_delete(&instance->active);
-    f_thread_mutex_full_delete(&instance->wait);
+
+    if (F_status_set_fine(f_thread_mutex_full_delete(&instance->wait)) == F_mutex) {
+      f_thread_mutex_attribute_delete(&instance->wait.attribute);
+    }
 
     controller_cache_delete(&instance->cache);
     controller_rule_delete(&instance->rule);
 
     f_memory_array_resize(0, sizeof(pid_t), (void **) &instance->childs.array, &instance->childs.used, &instance->childs.size);
-    f_memory_array_resize(0, sizeof(f_number_unsigned_t), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
+    f_memory_array_resize(0, sizeof(controller_rule_t *), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
 
     f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &instance->path_pids.array, &instance->path_pids.used, &instance->path_pids.size, &f_string_dynamics_delete_callback);
     f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &instance->environment.array, &instance->environment.used, &instance->environment.size, &f_string_maps_delete_callback);
   }
 #endif // _di_controller_instance_delete_
 
-#ifndef _di_controller_instances_delete_callback_
-  f_status_t controller_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const void_array) {
-
-    {
-      controller_instance_t ** const instances = (controller_instance_t **) void_array;
-
-      for (f_number_unsigned_t i = start; i < stop; ++i) {
-
-        if (instances[i]) {
-          controller_instance_delete(instances[i]);
-
-          f_memory_delete(1, sizeof(controller_instance_t), (void **) &instances[i]);
-
-          instances[i] = 0;
-        }
-      } // for
-    }
-
-    return F_okay;
-  }
-#endif // _di_controller_instances_delete_callback_
-
 #ifndef _di_controller_instance_initialize_
   f_status_t controller_instance_initialize(controller_instance_t ** restrict const instance) {
 
@@ -86,6 +67,28 @@ extern "C" {
   }
 #endif // _di_controller_instance_initialize_
 
+#ifndef _di_controller_instances_delete_callback_
+  f_status_t controller_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const void_array) {
+
+    {
+      controller_instance_t ** const instances = (controller_instance_t **) void_array;
+
+      for (f_number_unsigned_t i = start; i < stop; ++i) {
+
+        if (instances[i]) {
+          controller_instance_delete(instances[i]);
+
+          f_memory_delete(1, sizeof(controller_instance_t), (void **) &instances[i]);
+
+          instances[i] = 0;
+        }
+      } // for
+    }
+
+    return F_okay;
+  }
+#endif // _di_controller_instances_delete_callback_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 27ec9b8e4a99bbacef8132537d9cdc5a40a6bda9..762aba6b7684c836c16f40cfc37729ca77f14872 100644 (file)
@@ -30,6 +30,9 @@ extern "C" {
  * This can be used to check if anything is asynchronously operating the rule and designates that something is actively using the instance.
  * A write lock on "active" should be used to prevent activation.
  *
+ * The stack rule pointers must not be directly freed.
+ * They will be de-allocated from the main rules array.
+ *
  * Properties:
  *   - thread: The thread ID, a valid ID when state is "active", and an invalid ID when the state is "busy".
  *
@@ -47,9 +50,9 @@ extern "C" {
  *   - child:       The process id of a child process, if one is running (when forking to execute a child process).
  *   - path_pids:   An array of paths representing PID files.
  *   - environment: Environment data used when executing the instance (should not need locking to read or write to).
- *   - stack:       A stack used to represent dependencies as Rule ID's to avoid circular Rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
  *
  *   - rule:  A copy of the Rule actively being executed (should not need locking to read or write to).
+ *   - stack: A stack used to represent rule dependencies to avoid circular Rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
  *   - cache: The cache used by this Instance (should not need locking to read or write to).
  *   - main:  The main program data.
  */
@@ -71,9 +74,9 @@ extern "C" {
     f_pids_t childs;
     f_string_dynamics_t path_pids;
     f_string_maps_t environment;
-    f_number_unsigneds_t stack;
 
     controller_rule_t rule;
+    controller_rules_t stack;
     controller_cache_t cache;
     controller_t *main;
   };
@@ -92,8 +95,8 @@ extern "C" {
     f_pids_t_initialize, \
     f_string_dynamics_t_initialize, \
     f_string_maps_t_initialize, \
-    f_number_unsigneds_t_initialize, \
     controller_rule_t_initialize, \
+    controller_rules_t_initialize, \
     controller_cache_t_initialize, \
     0, \
   }
@@ -141,33 +144,6 @@ extern "C" {
 #endif // _di_controller_instance_delete_
 
 /**
- * A callback intended to be passed to f_memory_arrays_resize() for an f_instances_t structure.
- *
- * This is only called when shrinking the array and generally should perform de-allocations.
- *
- * This does not do parameter checking.
- *
- * @param start
- *   The inclusive start position in the array to start deleting.
- * @param stop
- *   The exclusive stop position in the array to stop deleting.
- * @param array
- *   The array structure to delete all values of.
- *
- *   Must not be NULL.
- *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
- *
- * @see controller_instance_delete()
- */
-#ifndef _di_controller_instances_delete_callback_
-  extern f_status_t controller_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const array);
-#endif // _di_controller_instances_delete_callback_
-
-/**
  * Perform initialization that must be performed exactly once for each Instance.
  *
  * This performs the initial lock allocation as well as other such defaults.
@@ -194,6 +170,33 @@ extern "C" {
   extern f_status_t controller_instance_initialize(controller_instance_t ** restrict const instance);
 #endif // _di_controller_instance_initialize_
 
+/**
+ * A callback intended to be passed to f_memory_arrays_resize() for an f_instances_t structure.
+ *
+ * This is only called when shrinking the array and generally should perform de-allocations.
+ *
+ * This does not do parameter checking.
+ *
+ * @param start
+ *   The inclusive start position in the array to start deleting.
+ * @param stop
+ *   The exclusive stop position in the array to stop deleting.
+ * @param array
+ *   The array structure to delete all values of.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_instance_delete()
+ */
+#ifndef _di_controller_instances_delete_callback_
+  extern f_status_t controller_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const array);
+#endif // _di_controller_instances_delete_callback_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c11cf0c68a123d3d164dfba9f9ea8e99fa543c15..efb6962350a7a16b25f4124898ac3ab558111213 100644 (file)
@@ -9,11 +9,25 @@ extern "C" {
 
     if (!lock || (lock->flag & controller_lock_flag_setup_not_d)) return;
 
-    f_thread_mutex_full_delete(&lock->alert);
-    f_thread_mutex_full_delete(&lock->cancel);
-    f_thread_mutex_full_delete(&lock->entry);
-    f_thread_mutex_full_delete(&lock->print);
-    f_thread_mutex_full_delete(&lock->reap);
+    if (F_status_set_fine(f_thread_mutex_full_delete(&lock->alert)) == F_mutex) {
+      f_thread_mutex_attribute_delete(&lock->alert.attribute);
+    }
+
+    if (F_status_set_fine(f_thread_mutex_full_delete(&lock->cancel)) == F_mutex) {
+      f_thread_mutex_attribute_delete(&lock->cancel.attribute);
+    }
+
+    if (F_status_set_fine(f_thread_mutex_full_delete(&lock->entry)) == F_mutex) {
+      f_thread_mutex_attribute_delete(&lock->entry.attribute);
+    }
+
+    if (F_status_set_fine(f_thread_mutex_full_delete(&lock->print)) == F_mutex) {
+      f_thread_mutex_attribute_delete(&lock->print.attribute);
+    }
+
+    if (F_status_set_fine(f_thread_mutex_full_delete(&lock->reap)) == F_mutex) {
+      f_thread_mutex_attribute_delete(&lock->reap.attribute);
+    }
 
     f_thread_lock_delete(&lock->enable);
     f_thread_lock_delete(&lock->instance);
index d4f81d16411d488b2779d9ff860f37fb8985e719..ed8e2e951ec24501da75ebacd4ccaa988875c43d 100644 (file)
@@ -88,6 +88,7 @@ extern "C" {
  * @see f_thread_condition_delete()
  * @see f_thread_lock_delete()
  * @see f_thread_mutex_full_delete()
+ * @see f_thread_mutex_attribute_delete()
  */
 #ifndef _di_controller_lock_delete_
   extern void controller_lock_delete(controller_lock_t * const lock);
index 8e0eefea961fb722de1edcfd3f89ff802ef02615..56a3abba5415df6a8da867ad84e2769996d251a8 100644 (file)
@@ -20,11 +20,11 @@ extern "C" {
     f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->entry.parameter.array, &process->entry.parameter.used, &process->entry.parameter.size, &f_string_maps_delete_callback);
     f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->exit.define.array, &process->exit.define.used, &process->exit.define.size, &f_string_maps_delete_callback);
     f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->exit.parameter.array, &process->exit.parameter.used, &process->exit.parameter.size, &f_string_maps_delete_callback);
+    f_memory_arrays_resize(0, sizeof(controller_instance_t), (void **) &process->rules.array, &process->rules.used, &process->rules.size, &controller_rules_delete_callback);
 
     controller_control_delete(&process->control);
     controller_entry_items_delete(&process->entry.items);
     controller_entry_items_delete(&process->exit.items);
-    controller_rules_delete(&process->rules);
   }
 #endif // _di_controller_process_delete_
 
index 2f3bf6565def8d1acc55041888cfee606d28bd98..b213606fc7bb7728998d43f38c3ec1e4443c3b31 100644 (file)
@@ -60,6 +60,18 @@ extern "C" {
   }
 #endif // _di_controller_rule_actions_delete_callback_
 
+#ifndef _di_controller_rule_initialize_
+  f_status_t controller_rule_initialize(controller_rule_t ** restrict const rule) {
+
+    if (!rule) return F_status_set_error(F_parameter);
+    if (*rule) return F_okay;
+
+    f_status_t status = f_memory_new(1, sizeof(controller_rule_t), (void **) rule);
+
+    return F_status_is_error(status) ? status : F_okay;
+  }
+#endif // _di_controller_rule_initialize_
+
 #ifndef _di_controller_rule_item_delete_
   void controller_rule_item_delete(controller_rule_item_t * const item) {
 
@@ -111,20 +123,27 @@ extern "C" {
   }
 #endif // _di_controller_rule_ons_delete_callback_
 
-#ifndef _di_controller_rules_delete_
-  void controller_rules_delete(controller_rules_t * const rules) {
+#ifndef _di_controller_rules_delete_callback_
+  f_status_t controller_rules_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const void_array) {
+
+    {
+      controller_rule_t ** const rules = (controller_rule_t **) void_array;
+
+      for (f_number_unsigned_t i = start; i < stop; ++i) {
 
-    if (!rules) return;
+        if (rules[i]) {
+          controller_rule_delete(rules[i]);
 
-    rules->used = rules->size;
+          f_memory_delete(1, sizeof(controller_rule_t), (void **) &rules[i]);
 
-    while (rules->used) {
-      controller_rule_delete(&rules->array[--rules->used]);
-    } // while
+          rules[i] = 0;
+        }
+      } // for
+    }
 
-    f_memory_array_resize(0, sizeof(controller_rule_t), (void **) &rules->array, &rules->used, &rules->size);
+    return F_okay;
   }
-#endif // _di_controller_rules_delete_
+#endif // _di_controller_rules_delete_callback_
 
 #ifdef __cplusplus
 } // extern "C"
index daa948986ec8a05923b363fb85dcb570591e92fa..42041527180d669936bf75a110ef9d5b3371c342 100644 (file)
@@ -271,7 +271,7 @@ extern "C" {
  *   - user:             The User ID if the Rule "has" a user.
  */
 #ifndef _di_controller_rule_t_
-  typedef struct {
+  struct controller_rule_t_ {
     f_status_t status[controller_rule_action_type__enum_size_e];
 
     f_number_unsigned_t timeout_kill;
@@ -305,7 +305,7 @@ extern "C" {
 
     controller_rule_ons_t ons;
     controller_rule_items_t items;
-  } controller_rule_t;
+  };
 
   #define controller_rule_t_initialize { \
       { \
@@ -355,18 +355,20 @@ extern "C" {
 /**
  * Controller Rules.
  *
+ * Rules in this array are pointers and must each be individually allocated.
+ *
  * Properties:
- *   - array: An array of Rules.
+ *   - array: An array of Rules pointers (note the double-pointer).
  *   - size:  Total amount of allocated space.
  *   - used:  Total number of allocated spaces used.
  */
 #ifndef _di_controller_rules_t_
-  typedef struct {
-    controller_rule_t *array;
+  struct controller_rules_t_ {
+    controller_rule_t **array;
 
     f_number_unsigned_t size;
     f_number_unsigned_t used;
-  } controller_rules_t;
+  };
 
   #define controller_rules_t_initialize { \
     0, \
@@ -430,6 +432,33 @@ extern "C" {
 #endif // _di_controller_rule_actions_delete_callback_
 
 /**
+ * Perform initialization that must be performed exactly once for each Instance.
+ *
+ * This performs the initial lock allocation as well as other such defaults.
+ *
+ * @param rule
+ *   The Instance to initialize.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   F_parameter (with error bit) on invalid parameter.
+ *
+ *   Errors (with error bit) from: f_thread_condition_create().
+ *   Errors (with error bit) from: f_thread_lock_create().
+ *   Errors (with error bit) from: f_thread_mutex_create().
+ *
+ * @see f_thread_condition_create()
+ * @see f_thread_lock_create()
+ * @see f_thread_mutex_create()
+ */
+#ifndef _di_controller_rule_initialize_
+  extern f_status_t controller_rule_initialize(controller_rule_t ** restrict const rule);
+#endif // _di_controller_rule_initialize_
+
+/**
  * Delete the Controller Rule Item data.
  *
  * @param item
@@ -509,16 +538,31 @@ extern "C" {
 #endif // _di_controller_rule_ons_delete_callback_
 
 /**
- * Delete the Controller Rules data.
+ * A callback intended to be passed to f_memory_arrays_resize() for an f_rules_t structure.
  *
- * @param rules
- *   The Controller Rules data.
+ * This is only called when shrinking the array and generally should perform de-allocations.
+ *
+ * This does not do parameter checking.
+ *
+ * @param start
+ *   The inclusive start position in the array to start deleting.
+ * @param stop
+ *   The exclusive stop position in the array to stop deleting.
+ * @param array
+ *   The array structure to delete all values of.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
  *
- * @see controller_rules_resize()
+ * @see controller_rule_delete()
  */
-#ifndef _di_controller_rules_delete_
-  extern void controller_rules_delete(controller_rules_t * const rules);
-#endif // _di_controller_rules_delete_
+#ifndef _di_controller_rules_delete_callback_
+  extern f_status_t controller_rules_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const array);
+#endif // _di_controller_rules_delete_callback_
 
 #ifdef __cplusplus
 } // extern "C"
index 2743f67abddd6918112054477f54c51fb1bb1e2e..2e3556778333873d59d121aea2a12b6df6a28841 100644 (file)
 #include <program/controller/main/common/enumeration/rule.h>
 #include <program/controller/main/common/enumeration/process.h>
 #include <program/controller/main/common/enumeration/thread.h>
-#include <program/controller/main/common/type/cache.h>
+#include <program/controller/main/common/type/defs.h>
 #include <program/controller/main/common/type/control.h>
 #include <program/controller/main/common/type/entry.h>
 #include <program/controller/main/common/type/execute.h>
 #include <program/controller/main/common/type/lock.h>
 #include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/defs.h>
+#include <program/controller/main/common/type/cache.h> // Must be after rule.h.
 #include <program/controller/main/common/type/process.h>
 #include <program/controller/main/common/type/instance.h>
 #include <program/controller/main/common/type/thread.h>
index 05e67f1cd5e66fc3c791cf8f83e4fda22b339693..55b7cc5cae48d47e588b5aa758d9b0a0cab9ae39 100644 (file)
@@ -22,7 +22,7 @@ extern "C" {
     controller_entry_actions_t *entry_actions = 0;
 
     // An empty stack is used here because each Rule here is the first Rule run in the Rule's scope.
-    const f_number_unsigneds_t stack = f_number_unsigneds_t_initialize;
+    const controller_rules_t stack = controller_rules_t_initialize;
 
     cache->ats.used = 0;
     cache->stack.used = 0;
@@ -187,24 +187,6 @@ extern "C" {
           break;
         }
         else if (entry_action->type == controller_entry_action_type_consider_e || controller_entry_action_type_is_rule(entry_action->type)) {
-          status_lock = controller_lock_write_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.rule);
-
-          if (status_lock != F_okay) {
-            controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false);
-
-            break;
-          }
-
-          status = f_memory_array_increase(controller_allocation_small_d, sizeof(controller_rule_t), (void **) &main->process.rules.array, &main->process.rules.used, &main->process.rules.size);
-
-          f_thread_unlock(&main->thread.lock.rule);
-
-          if (F_status_is_error(status)) {
-            controller_print_error_entry(&main->program.error, is_entry, F_status_set_fine(status), macro_controller_f(f_memory_array_increase), F_true);
-
-            return status;
-          }
-
           const f_number_unsigned_t id_rule_length = entry_action->parameters.array[0].used + entry_action->parameters.array[1].used + 1;
           f_char_t id_rule_name[id_rule_length + 1];
           const f_string_static_t alias_rule = macro_f_string_static_t_initialize_1(id_rule_name, 0, id_rule_length);
@@ -215,18 +197,16 @@ extern "C" {
           id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s.string[0];
           id_rule_name[id_rule_length] = 0;
 
-          status_lock = controller_lock_read_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.rule);
+          status = controller_rule_find(main, is_entry, alias_rule, main->process.rules, 0);
 
-          if (status_lock != F_okay) {
-            controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true);
+          if (F_status_is_error(status)) {
+
+            // Set the lock status because controller_rule_find() generally only errors out on locking error (might need to translate the status codes to guarantee this).
+            status_lock = status;
 
             break;
           }
 
-          status = controller_rule_find(alias_rule, main->process.rules, 0);
-
-          f_thread_unlock(&main->thread.lock.rule);
-
           if ((main->setting.flag & controller_main_flag_simulate_d) || main->program.error.verbosity == f_console_verbosity_verbose_e || main->program.error.verbosity == f_console_verbosity_debug_e || (entry->show == controller_entry_show_init_e && entry_action->type != controller_entry_action_type_consider_e)) {
             controller_print_message_entry_item_rule(&main->program.message, entry, entry_action, is_entry, alias_rule);
           }
@@ -236,6 +216,16 @@ extern "C" {
           // The Rule is not yet loaded, ensure that it is loaded.
           if (status != F_true) {
 
+            controller_rule_t *rule = 0;
+
+            status = f_memory_new(1, sizeof(controller_rule_t), (void **) &rule);
+
+            if (F_status_is_error(status)) {
+              controller_print_error_entry(&main->program.error, is_entry, F_status_set_fine(status), macro_controller_f(f_memory_new), F_true);
+
+              return status;
+            }
+
             // Rule execution will re-use the existing cache, so save the current cache.
             const f_number_unsigned_t cache_line_action = cache->action.line_action;
             const f_number_unsigned_t cache_line_item = cache->action.line_item;
@@ -252,11 +242,7 @@ extern "C" {
             memcpy(cache_name_item, cache->action.name_item.string, sizeof(f_char_t) * cache->action.name_item.used);
             memcpy(cache_name_file, cache->action.name_file.string, sizeof(f_char_t) * cache->action.name_file.used);
 
-            status_lock = controller_lock_write_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.rule);
-
-            if (status_lock == F_okay) {
-              status = controller_rule_read(main, cache, is_entry, alias_rule, entry, &main->process.rules.array[main->process.rules.used]);
-            }
+            status = controller_rule_read(main, cache, is_entry, alias_rule, entry, rule);
 
             // Restore cache.
             memcpy(cache->action.name_action.string, cache_name_action, sizeof(f_char_t) * cache_name_action_used);
@@ -274,19 +260,7 @@ extern "C" {
             cache->action.line_action = cache_line_action;
             cache->action.line_item = cache_line_item;
 
-            if (status_lock != F_okay) {
-              if (F_status_set_fine(status_lock) != F_interrupt) {
-                controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false);
-              }
-
-              break;
-            }
-
-            if (F_status_set_fine(status) == F_interrupt || !controller_thread_enable_is_normal(&main->thread, is_entry)) {
-              f_thread_unlock(&main->thread.lock.rule);
-
-              break;
-            }
+            if (F_status_set_fine(status) == F_interrupt || !controller_thread_enable_is_normal(&main->thread, is_entry)) break;
 
             if (F_status_is_error(status)) {
               if (main->program.error.verbosity > f_console_verbosity_quiet_e) {
@@ -301,6 +275,10 @@ extern "C" {
               entry_action->status = controller_status_simplify_error(F_failure);
 
               if (!(main->setting.flag & controller_main_flag_simulate_d)) {
+                if (rule) {
+                  f_memory_delete(1, sizeof(controller_rule_t), (void **) &rule);
+                }
+
                 f_thread_unlock(&main->thread.lock.rule);
 
                 if (entry_action->code & controller_entry_rule_code_require_d) return F_status_set_error(F_require);
@@ -311,10 +289,36 @@ extern "C" {
               }
             }
             else {
-              ++main->process.rules.used;
-            }
+              status_lock = controller_lock_write_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.rule);
+
+              if (status_lock != F_okay) {
+                if (rule) {
+                  f_memory_delete(1, sizeof(controller_rule_t), (void **) &rule);
+                }
 
-            f_thread_unlock(&main->thread.lock.rule);
+                controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false);
+
+                break;
+              }
+
+              status = f_memory_array_increase(controller_allocation_small_d, sizeof(controller_rule_t), (void **) &main->process.rules.array, &main->process.rules.used, &main->process.rules.size);
+
+              if (F_status_is_error(status)) {
+                if (rule) {
+                  f_memory_delete(1, sizeof(controller_rule_t), (void **) &rule);
+                }
+
+                f_thread_unlock(&main->thread.lock.rule);
+
+                controller_print_error_entry(&main->program.error, is_entry, F_status_set_fine(status), macro_controller_f(f_memory_array_increase), F_true);
+
+                return status;
+              }
+
+              main->process.rules.array[main->process.rules.used++] = rule;
+
+              f_thread_unlock(&main->thread.lock.rule);
+            }
           }
 
           if (F_status_is_error_not(status)) {
index f7ed3a66b1665b89fbadfab148e56d158231ccb6..52f13aa2a26378ade099bce94bd632296bbb13cb 100644 (file)
@@ -102,6 +102,8 @@ extern "C" {
     if (F_status_is_error_not(status)) {
       struct stat stat_file;
 
+      memset(&stat_file, 0, sizeof(struct stat));
+
       status = f_file_stat(path, F_true, &stat_file);
 
       if (F_status_is_error(status)) {
index afb80dce6e0707113d140cd437ca970f7317c1a7..905692d4a5ec65aa56711db40ef81f845a2c75e0 100644 (file)
@@ -13,7 +13,7 @@ extern "C" {
     for (f_number_unsigned_t i = 0; i < instances.used; ++i) {
 
       if (instances.array[i] && instances.array[i]->action == action && f_compare_dynamic(alias, instances.array[i]->rule.alias) == F_equal_to) {
-        *instance = instances.array[i];
+        if (instance) *instance = instances.array[i];
 
         return F_true;
       }
index 1e0e00ddaaf616350e6110f75bd065d1f85d6bd5..3ea0a6ba2d73b88fe039ea6870ab533773c20b56 100644 (file)
@@ -28,9 +28,7 @@ extern "C" {
  * @param instances
  *   The array of instancees to.
  * @param instance
- *   The found instance.
- *
- *   Must not be NULL.
+ *   (optional) The found instance.
  *
  * @return
  *   F_okay if not given a valid id to search.
index e1a79cb80af451df9467327f16a6df9ddb9bbe1b..5a82f94f53041f996b956500d94cb36a9ea6b2c3 100644 (file)
@@ -67,27 +67,37 @@ extern "C" {
             }
 
             if (F_status_is_error(status)) {
-              f_thread_mutex_full_delete(&lock->reap);
+              if (F_status_set_fine(f_thread_mutex_full_delete(&lock->reap)) == F_mutex) {
+                f_thread_mutex_attribute_delete(&lock->reap.attribute);
+              }
             }
           }
 
           if (F_status_is_error(status)) {
-            f_thread_mutex_full_delete(&lock->print);
+            if (F_status_set_fine(f_thread_mutex_full_delete(&lock->print)) == F_mutex) {
+              f_thread_mutex_attribute_delete(&lock->print.attribute);
+            }
           }
         }
 
         if (F_status_is_error(status)) {
-          f_thread_mutex_full_delete(&lock->entry);
+          if (F_status_set_fine(f_thread_mutex_full_delete(&lock->entry)) == F_mutex) {
+            f_thread_mutex_attribute_delete(&lock->entry.attribute);
+          }
         }
       }
 
       if (F_status_is_error(status)) {
-        f_thread_mutex_full_delete(&lock->cancel);
+        if (F_status_set_fine(f_thread_mutex_full_delete(&lock->cancel)) == F_mutex) {
+          f_thread_mutex_attribute_delete(&lock->cancel.attribute);
+        }
       }
     }
 
     if (F_status_is_error(status)) {
-      f_thread_mutex_full_delete(&lock->alert);
+      if (F_status_set_fine(f_thread_mutex_full_delete(&lock->alert)) == F_mutex) {
+        f_thread_mutex_attribute_delete(&lock->alert.attribute);
+      }
 
       return status;
     }
index 0f5927398c605a36c244252164d0b52b5026007e..a95de1bcd939c04022d33b8bd0151d69aa2cdd54 100644 (file)
@@ -35,6 +35,8 @@ extern "C" {
  *
  * @see f_thread_lock_delete()
  * @see f_thread_mutex_full_delete()
+ * @see f_thread_mutex_attribute_delete()
+ *
  * @see controller_mutex_full_create()
  */
 #ifndef _di_controller_lock_create_
index 1f02bb593093602398f17e2118ae86c482dd4a3e..c02743bcfa78986e063069abef7fc19a8db7ebb7 100644 (file)
@@ -227,22 +227,36 @@ extern "C" {
 #endif // _di_controller_rule_copy_
 
 #ifndef _di_controller_rule_find_
-  f_status_t controller_rule_find(const f_string_static_t alias, const controller_rules_t rules, f_number_unsigned_t * const at) {
+  f_status_t controller_rule_find(controller_t * const main, const uint8_t is_entry, const f_string_static_t alias, const controller_rules_t rules, controller_rule_t ** const rule) {
 
-    if (!at) return F_status_set_error(F_parameter);
+    if (!main) return F_status_set_error(F_parameter);
     if (!alias.used) return F_okay;
     if (!rules.used) return F_false;
 
+    f_status_t status = controller_lock_read_standard(is_entry, controller_lock_check_flag_yes_d, &main->thread, &main->thread.lock.rule);
+
+    if (F_status_is_error(status)) {
+      controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status), F_true);
+
+      return status;
+    }
+
+    status = F_false;
+
     for (f_number_unsigned_t i = 0; i < rules.used; ++i) {
 
-      if (f_compare_dynamic(alias, rules.array[i].alias) == F_equal_to) {
-        if (at) *at = i;
+      if (f_compare_dynamic(alias, rules.array[i]->alias) == F_equal_to) {
+        if (rule) *rule = rules.array[i];
+
+        status = F_true;
 
-        return F_true;
+        break;
       }
     } // for
 
-    return F_false;
+    f_thread_unlock(&main->thread.lock.rule);
+
+    return status;
   }
 #endif // _di_controller_rule_find_
 
index e47d124b5b7e3662e1d9231b26d83efef0ae6af7..531cfa0920889ac03bc892cd2c98efb1cfd7845d 100644 (file)
@@ -56,22 +56,36 @@ extern "C" {
 /**
  * Find the location of the Rule by the Rule alias.
  *
+ * The main.thread.lock.rule lock must neither have a read nor a write lock.
+ * This will set and release the main.thread.lock.rule read lock.
+ *
+ * This calls controller_print_error_lock_critical() on locking error.
+ *
+ * @param main
+ *   The main program data.
+ *
+ *   Must not be NULL.
+ * @param is_entry
+ *   If TRUE, then this operates as an Entry.
+ *   If FALSE, then this operates as an Exit.
  * @param alias
  *   The Rule alias to find.
  * @param rules
  *   The rules to search through.
- * @param at
- *   (optional) The index the Rule was found at.
- *
- *   Set to NULL to disable.
+ * @param rule
+ *   (optional) The found rule.
  *
  * @return
  *   F_okay on success, but the id.used is 0.
  *   F_true on success and Rule was found, index is updated.
  *   F_false on success and Rule was not found.
+ *
+ *   Errors (with error bit) from: controller_lock_read_standard().
+ *
+ * @see controller_lock_read_standard()
  */
 #ifndef _di_controller_rule_find_
-  extern f_status_t controller_rule_find(const f_string_static_t alias, const controller_rules_t rules, f_number_unsigned_t * const at);
+  extern f_status_t controller_rule_find(controller_t * const main, const uint8_t is_entry, const f_string_static_t alias, const controller_rules_t rules, controller_rule_t ** const rule);
 #endif // _di_controller_rule_find_
 
 /**
index 2358a70af3d7f356328dd77ebb8fb1768089ad0a..31e4b419776773f7648ec3877abe25b6b7c6ed83 100644 (file)
@@ -90,16 +90,16 @@ extern "C" {
     }
 
     f_number_unsigned_t i = 0;
+    f_number_unsigned_t j = 0;
 
-    {
-      f_number_unsigned_t j = 0;
-      f_number_unsigned_t id_rule = 0;
-
-      controller_instance_t *dependency = 0;
+    controller_rule_t *rule = 0;
 
+    {
       uint8_t found = F_false;
       uint8_t options_instance = 0;
 
+      controller_instance_t *dependency = 0;
+
       const f_string_static_t strings[3] = {
         controller_rule_needed_s,
         controller_rule_wanted_s,
@@ -154,23 +154,16 @@ extern "C" {
             dependency = 0;
           }
           else {
-            status_lock = controller_lock_read_instance(instance, &main->thread.lock.rule);
-
-            if (F_status_is_error(status_lock)) {
-              controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true);
+            status = controller_rule_find(main, instance->type != controller_instance_type_exit_e, dynamics[i]->array[j], main->process.rules, &rule);
 
+            if (F_status_is_error(status) && F_status_set_fine(status) != F_interrupt) {
               status = F_false;
             }
-            else {
-              status = controller_rule_find(dynamics[i]->array[j], main->process.rules, &id_rule);
-
-              f_thread_unlock(&main->thread.lock.rule);
-            }
           }
 
           if (status != F_true) {
             found = F_false;
-            id_rule = 0;
+            rule = 0;
 
             if (i) {
               controller_print_debug_rule_instance_need_want_wish(&main->program.warning, instance, strings[i], dynamics[i]->array[j], "is not found");
@@ -189,31 +182,19 @@ extern "C" {
               }
             }
           }
-          else if (found) {
-            status_lock = controller_lock_read_instance(instance, &main->thread.lock.rule);
-
-            if (F_status_is_error(status_lock)) {
-              controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true);
-
-              found = F_false;
-              status = status_lock;
-            }
-          }
 
           if (found) {
 
             // The dependency may have write locks, which needs to be avoided, so copy the alias from the Rule.
             f_string_static_t alias_other_buffer = f_string_static_t_initialize;
-            alias_other_buffer.used = main->process.rules.array[id_rule].alias.used;
+            alias_other_buffer.used = rule->alias.used;
 
             f_char_t alias_other_buffer_string[alias_other_buffer.used + 1];
             alias_other_buffer.string = alias_other_buffer_string;
 
-            memcpy(alias_other_buffer_string, main->process.rules.array[id_rule].alias.string, sizeof(f_char_t) * alias_other_buffer.used);
+            memcpy(alias_other_buffer_string, rule->alias.string, sizeof(f_char_t) * alias_other_buffer.used);
             alias_other_buffer_string[alias_other_buffer.used] = 0;
 
-            f_thread_unlock(&main->thread.lock.rule);
-
             status_lock = controller_lock_read_instance(instance, &dependency->use);
 
             if (F_status_is_error(status_lock)) {
@@ -244,16 +225,7 @@ extern "C" {
             else {
               f_thread_unlock(&dependency->use);
 
-              status_lock = controller_lock_read_instance(instance, &main->thread.lock.rule);
-
-              if (F_status_is_error(status_lock)) {
-                controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true);
-
-                status = status_lock;
-              }
-              else if (controller_rule_status_is_available(instance->action, main->process.rules.array[id_rule])) {
-                f_thread_unlock(&main->thread.lock.rule);
-
+              if (controller_rule_status_is_available(instance->action, *rule)) {
                 options_instance = 0;
 
                 if (main->setting.flag & controller_main_flag_simulate_d) {
@@ -289,9 +261,7 @@ extern "C" {
                 }
               }
               else {
-                status = main->process.rules.array[id_rule].status[instance->action];
-
-                f_thread_unlock(&main->thread.lock.rule);
+                status = rule->status[instance->action];
               }
             }
 
@@ -301,14 +271,6 @@ extern "C" {
               break;
             }
 
-            if (F_status_is_error_not(status_lock)) {
-              status_lock = controller_lock_read_instance(instance, &main->thread.lock.rule);
-
-              if (F_status_is_error(status_lock)) {
-                controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false);
-              }
-            }
-
             if (F_status_is_error(status_lock)) {
               status = status_lock;
 
@@ -316,9 +278,7 @@ extern "C" {
                 controller_print_error_rule_instance_need_want_wish(&main->program.error, instance, strings[i], alias_other_buffer, "due to lock failure");
               }
             }
-            else if (controller_rule_status_is_error(instance->action, main->process.rules.array[id_rule])) {
-              f_thread_unlock(&main->thread.lock.rule);
-
+            else if (controller_rule_status_is_error(instance->action, *rule)) {
               if (i == 0 || i == 1) {
                 status = F_status_set_error(F_found_not);
 
@@ -334,9 +294,6 @@ extern "C" {
                 controller_print_debug_rule_instance_need_want_wish(&main->program.warning, instance, strings[i], alias_other_buffer, "is in a failed state");
               }
             }
-            else {
-              f_thread_unlock(&main->thread.lock.rule);
-            }
           }
 
           if (dependency) {
@@ -362,7 +319,6 @@ extern "C" {
       // Find at least one of the requested Action when the Rule is required.
       if (instance->options & controller_instance_option_require_d) {
         uint8_t missing = F_true;
-        f_number_unsigned_t j = 0;
 
         for (i = 0; i < instance->rule.items.used; ++i) {
 
@@ -394,8 +350,6 @@ extern "C" {
       }
     }
 
-    f_number_unsigned_t id_rule = 0;
-
     status_lock = controller_lock_write_instance(instance, &instance->use);
 
     if (F_status_is_error(status_lock)) {
@@ -411,42 +365,59 @@ extern "C" {
       instance->rule.status[instance->action] = status;
     }
 
-    status_lock = controller_lock_write_instance(instance, &main->thread.lock.rule);
-
-    if (F_status_is_error(status_lock)) {
-      f_thread_unlock(&instance->use);
-
-      controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_false);
+    f_thread_unlock(&instance->use);
 
-      return F_status_set_error(status_lock);
-    }
+    rule = 0;
 
     // Update the Rule status, which is stored separately from the Rule status for this instance.
-    if (controller_rule_find(instance->rule.alias, main->process.rules, &id_rule) == F_true) {
-      controller_rule_t * const rule = &main->process.rules.array[id_rule];
+    status = controller_rule_find(main, instance->type != controller_instance_type_exit_e, instance->rule.alias, main->process.rules, &rule);
+    if (F_status_is_error(status)) return status;
 
+    if (status == F_true) {
       rule->status[instance->action] = instance->rule.status[instance->action];
 
-      f_number_unsigned_t j = 0;
-
       // Copy all Rule Item Action statuses from the Rule instance to the Rule.
       for (i = 0; i < rule->items.used; ++i) {
 
         for (j = 0; j < rule->items.array[i].actions.used; ++j) {
+
+          status_lock = controller_lock_read_instance(instance, &instance->use);
+
+          if (F_status_is_error(status_lock)) {
+            f_thread_unlock(&instance->use);
+
+            controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true);
+
+            return F_status_set_error(status_lock);
+          }
+
           rule->items.array[i].actions.array[j].status = instance->rule.items.array[i].actions.array[j].status;
+
+          f_thread_unlock(&instance->use);
         } // for
       } // for
     }
 
-    f_thread_unlock(&main->thread.lock.rule);
+    status_lock = controller_lock_read_instance(instance, &instance->use);
+
+    if (F_status_is_error(status_lock)) {
+      f_thread_unlock(&instance->use);
+
+      controller_print_error_lock_critical(&main->program.error, F_status_set_fine(status_lock), F_true);
+
+      return F_status_set_error(status_lock);
+    }
+
+    status = instance->rule.status[instance->action];
+
     f_thread_unlock(&instance->use);
 
-    return instance->rule.status[instance->action];
+    return status;
   }
 #endif // _di_controller_rule_instance_
 
 #ifndef _di_controller_rule_instance_begin_
-  f_status_t controller_rule_instance_begin(controller_t * const main, controller_cache_t * const cache, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_number_unsigneds_t stack) {
+  f_status_t controller_rule_instance_begin(controller_t * const main, controller_cache_t * const cache, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const controller_rules_t stack) {
 
     if (!main || !cache) return F_status_set_error(F_parameter);
     if (!controller_thread_is_enabled_instance_type(&main->thread, type)) return F_status_set_error(F_interrupt);
@@ -537,7 +508,7 @@ extern "C" {
 
     if (F_status_is_error_not(status) && stack.used) {
       if (instance->stack.size < stack.used) {
-        status = f_memory_array_resize(stack.used, sizeof(f_number_unsigned_t), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
+        status = f_memory_array_resize(stack.used, sizeof(controller_rule_t *), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
       }
 
       if (F_status_is_error(status)) {
@@ -647,197 +618,197 @@ extern "C" {
 
     if (!instance || !instance->main) return F_status_set_error(F_parameter);
 
-    {
-      f_status_t status_lock = F_okay;
+    f_status_t status = F_okay;
 
-      if (options_force & controller_instance_option_asynchronous_d) {
-        status_lock = controller_lock_read_instance(instance, &instance->active);
+    if (options_force & controller_instance_option_asynchronous_d) {
+      status = controller_lock_read_instance(instance, &instance->active);
 
-        if (F_status_is_error(status_lock)) {
-          controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_true);
+      if (F_status_is_error(status)) {
+        controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), F_true);
 
-          return status_lock;
-        }
+        return status;
       }
     }
 
-    uint8_t flag = 0x0;
-
-    const f_status_t status = controller_rule_instance_perform_details(instance, options_force, &flag);
-
-    if (flag & 0x4) {
-      f_thread_unlock(&instance->main->thread.lock.rule);
-    }
+    status = controller_rule_instance_perform_details(instance, options_force);
 
     if (options_force & controller_instance_option_asynchronous_d) {
       f_thread_unlock(&instance->active);
     }
 
-    if (flag & 0x1) {
-      controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), !(flag & 0x2));
-    }
-
     return status;
   }
 #endif // _di_controller_rule_instance_perform_
 
 #ifndef _di_controller_rule_instance_perform_details_
-  f_status_t controller_rule_instance_perform_details(controller_instance_t * const instance, const uint8_t options_force, uint8_t * const flag) {
+  f_status_t controller_rule_instance_perform_details(controller_instance_t * const instance, const uint8_t options_force) {
 
     if (!instance || !instance->main) return F_status_set_error(F_parameter);
 
-    f_status_t status_lock = controller_lock_read_instance(instance, &instance->use);
+    f_status_t status = controller_lock_read_instance(instance, &instance->use);
 
-    if (F_status_is_error(status_lock)) {
-      *flag |= 0x1;
+    if (F_status_is_error(status)) {
+      controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), F_true);
 
-      return status_lock;
+      return status;
     }
 
-    f_status_t status = F_okay;
-    f_number_unsigned_t id_rule = 0;
-
     const f_number_unsigned_t used_original_stack = instance->stack.used;
 
     f_thread_unlock(&instance->use);
 
-    status_lock = controller_lock_read_instance(instance, &instance->main->thread.lock.rule);
-    if (F_status_is_error(status_lock)) return status_lock;
+    controller_rule_t *rule = 0;
 
-    *flag |= 0x4;
+    status = controller_rule_find(instance->main, instance->type != controller_instance_type_exit_e, instance->rule.alias, instance->main->process.rules, &rule);
+    if (F_status_is_error(status)) return status;
 
-    if (controller_rule_find(instance->rule.alias, instance->main->process.rules, &id_rule) == F_true) {
-      status_lock = controller_lock_write_instance(instance, &instance->use);
+    if (status == F_true) {
+      status = controller_rule_instance_perform_details_copy(instance, *rule, &instance->rule);
 
-      if (F_status_is_error(status_lock)) {
-        *flag |= 0x3;
-
-        return status_lock;
-      }
-
-      controller_rule_delete(&instance->rule);
+      if (F_status_is_error_not(status)) {
 
-      status = controller_rule_copy(instance->main->process.rules.array[id_rule], &instance->rule);
+        // This is a "consider" Action, so do not actually execute the Rule.
+        if (!instance->action) {
+          return F_process_not;
+        }
 
-      f_thread_unlock(&instance->use);
-      f_thread_unlock(&instance->main->thread.lock.rule);
+        status = controller_rule_instance_perform_details_stack_verify(instance, rule);
 
-      *flag &= ~0x4;
+        if (!controller_thread_is_enabled_instance(instance)) return F_status_set_error(F_interrupt);
 
-      if (F_status_is_error(status)) {
-        controller_print_error_status(&instance->main->program.error, macro_controller_f(controller_rule_copy), F_status_set_fine(status));
-      }
-      else if (!instance->action) {
+        if (F_status_is_error_not(status)) {
+          status = controller_rule_instance_perform_details_stack_rule_append(instance, rule);
 
-        // This is a "consider" Action, so do not actually execute the Rule.
-        return F_process_not;
+          if (F_status_is_error_not(status)) {
+            status = controller_rule_instance(instance);
+          }
+        }
       }
-      else {
-        status_lock = controller_lock_read_instance(instance, &instance->use);
+    }
+    else {
+      status = F_status_set_error(F_found_not);
 
-        if (F_status_is_error(status_lock)) {
-          *flag |= 0x1;
+      controller_print_error_rule_item_rule_not_loaded(&instance->main->program.error, &instance->cache.action, instance->rule.alias);
+    }
 
-          return status_lock;
-        }
+    if (status == F_child) return status;
 
-        for (f_number_unsigned_t i = 0; i < instance->stack.used && controller_thread_is_enabled_instance(instance); ++i) {
+    if (F_status_set_fine(status) == F_lock) {
+      rule->status[instance->action] = status; // @todo Probably should establish r/w use locks on rule; add appropriate locks to rule structure and handle appropriately.
+    }
 
-          if (instance->stack.array[i] == id_rule) {
+    // @todo Why are F_lock and related being converted into F_interrupt?
+    if (F_status_set_fine(status) == F_interrupt || (F_status_set_fine(status) == F_lock || F_status_set_fine(status) == F_lock_read || F_status_set_fine(status) == F_lock_write) && !controller_thread_is_enabled_instance(instance)) {
+      return F_status_set_error(F_interrupt);
+    }
 
-            // Never continue on circular recursion errors even in simulate mode.
-            status = F_status_set_error(F_recurse);
+    {
+      const f_status_t status_lock = controller_lock_write_instance(instance, &instance->use);
 
-            controller_print_error_rule_stack_already(&instance->main->program.error, &instance->cache.action, instance->rule.alias, F_true);
+      if (F_status_is_error(status_lock)) {
+        controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status_lock), F_false);
 
-            break;
-          }
-        } // for
+        return status_lock;
+      }
+    }
 
-        f_thread_unlock(&instance->use);
+    instance->state = (options_force & controller_instance_option_asynchronous_d) ? controller_instance_state_done_e : controller_instance_state_idle_e;
+    instance->stack.used = used_original_stack;
 
-        if (!controller_thread_is_enabled_instance(instance)) return F_status_set_error(F_interrupt);
+    f_thread_unlock(&instance->use);
 
-        if (F_status_is_error_not(status)) {
-          status_lock = controller_lock_write_instance(instance, &instance->use);
+    f_thread_condition_signal_all(&instance->wait_condition);
 
-          if (F_status_is_error(status_lock)) {
-            *flag |= 0x3;
+    return controller_thread_is_enabled_instance(instance) ? status : F_status_set_error(F_interrupt);
+  }
+#endif // _di_controller_rule_instance_perform_details_
 
-            return status_lock;
-          }
+#ifndef _di_controller_rule_instance_perform_details_copy_
+  f_status_t controller_rule_instance_perform_details_copy(controller_instance_t * const instance, const controller_rule_t source, controller_rule_t * const destination) {
 
-          status = f_memory_array_increase(controller_allocation_small_d, sizeof(f_number_unsigned_t), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
+    if (!instance || !instance->main) return F_status_set_error(F_parameter);
 
-          if (F_status_is_error(status)) {
-            controller_print_error_status(&instance->main->program.error, macro_controller_f(f_memory_array_increase), F_status_set_fine(status));
-          }
-          else {
-            instance->stack.array[instance->stack.used++] = id_rule;
-          }
+    f_status_t status = controller_lock_write_instance(instance, &instance->use);
 
-          f_thread_unlock(&instance->use);
-        }
-      }
+    if (F_status_is_error(status)) {
+      controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), F_false);
 
-      if (F_status_is_error_not(status)) {
-        status = controller_rule_instance(instance);
-      }
+      return status;
     }
-    else {
-      status = F_status_set_error(F_found_not);
 
-      controller_print_error_rule_item_rule_not_loaded(&instance->main->program.error, &instance->cache.action, instance->rule.alias);
+    controller_rule_delete(destination);
 
-      f_thread_unlock(&instance->main->thread.lock.rule);
+    status = controller_rule_copy(source, destination);
 
-      *flag &= ~0x4;
+    if (F_status_is_error(status)) {
+      controller_print_error_status(&instance->main->program.error, macro_controller_f(controller_rule_copy), F_status_set_fine(status));
     }
 
-    if (status == F_child) return status;
+    f_thread_unlock(&instance->use);
 
-    status_lock = controller_lock_write_instance(instance, &instance->main->thread.lock.rule);
+    return status;
+  }
+#endif // _di_controller_rule_instance_perform_details_copy_
 
-    if (F_status_is_error(status_lock)) {
-      *flag |= 0x3;
+#ifndef _di_controller_rule_instance_perform_details_stack_rule_append_
+  f_status_t controller_rule_instance_perform_details_stack_rule_append(controller_instance_t * const instance, controller_rule_t * const rule) {
 
-      return status_lock;
+    if (!instance || !instance->main || !rule) return F_status_set_error(F_parameter);
+
+    f_status_t status = controller_lock_write_instance(instance, &instance->use);
+
+    if (F_status_is_error(status)) {
+      controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), F_false);
+
+      return status;
     }
 
-    *flag |= 0x4;
+    status = f_memory_array_increase(controller_allocation_small_d, sizeof(controller_rule_t *), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
 
-    if (F_status_set_fine(status) == F_lock) {
-      if (controller_rule_find(instance->rule.alias, instance->main->process.rules, &id_rule) == F_true) {
-        instance->main->process.rules.array[id_rule].status[instance->action] = status;
-      }
+    if (F_status_is_error(status)) {
+      controller_print_error_status(&instance->main->program.error, macro_controller_f(f_memory_array_increase), F_status_set_fine(status));
+    }
+    else {
+      instance->stack.array[instance->stack.used++] = rule;
     }
 
-    f_thread_unlock(&instance->main->thread.lock.rule);
+    f_thread_unlock(&instance->use);
 
-    *flag &= ~0x4;
+    return status;
+  }
+#endif // _di_controller_rule_instance_perform_details_stack_rule_append_
 
-    if (F_status_set_fine(status) == F_interrupt || (F_status_set_fine(status) == F_lock || F_status_set_fine(status) == F_lock_read || F_status_set_fine(status) == F_lock_write) && !controller_thread_is_enabled_instance(instance)) {
-      return F_status_set_error(F_interrupt);
-    }
+#ifndef _di_controller_rule_instance_perform_details_stack_verify_
+  f_status_t controller_rule_instance_perform_details_stack_verify(controller_instance_t * const instance, controller_rule_t * const rule) {
 
-    status_lock = controller_lock_write_instance(instance, &instance->use);
+    if (!instance || !instance->main || !rule) return F_status_set_error(F_parameter);
 
-    if (F_status_is_error(status_lock)) {
-      *flag |= 0x3;
+    f_status_t status = controller_lock_read_instance(instance, &instance->use);
 
-      return status_lock;
+    if (F_status_is_error(status)) {
+      controller_print_error_lock_critical(&instance->main->program.error, F_status_set_fine(status), F_true);
+
+      return status;
     }
 
-    instance->state = (options_force & controller_instance_option_asynchronous_d) ? controller_instance_state_done_e : controller_instance_state_idle_e;
-    instance->stack.used = used_original_stack;
+    for (f_number_unsigned_t i = 0; i < instance->stack.used && controller_thread_is_enabled_instance(instance); ++i) {
 
-    f_thread_unlock(&instance->use);
+      if (instance->stack.array[i] == rule) {
 
-    f_thread_condition_signal_all(&instance->wait_condition);
+        // Never continue on circular recursion errors even in simulate mode.
+        status = F_status_set_error(F_recurse);
 
-    return controller_thread_is_enabled_instance(instance) ? status : F_status_set_error(F_interrupt);
+        controller_print_error_rule_stack_already(&instance->main->program.error, &instance->cache.action, instance->rule.alias, F_true);
+
+        break;
+      }
+    } // for
+
+    f_thread_unlock(&instance->use);
+
+    return status;
   }
-#endif // _di_controller_rule_instance_perform_details_
+#endif // _di_controller_rule_instance_perform_details_stack_verify_
 
 #ifdef __cplusplus
 } // extern "C"
index f78ab8327efb98518709c5b95fbddd4048f8131f..e0c4bfc8479c83ec69c1cb72648264bf53c8aff9 100644 (file)
@@ -44,9 +44,11 @@ extern "C" {
  *
  *   Errors (with error bit) from: controller_lock_read_standard().
  *   Errors (with error bit) from: controller_lock_write_instance().
+ *   Errors (with error bit) from: controller_rule_find().
  *
  *   @see controller_lock_read_standard().
  *   @see controller_lock_write_instance().
+ *   @see controller_rule_find();
  */
 #ifndef _di_controller_rule_instance_
   extern f_status_t controller_rule_instance(controller_instance_t * const instance);
@@ -101,7 +103,7 @@ extern "C" {
  * @see f_thread_create()
  */
 #ifndef _di_controller_rule_instance_begin_
-  extern f_status_t controller_rule_instance_begin(controller_t * const main, controller_cache_t * const cache, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_number_unsigneds_t stack);
+  extern f_status_t controller_rule_instance_begin(controller_t * const main, controller_cache_t * const cache, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const controller_rules_t stack);
 #endif // _di_controller_rule_instance_begin_
 
 /**
@@ -151,13 +153,6 @@ extern "C" {
  *
  *   If controller_instance_option_asynchronous_d, then asynchronously execute.
  *   If not controller_instance_option_asynchronous_d, then synchronously execute.
- * @param flag
- *   Designate lock states:
- *     - 0x1: Locking error.
- *     - 0x2: Locking error is a write lock.
- *     - 0x4: The rule lock is still set.
- *
- *   Must not be NULL.
  *
  * @return
  *   F_okay on success.
@@ -171,15 +166,103 @@ extern "C" {
  *
  *   Errors (with error bit) from: controller_rule_copy().
  *   Errors (with error bit) from: controller_rule_instance().
+ *   Errors (with error bit) from: controller_lock_read_instance().
  *
  * @see controller_rule_copy()
  * @see controller_rule_instance()
  * @see controller_rule_instance_begin()
+ * @see controller_lock_read_instance()
  */
 #ifndef _di_controller_rule_instance_perform_details_
-  extern f_status_t controller_rule_instance_perform_details(controller_instance_t * const instance, const uint8_t options_force, uint8_t * const flag);
+  extern f_status_t controller_rule_instance_perform_details(controller_instance_t * const instance, const uint8_t options_force);
 #endif // _di_controller_rule_instance_perform_details_
 
+/**
+ * Wrap controller_rule_copy(), handling locking and prepping of rule before actual copy.
+ *
+ * The destination rule will be deleted before copying the source.
+ *
+ * This calls controller_print_error_lock_critical() on locking error.
+ *
+ * @param instance
+ *   The instance data.
+ *
+ *   Must not be NULL.
+ * @param source
+ *   The source Rule to copy from.
+ * @param destination
+ *   The destination Rule to copy to.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   Errors (with error bit) from: controller_rule_copy().
+ *
+ *  @see controller_rule_copy()
+ */
+#ifndef _di_controller_rule_instance_perform_details_copy_
+  extern f_status_t controller_rule_instance_perform_details_copy(controller_instance_t * const instance, const controller_rule_t source, controller_rule_t * const destination);
+#endif // _di_controller_rule_instance_perform_details_copy_
+
+/**
+ * Append the rule to the stack.
+ *
+ * This prints error messages (such as memory allocation error).
+ * This prints critical error message on lock error.
+ *
+ * @param instance
+ *   The instance data.
+ *
+ *   Must not be NULL.
+ * @param rule
+ *   The rule to verify.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   F_recurse (with error bit) on rule already being on the stack.
+ *
+ *   Errors (with error bit) from: controller_lock_read_instance().
+ *
+ * @see controller_lock_read_instance()
+ */
+#ifndef _di_controller_rule_instance_perform_details_stack_rule_append_
+  extern f_status_t controller_rule_instance_perform_details_stack_rule_append(controller_instance_t * const instance, controller_rule_t * const rule);
+#endif // _di_controller_rule_instance_perform_details_stack_rule_append_
+
+/**
+ * Check if the rule is on the stack already.
+ *
+ * If the rule is already on the stack, then error out.
+ *
+ * This prints critical error message on lock error.
+ *
+ * @param instance
+ *   The instance data.
+ *
+ *   Must not be NULL.
+ * @param rule
+ *   The rule to verify.
+ *
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   F_recurse (with error bit) on rule already being on the stack.
+ *
+ *   Errors (with error bit) from: controller_lock_read_instance().
+ *
+ * @see controller_lock_read_instance()
+ */
+#ifndef _di_controller_rule_instance_perform_details_stack_verify_
+  extern f_status_t controller_rule_instance_perform_details_stack_verify(controller_instance_t * const instance, controller_rule_t * const rule);
+#endif // _di_controller_rule_instance_perform_details_stack_verify_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 90c0e00c1e096e010c4cbe44e97ac32585ba866b..4601db430f4d3488df506203166a6703263fb86e 100644 (file)
@@ -166,6 +166,7 @@ extern "C" {
 
     controller_interrupt_t custom = macro_controller_interrupt_t_initialize_1(is_normal, main);
     f_state_t state = macro_f_state_t_initialize_1(controller_allocation_large_d, controller_allocation_small_d, F_okay, 0, 0, 0, &controller_thread_signal_state_fss, 0, (void *) &custom, 0);
+
     state.status = f_string_dynamic_append_nulless(alias, &rule->alias);
 
     if (F_status_is_error(state.status)) {
index 6c517773ed2045f5da747d69e47055b303d4851c..dc53af2eb595e63caec37cb93fd2adad9c7b936f 100644 (file)
@@ -142,7 +142,8 @@ extern "C" {
 
           // De-allocate dynamic portions of the structure that are only ever needed while the instance is running.
           controller_cache_delete(&instance->cache);
-          f_memory_array_resize(0, sizeof(f_number_unsigned_t), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
+
+          f_memory_array_resize(0, sizeof(controller_rule_t *), (void **) &instance->stack.array, &instance->stack.used, &instance->stack.size);
 
           // Shrink the childs array.
           if (instance->childs.used && instance->childs.used < instance->childs.size) {