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.
"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",
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,
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_
/**
* 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.
* - 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;
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, \
f_string_dynamic_t_initialize, \
f_string_dynamics_t_initialize, \
controller_cache_action_t_initialize, \
+ controller_rules_t_initialize, \
}
#endif // _di_controller_cache_t_
#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_
#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_
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) {
}
#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
* 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".
*
* - 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.
*/
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;
};
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, \
}
#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.
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
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);
* @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);
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_
}
#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) {
}
#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"
* - 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;
controller_rule_ons_t ons;
controller_rule_items_t items;
- } controller_rule_t;
+ };
#define controller_rule_t_initialize { \
{ \
/**
* 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, \
#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
#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"
#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>
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;
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);
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);
}
// 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;
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);
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) {
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);
}
}
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)) {
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)) {
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;
}
* @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.
}
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;
}
*
* @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_
#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_
/**
* 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_
/**
}
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,
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");
}
}
}
- 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)) {
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) {
}
}
else {
- status = main->process.rules.array[id_rule].status[instance->action];
-
- f_thread_unlock(&main->thread.lock.rule);
+ status = rule->status[instance->action];
}
}
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;
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);
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) {
// 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) {
}
}
- f_number_unsigned_t id_rule = 0;
-
status_lock = controller_lock_write_instance(instance, &instance->use);
if (F_status_is_error(status_lock)) {
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);
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)) {
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"
*
* 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);
* @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_
/**
*
* 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.
*
* 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
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)) {
// 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) {