}
#endif // _di_controller_lock_create_
+#ifndef _di_controller_lock_delete_mutex_
+ void controller_lock_delete_mutex(f_thread_mutex_t *mutex) {
+
+ const f_status_t status = f_thread_mutex_delete(mutex);
+
+ if (F_status_is_error(status)) {
+ if (F_status_set_fine(status) == F_busy) {
+ f_thread_mutex_lock(mutex);
+ f_thread_mutex_unlock(mutex);
+
+ if (f_thread_mutex_delete(mutex) == F_none) {
+ mutex = 0;
+ }
+ }
+ }
+ else {
+ mutex = 0;
+ }
+ }
+#endif // _di_controller_lock_delete_mutex_
+
+#ifndef _di_controller_lock_delete_rw_
+ void controller_lock_delete_rw(f_thread_lock_t *lock) {
+
+ const f_status_t status = f_thread_lock_delete(lock);
+
+ if (F_status_is_error(status)) {
+ if (F_status_set_fine(status) == F_busy) {
+ f_thread_lock_write(lock);
+ f_thread_unlock(lock);
+
+ if (f_thread_lock_delete(lock) == F_none) {
+ lock = 0;
+ }
+ }
+ }
+ else {
+ lock = 0;
+ }
+ }
+#endif // _di_controller_lock_delete_rw_
+
#ifndef _di_controller_lock_delete_simple_
void controller_lock_delete_simple(controller_lock_t *lock) {
- f_thread_mutex_delete(&lock->print);
-
- f_thread_lock_delete(&lock->process);
- f_thread_lock_delete(&lock->rule);
+ controller_lock_delete_mutex(&lock->print);
+ controller_lock_delete_rw(&lock->process);
+ controller_lock_delete_rw(&lock->rule);
}
#endif // _di_controller_lock_delete_simple_
#ifndef _di_controller_process_delete_simple_
void controller_process_delete_simple(controller_process_t *process) {
- f_thread_lock_delete(&process->lock);
- f_thread_lock_delete(&process->active);
-
- f_thread_mutex_lock(&process->wait_lock);
- f_thread_condition_signal_all(&process->wait);
- f_thread_mutex_unlock(&process->wait_lock);
- f_thread_mutex_delete(&process->wait_lock);
+ controller_lock_delete_rw(&process->lock);
+ controller_lock_delete_rw(&process->active);
+ controller_lock_delete_mutex(&process->wait_lock);
+ f_thread_condition_delete(&process->wait);
controller_cache_delete_simple(&process->cache);
controller_rule_delete_simple(&process->rule);
status = f_memory_resize(processs->size, length, sizeof(controller_process_t), (void **) & processs->array);
- if (F_status_is_error_not(status)) {
+ if (F_status_is_error_not(status) && length) {
// the lock must be initialized, but only once, so initialize immediately upon allocation.
for (; processs->size < length; ++processs->size) {
f_macro_int32s_t_delete_simple(rule->groups)
f_macro_limit_sets_t_delete_simple(rule->limits)
- f_capability_delete(&rule->capability);
+ if (rule->capability) {
+ f_capability_delete(&rule->capability);
+ }
controller_rule_items_delete_simple(&rule->items);
}
fl_execute_as_t_initialize \
}
- #define controller_macro_execute_set_t_initialize(option, environment, signals, data, as) { \
- fl_macro_execute_parameter_t_initialize(option, environment, signals, data), \
+ #define controller_macro_execute_set_t_initialize(option, wait, environment, signals, data, as) { \
+ fl_macro_execute_parameter_t_initialize(option, wait, environment, signals, data), \
as, \
}
#endif // _di_controller_execute_set_t_
/**
* A Rule.
*
+ * status: The status of the rule as the result of processing/execution.
* timeout_kill: The timeout to wait relating to using a kill signal.
* timeout_start: The timeout to wait relating to starting a process.
* timeout_stop: The timeout to wait relating to stopping a process.
*
* This refers to "process" as in the processing of a single rule for the given Rule ID and does not refer to "process" as in a CPU Process.
*
+ * The "cache" should only be used by the function processing/executing the process and as such should not require a write lock on the "process".
+ * There should only be a single thread running any given Rule process at a time, guaranteeing the cache to not need read/write locks.
+ *
* Process States:
* - idle: No process is running for this rule.
* - busy: A process is actively using this, and is running synchronously.
* - done: A process has finished running on this and there is a thread that needs to be cleaned up.
*
* id: The ID of this process relative to the processes array.
- * status: The last execution status of the Rule.
+ * status: The last execution status of the process.
* state: The state of the process.
* action: The action being performed.
* options: Configuration options for this asynchronous thread.
#define controller_thread_cleanup_interval_long 3600 // 1 hour in seconds.
#define controller_thread_cleanup_interval_short 180 // 3 minutes in seconds.
//#define controller_thread_exit_force_timeout 60 // 1 minute in seconds.
- #define controller_thread_exit_force_timeout 5
+ #define controller_thread_exit_process_force_timeout 2000000 // 2 seconds in microseconds.
+ #define controller_thread_exit_main_force_timeout 100000 // 0.1 seconds in microseconds.
typedef struct {
bool enabled;
#endif // _di_controller_lock_create_
/**
+ * Delete the mutex lock and if the mutex lock is busy, forcibly unlock it and then delete it.
+ *
+ * @param mutex
+ * The mutex lock to delete.
+ * Will be set to NULLif delete succeeded.
+ */
+#ifndef _di_controller_lock_delete_mutex_
+ extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_lock_delete_mutex_
+
+/**
+ * Delete the r/w lock and if the r/w lock is busy, forcibly unlock it and then delete it.
+ *
+ * @param lock
+ * The r/w lock to delete.
+ * Will be set to NULL if delete succeeded.
+ */
+#ifndef _di_controller_lock_delete_rw_
+ extern void controller_lock_delete_rw(f_thread_lock_t *lock) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_lock_delete_rw_
+
+/**
* Fully deallocate all memory for the given lock without caring about return status.
*
* @param lock
actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions;
- for (; cache->ats.array[at_j] < actions->used; ++cache->ats.array[at_j]) {
-
- if (main.thread->signal) {
- return F_signal;
- }
+ for (; cache->ats.array[at_j] < actions->used && main.thread->enabled; ++cache->ats.array[at_j]) {
cache->action.line_action = actions->array[cache->ats.array[at_j]].line;
cache->action.name_action.used = 0;
}
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "Processing entry item rule '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_main_s, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "Processing entry item '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_main_s, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
for (;;) {
entry_actions = &main.setting->entry.items.array[cache->ats.array[at_i]].actions;
- for (; cache->ats.array[at_j] < entry_actions->used; ++cache->ats.array[at_j]) {
-
- if (main.thread->signal) {
- status = F_signal;
- break;
- }
+ for (; cache->ats.array[at_j] < entry_actions->used && main.thread->enabled; ++cache->ats.array[at_j]) {
entry_action = &entry_actions->array[cache->ats.array[at_j]];
}
if (F_status_is_error(entry_action->status)) {
-
if (entry_action->type == controller_entry_action_type_rule) {
-
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "The entry item action '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "The entry item action '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
- if (entry_action->parameters.used) {
- fprintf(main.data->output.stream, f_string_space_s);
- fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
- controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
- fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
- }
+ if (entry_action->parameters.used) {
+ fprintf(main.data->output.stream, f_string_space_s);
+ fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
+ controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
+ fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
+ }
- fprintf(main.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "' is %s and is in a %sfailed%s state, skipping execution.%c", entry_action->code & controller_entry_rule_code_require ? "required" : "optional", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
else if (entry_action->code & controller_entry_rule_code_require) {
}
else {
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "The entry item action '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "The entry item action '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_action.string, main.data->context.set.title.after->string);
- if (entry_action->parameters.used) {
- fprintf(main.data->output.stream, f_string_space_s);
- fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
- controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
- fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
- }
+ if (entry_action->parameters.used) {
+ fprintf(main.data->output.stream, f_string_space_s);
+ fprintf(main.data->output.stream, "%s", main.data->context.set.notable.before->string);
+ controller_entry_action_parameters_print(main.data->output.stream, entry_actions->array[cache->ats.array[at_j]]);
+ fprintf(main.data->output.stream, "%s", main.data->context.set.notable.after->string);
+ }
- fprintf(main.data->output.stream, "' is in a %sfailed%s state, skipping.%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "' is in a %sfailed%s state, skipping.%c", main.data->error.context.before->string, main.data->error.context.after->string, f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
else if (main.data->warning.verbosity == f_console_verbosity_debug) {
f_thread_mutex_lock(&main.thread->lock.print);
if (main.setting->ready == controller_setting_ready_wait) {
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "Processing entry item action '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "Processing entry item action '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
else {
controller_perform_ready(main, cache);
main.setting->ready = controller_setting_ready_yes;
}
else if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "Ignoring entry item action '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "Ignoring entry item action '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_ready_s, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "', state already is ready.%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
}
else if (entry_action->type == controller_entry_action_type_item) {
}
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "Processing entry item '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_item.string, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "Processing entry item '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, cache->action.name_item.string, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
// exit inner loop to force restarting and start processing the requested item.
f_thread_unlock(&main.thread->lock.rule);
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, alias_rule.string, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%s entry item rule '", entry_action->type == controller_entry_action_type_rule ? "Processing" : "Considering");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, alias_rule.string, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
// the rule is not yet loaded, ensure that it is loaded.
status = controller_rule_process_begin(entry_action->code & controller_entry_rule_code_asynchronous, alias_rule, controller_rule_action_type_start, rule_options, stack, main, *cache);
- if (!simulate || F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal) {
+ if (F_status_set_fine(status) == F_memory_not || status == F_child || status == F_signal) {
break;
}
}
code = controller_string_stop_s;
}
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "Processing entry item action '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_timeout_s, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "' setting '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, code, main.data->context.set.important.after->string);
- fprintf(main.data->output.stream, "' to '");
- fprintf(main.data->output.stream, "%s%llu%s", main.data->context.set.important.before->string, entry_action->number, main.data->context.set.important.after->string);
- fprintf(main.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "Processing entry item action '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_timeout_s, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "' setting '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, code, main.data->context.set.important.after->string);
+ fprintf(main.data->output.stream, "' to '");
+ fprintf(main.data->output.stream, "%s%llu%s", main.data->context.set.important.before->string, entry_action->number, main.data->context.set.important.after->string);
+ fprintf(main.data->output.stream, "' MegaTime (milliseconds).%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
if (entry_action->code == controller_entry_timeout_code_kill) {
main.setting->failsafe_rule_id = entry_action->number;
if (simulate) {
- f_thread_mutex_lock(&main.thread->lock.print);
+ if (main.data->error.verbosity != f_console_verbosity_quiet) {
+ f_thread_mutex_lock(&main.thread->lock.print);
- fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
- fprintf(main.data->output.stream, "Processing entry item action '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_failsafe_s, main.data->context.set.title.after->string);
- fprintf(main.data->output.stream, "' setting value to '");
- fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, main.setting->entry.items.array[main.setting->failsafe_rule_id].name.string, main.data->context.set.important.after->string);
- fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "%c", f_string_eol_s[0]);
+ fprintf(main.data->output.stream, "Processing entry item action '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.title.before->string, controller_string_failsafe_s, main.data->context.set.title.after->string);
+ fprintf(main.data->output.stream, "' setting value to '");
+ fprintf(main.data->output.stream, "%s%s%s", main.data->context.set.important.before->string, main.setting->entry.items.array[main.setting->failsafe_rule_id].name.string, main.data->context.set.important.after->string);
+ fprintf(main.data->output.stream, "'.%c", f_string_eol_s[0]);
- f_thread_mutex_unlock(&main.thread->lock.print);
+ f_thread_mutex_unlock(&main.thread->lock.print);
+ }
}
}
}
} // for
- if (main.thread->signal || !main.thread->enabled) {
+ if (!main.thread->enabled) {
status = F_signal;
}
}
#endif // _di_controller_process_entry_
-#ifndef _di_controller_status_simplify_
- f_status_t controller_status_simplify(const f_status_t status) {
+#ifndef _di_controller_status_simplify_error_
+ f_status_t controller_status_simplify_error(const f_status_t status) {
if (status == F_memory_not) {
return F_status_set_error(F_memory);
return F_status_set_error(status);
}
+ if (status == F_failure) {
+ return F_status_set_error(F_failure);
+ }
+
return F_status_set_error(F_valid_not);
}
-#endif // _di_controller_status_simplify_
+#endif // _di_controller_status_simplify_error_
#ifndef _di_controller_validate_define_name_
f_status_t controller_validate_environment_name(const f_string_static_t name) {
#endif // _di_controller_process_entry_
/**
- * Given a wide range of status codes, simplify them down to a small subset.
+ * Given a wide range of status codes (that are errors), simplify them down to a small subset.
*
* @param status
* The status code (without the error bit set) to simplify.
* @return
* A subset of status codes with error bit.
*/
-#ifndef _di_controller_status_simplify_
- extern f_status_t controller_status_simplify(const f_status_t status) f_gcc_attribute_visibility_internal;
-#endif // _di_controller_status_simplify_
+#ifndef _di_controller_status_simplify_error_
+ extern f_status_t controller_status_simplify_error(const f_status_t status) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_status_simplify_error_
/**
* Validate that the given string is a valid environment variable name.
action->status = F_status_set_error(F_number);
}
else {
- action->status = controller_status_simplify(F_status_set_fine(status));
+ action->status = controller_status_simplify_error(F_status_set_fine(status));
}
if (F_status_set_fine(status) == F_memory_not) {
f_array_length_t i = 0;
f_array_length_t j = 0;
- for (; i < cache->object_items.used; ++i) {
+ for (; i < cache->object_items.used && main.thread->enabled; ++i) {
- if (main.thread->signal) {
+ if (!main.thread->enabled) {
return F_signal;
}
for (j = 0; j < main.setting->entry.items.array[i].actions.used; ++j) {
- if (main.thread->signal) {
+ if (!main.thread->enabled) {
return F_signal;
}
}
action->number = 0;
- action->status = controller_status_simplify(F_found_not);
+ action->status = controller_status_simplify_error(F_found_not);
// @fixme review how main.setting->entry.status is being handled with respect to action->status (here the action failed, should the entire entry fail? at the moment if mode is simulation this prevents simulation from continuing).
- //main.setting->entry.status = controller_status_simplify(F_found_not);
+ //main.setting->entry.status = controller_status_simplify_error(F_found_not);
cache->action.name_action.used = 0;
cache->action.name_item.used = 0;
if (F_status_is_error(status)) {
controller_entry_error_print_cache(main.data->error, cache->action);
- main.setting->entry.status = controller_status_simplify(F_status_set_fine(status));
+ main.setting->entry.status = controller_status_simplify_error(F_status_set_fine(status));
}
else {
main.setting->entry.status = F_none;
* Errors (with error bit) from: controller_entry_actions_read().
* Errors (with error bit) from: controller_entry_items_increase_by().
* Errors (with error bit) from: controller_file_load().
- * Errors (with error bit) from: controller_status_simplify().
+ * Errors (with error bit) from: controller_status_simplify_error().
* Errors (with error bit) from: controller_string_dynamic_append_terminated().
* Errors (with error bit) from: controller_string_dynamic_partial_append_terminated().
* Errors (with error bit) from: f_fss_count_lines().
* @see controller_entry_actions_read()
* @see controller_entry_items_increase_by()
* @see controller_file_load()
- * @see controller_status_simplify()
+ * @see controller_status_simplify_error()
* @see controller_string_dynamic_append_terminated()
* @see controller_string_dynamic_partial_append_terminated()
* @see f_fss_count_lines()
if (F_status_is_error(status)) {
controller_error_print(main.data->error, F_status_set_fine(status), "f_string_dynamics_increase", F_true, main.thread);
- actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+ actions->array[actions->used].status = controller_status_simplify_error(F_status_set_fine(status));
break;
}
status = controller_rule_parameters_read(main, cache->buffer_item, &cache->object_actions.array[i], &cache->content_actions.array[i], &actions->array[actions->used].parameters);
- actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+ actions->array[actions->used].status = controller_status_simplify_error(F_status_set_fine(status));
actions->used++;
} // for
if (F_status_is_error(status)) {
controller_error_print(main.data->error, F_status_set_fine(status), "controller_rule_parameters_read", F_true, main.thread);
- actions->array[actions->used].status = controller_status_simplify(F_status_set_fine(status));
+ actions->array[actions->used].status = controller_status_simplify_error(F_status_set_fine(status));
}
else {
actions->array[actions->used].status = status;
f_status_t status = F_none;
+ // delete the third party structures.
+ f_macro_control_group_t_delete_simple(destination->control_group)
+ f_capability_delete(&destination->capability);
+
+ destination->status = source.status;
+
destination->timeout_kill = source.timeout_kill;
destination->timeout_start = source.timeout_start;
destination->timeout_stop = source.timeout_stop;
const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize;
- controller_execute_set_t execute_set = controller_macro_execute_set_t_initialize(0, &environment, &signals, 0, fl_execute_as_t_initialize);
+ controller_execute_set_t execute_set = controller_macro_execute_set_t_initialize(0, 0, &environment, &signals, 0, fl_execute_as_t_initialize);
// when using pointers in threads and calling the exec functions, invalid reads and writes may occur.
// this problem might be happening due to a compiler optimization/decision, so make local copies and have the pointers reference these to avoid invalid reads and writes.
if (F_status_is_error(status)) {
controller_error_print(main.data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, main.thread);
- process->status = F_status_set_error(F_failure);
return status;
}
}
if (F_status_is_error(status)) {
controller_error_print(main.data->error, F_status_set_fine(status), "fl_environment_load_names", F_true, main.thread);
- process->status = F_status_set_error(F_failure);
return status;
}
for (i = 0; i < process->rule.items.used; ++i) {
- if (main.thread->signal) {
+ if (!main.thread->enabled) {
status = F_signal;
break;
}
for (j = 0; j < process->rule.items.array[i].actions.used; ++j) {
- if (main.thread->signal) {
+ if (!main.thread->enabled) {
status = F_signal;
break;
}
process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
if (!(options & controller_rule_option_simulate)) break;
- }
- success = F_true;
+ success = F_status_set_error(F_failure);
+ }
+ else if (success == F_false || success == F_ignore) {
+ success = F_true;
+ }
}
else if (process->rule.items.array[i].type == controller_rule_item_type_script) {
process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
if (!(options & controller_rule_option_simulate)) break;
- }
- success = F_true;
+ success = F_status_set_error(F_failure);
+ }
+ else if (success == F_false || success == F_ignore) {
+ success = F_true;
+ }
}
else if (process->rule.items.array[i].type == controller_rule_item_type_service) {
process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure);
if (!(options & controller_rule_option_simulate)) break;
- }
- success = F_true;
+ success = F_status_set_error(F_failure);
+ }
+ else if (success == F_false || success == F_ignore) {
+ success = F_true;
+ }
}
else {
f_thread_mutex_unlock(&main.thread->lock.print);
}
- process->rule.items.array[i].actions.array[j].status = F_ignore;
-
- if (success != F_true) {
+ if (success == F_false) {
success = F_ignore;
}
}
if (F_status_is_error(status) || success == F_false) {
- process->status = F_status_set_error(F_failure);
+ return F_status_set_error(F_failure);
}
- else if (success == F_ignore || success == F_busy) {
- process->status = success;
- }
- else {
- process->status = F_none;
+
+ if (success == F_ignore) {
+ return F_ignore;
}
- return process->status;
+ return F_none;
}
#endif // _di_controller_rule_execute_
const f_string_static_t simulated_program = f_macro_string_static_t_initialize(f_string_empty_s, 0);
const f_string_statics_t simulated_arguments = f_string_statics_t_initialize;
- fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
+ fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.wait, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, simulated_parameter.option & fl_execute_parameter_option_return ? (void *) &result : (void *) &id_process);
}
if (status == F_parent) {
result = 0;
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
// assign the child process id to allow for the cancel process to send appropriate termination signals to the child process.
process->child = id_process;
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
+
// have the parent wait for the child process to finish.
- waitpid(id_process, &result, WUNTRACED | WCONTINUED);
+ waitpid(id_process, &result, 0);
+
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
// remove the pid now that waidpid() has returned.
process->child = 0;
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
+
// this must explicitly check for 0 (as opposed to checking (!result)).
if (!WIFEXITED(result)) {
status = F_status_set_error(F_failure);
const f_string_static_t simulated_program = f_macro_string_static_t_initialize(f_string_empty_s, 0);
const f_string_statics_t simulated_arguments = f_string_statics_t_initialize;
- fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
+ fl_execute_parameter_t simulated_parameter = fl_macro_execute_parameter_t_initialize(execute_set->parameter.option, execute_set->parameter.wait, execute_set->parameter.environment, execute_set->parameter.signals, &simulated_program);
status = fll_execute_program(controller_default_program_script, simulated_arguments, &simulated_parameter, &execute_set->as, simulated_parameter.option & fl_execute_parameter_option_return ? (void *) &result : (void *) &id_process);
}
if (status == F_parent) {
result = 0;
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
// assign the child process id to allow for the cancel process to send appropriate termination signals to the child process.
process->child = id_process;
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
+
// have the parent wait for the child process to finish.
- waitpid(id_process, &result, WUNTRACED | WCONTINUED);
+ waitpid(id_process, &result, 0);
+
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
// remove the pid now that waidpid() has returned.
process->child = 0;
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
+
// this must explicitly check for 0 (as opposed to checking (!result)).
if (!WIFEXITED(result)) {
status = F_status_set_error(F_failure);
#endif // _di_controller_rule_setting_limit_type_name_
#ifndef _di_controller_rule_process_
- f_status_t controller_rule_process(const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) {
+ f_status_t controller_rule_process(const uint8_t action, const controller_main_t main, controller_process_t *process) {
switch (action) {
case controller_rule_action_type_freeze:
return status;
}
- if ((options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) {
- controller_rule_simulate(process->rule, controller_rule_action_type_start, options, main, &process->cache);
+ if ((process->options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) {
+ controller_rule_simulate(process->rule, controller_rule_action_type_start, process->options, main, &process->cache);
}
f_array_length_t i = 0;
f_array_length_t k = 0;
f_array_length_t id_rule = 0;
f_array_length_t id_process = 0;
+ bool found = F_false;
controller_process_t *process_other = 0;
status = controller_rule_find(dynamics[i]->array[j], main.setting->rules, &id_rule);
f_thread_unlock(&main.thread->lock.rule);
+
+ found = F_true;
}
if (status != F_true) {
- f_thread_lock_read(&main.thread->lock.rule);
+ found = F_false;
+ id_rule = 0;
- id_rule = main.setting->rules.used;
+ f_thread_lock_read(&main.thread->lock.rule);
if (i == 0) {
f_thread_mutex_lock(&main.thread->lock.print);
status = F_status_set_error(F_found_not);
- if (!(options & controller_rule_option_simulate)) {
+ if (!(process->options & controller_rule_option_simulate)) {
f_thread_unlock(&main.thread->lock.rule);
break;
f_thread_lock_read(&main.thread->lock.rule);
- if (status == F_true && id_rule < main.setting->rules.used) {
+ if (status == F_true && found) {
f_thread_unlock(&main.thread->lock.rule);
f_thread_lock_read(&main.thread->lock.process);
f_thread_unlock(&main.thread->lock.rule);
// attempt to (synchronously) execute the rule when the status is unknown (the rule has not yet been run).
- if (process_other->status == F_known_not) {
+ if (main.setting->rules.array[id_rule].status == F_known_not) {
const f_string_static_t alias_other = f_macro_string_static_t_initialize(alias_other_buffer, main.setting->rules.array[id_rule].alias.used);
- status = controller_rule_process_begin(F_false, alias_other, action, options & controller_rule_option_asynchronous ? options - controller_rule_option_asynchronous : options, process->stack, main, process->cache);
+ status = controller_rule_process_begin(F_false, alias_other, action, process->options & controller_rule_option_asynchronous ? process->options - controller_rule_option_asynchronous : process->options, process->stack, main, process->cache);
if (status == F_child || status == F_signal) {
f_thread_unlock(&process_other->active);
f_thread_mutex_unlock(&main.thread->lock.print);
- if (!(options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
+ if (!(process->options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
f_thread_unlock(&process_other->active);
break;
}
}
+ f_thread_lock_read(&main.thread->lock.rule);
f_thread_unlock(&process_other->active);
- if (F_status_is_error(process_other->status)) {
+ if (F_status_is_error(main.setting->rules.array[id_rule].status)) {
if (i == 0 || i == 1) {
f_thread_mutex_lock(&main.thread->lock.print);
f_thread_mutex_unlock(&main.thread->lock.print);
- if (!(options & controller_rule_option_simulate)) {
+ if (!(process->options & controller_rule_option_simulate)) {
f_thread_unlock(&main.thread->lock.rule);
break;
}
}
}
}
+
+ f_thread_unlock(&main.thread->lock.rule);
}
else {
f_thread_unlock(&main.thread->lock.rule);
if (status == F_child || status == F_signal) break;
- if (F_status_is_error(status) && !(options & controller_rule_option_simulate)) break;
+ if (F_status_is_error(status) && !(process->options & controller_rule_option_simulate)) break;
} // for
}
return F_signal;
}
- if (!(options & controller_rule_option_wait) && F_status_is_error_not(status)) {
+ if (!(process->options & controller_rule_option_wait) && F_status_is_error_not(status)) {
controller_rule_wait_all(main, process);
if (!main.thread->enabled) {
}
}
- if (!(options & controller_rule_option_validate) && F_status_is_error_not(status)) {
+ if (!(process->options & controller_rule_option_validate) && F_status_is_error_not(status)) {
// find at least one of the requested action when the rule is required.
- if (options & controller_rule_option_require) {
+ if (process->options & controller_rule_option_require) {
bool missing = F_true;
f_array_length_t j = 0;
}
if (F_status_is_error_not(status)) {
- status = controller_rule_execute(action, options, main, process);
+ status = controller_rule_execute(action, process->options, main, process);
- if (status == F_child) {
- return F_child;
+ if (status == F_child || status == F_signal) {
+ return status;
}
if (!main.thread->enabled) {
}
}
+ f_array_length_t id_rule = 0;
+
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
if (F_status_is_error(status)) {
- return status;
+ process->rule.status = controller_status_simplify_error(F_status_set_fine(status));
+ }
+ else {
+ process->rule.status = status;
}
- return F_none;
+ f_thread_lock_write(&main.thread->lock.rule);
+
+ status = controller_rule_find(process->rule.alias, main.setting->rules, &id_rule);
+
+ if (F_status_is_error(status)) {
+ controller_rule_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "controller_rule_find", F_true, F_true, main.thread);
+ }
+ else {
+ main.setting->rules.array[id_rule].status = process->rule.status;
+
+ // @fixme the rule item action status needs to be copied over from the local rule to the old one but there is no way to map the two (the structure could have changeed).
+ }
+
+ f_thread_unlock(&main.thread->lock.rule);
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
+
+ return process->rule.status;
}
#endif // _di_controller_rule_process_
}
f_status_t status = F_none;
-
controller_process_t *process = 0;
+ f_thread_lock_read(&main.thread->lock.process);
+
{
f_array_length_t at = 0;
- f_thread_lock_read(&main.thread->lock.process);
-
if (controller_find_process(alias_rule, main.thread->processs, &at) != F_true) {
status = F_status_set_error(F_found_not);
}
- f_thread_unlock(&main.thread->lock.process);
-
if (F_status_is_error(status)) {
+ f_thread_unlock(&main.thread->lock.process);
if (main.data->error.verbosity != f_console_verbosity_quiet) {
f_thread_mutex_lock(&main.thread->lock.print);
return status;
}
- f_thread_lock_read(&main.thread->lock.process);
- f_thread_lock_write(&main.thread->processs.array[at].lock);
- f_thread_unlock(&main.thread->lock.process);
-
process = &main.thread->processs.array[at];
+ f_thread_lock_read(&process->active);
+ f_thread_lock_write(&process->lock);
+
+ // once a write lock on the process is achieved, it is safe to unlock the main process read lock.
+ f_thread_unlock(&main.thread->lock.process);
+
// if the process is already running, then there is nothing to do.
if (process->state == controller_process_state_active || process->state == controller_process_state_busy) {
f_thread_unlock(&process->lock);
+ f_thread_unlock(&process->active);
return F_busy;
}
- f_thread_lock_read(&process->active);
-
// the thread is done, so detach/close the thread.
if (process->state == controller_process_state_done) {
f_thread_cancel(process->id_thread);
process->id = at;
}
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
process->state = controller_process_state_active;
process->action = action;
process->options = options;
process->main_thread = (void *) main.thread;
if (F_status_is_error_not(status) && stack.used) {
- if (process->stack.used < stack.used) {
- status = f_type_array_lengths_resize(process->stack.used, &process->stack);
+ if (process->stack.size < stack.used) {
+ status = f_type_array_lengths_resize(stack.used, &process->stack);
}
if (F_status_is_error(status)) {
}
else {
for (f_array_length_t i = 0; i < stack.used; ++i) {
- process->stack.array[process->stack.used++] = stack.array[i];
+ process->stack.array[i] = stack.array[i];
} // for
+
+ process->stack.used = stack.used;
}
}
f_status_t controller_rule_process_do(const bool asynchronous, controller_process_t *process) {
// the process lock shall be held for the duration of this processing (aside from switching between read to/from write).
- f_thread_lock_read(&process->active);
- f_thread_lock_write(&process->lock);
+ if (asynchronous) f_thread_lock_read(&process->active);
+ f_thread_lock_read(&process->lock);
controller_main_t main = controller_macro_main_t_initialize((controller_data_t *) process->main_data, (controller_setting_t *) process->main_setting, (controller_thread_t *) process->main_thread);
if (!main.thread->enabled) {
f_thread_unlock(&process->lock);
- f_thread_unlock(&process->active);
+ if (asynchronous) f_thread_unlock(&process->active);
return F_signal;
}
f_array_length_t id_rule = 0;
const f_array_length_t used_original_stack = process->stack.used;
+ const bool simulate = main.data->parameters[controller_parameter_test].result == f_console_result_found;
f_thread_lock_read(&main.thread->lock.rule);
if (controller_rule_find(process->rule.alias, main.setting->rules, &id_rule) == F_true) {
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
+ controller_rule_delete_simple(&process->rule);
+
status = controller_rule_copy(main.setting->rules.array[id_rule], &process->rule);
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
+
f_thread_unlock(&main.thread->lock.rule);
if (F_status_is_error(status)) {
controller_entry_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "f_type_array_lengths_increase", F_true, main.thread);
}
else {
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
process->stack.array[process->stack.used++] = id_rule;
+
+ f_thread_unlock(&process->lock);
+ f_thread_lock_read(&process->lock);
}
}
}
if (F_status_is_error_not(status) && main.thread->enabled) {
- const uint8_t rule_options = asynchronous ? controller_rule_option_asynchronous : 0;
-
- status = controller_rule_process(controller_rule_action_type_start, rule_options, main, process);
+ status = controller_rule_process(controller_rule_action_type_start, main, process);
}
}
else {
}
}
+ f_thread_lock_write(&main.thread->lock.rule);
+
+ if (controller_rule_find(process->rule.alias, main.setting->rules, &id_rule) == F_true) {
+ main.setting->rules.array[id_rule].status = status;
+ }
+
+ f_thread_unlock(&main.thread->lock.rule);
+
+ f_thread_unlock(&process->lock);
+ f_thread_lock_write(&process->lock);
+
if (asynchronous) {
process->state = controller_process_state_done;
}
process->stack.used = used_original_stack;
f_thread_unlock(&process->lock);
- f_thread_unlock(&process->active);
+ if (asynchronous) f_thread_unlock(&process->active);
if (main.thread->enabled) {
if (F_status_is_error(status)) {
controller_rule_item_error_print(main.data->error, cache->action, for_item, main.thread);
- rule->status = controller_status_simplify(F_status_set_fine(status));
+ rule->status = controller_status_simplify_error(F_status_set_fine(status));
return F_false;
}
/**
* Perform an execution of the given rule.
*
+ * This requires that a read lock be set on process->lock before being called.
+ *
* @param action
* The action to perform based on the action type codes.
*
/**
* Perform an execution of the given rule in the foreground.
*
+ * This requires that a read lock be set on process->lock before being called.
+ *
* @param type
* The item type code.
* @param action
/**
* Perform an execution of the given rule in the foreground or background and creating a PID file.
*
+ * This requires that a read lock be set on process->lock before being called.
+ *
* When this is synchronous, this will wait for the PID file to be generated before continuing.
* When this is asynchronous, this will continue on adding the rule id and action to the asynchronous list.
*
* Any dependent rules are processed and executed as per "need", "want", and "wish" rule settings.
* All dependent rules must be already loaded, this function will not load any rules.
*
- * @fixme recursion is no longer happening is it?
+ * This requires that a read lock be set on process->lock before being called.
+ *
* This function is recursively called for each "need", "want", and "wish", and has a max recursion length of the max size of the f_array_lengths_t array.
*
+ * The rule status will be updated by this function.
+ *
* @param action
* The action to perform based on the action type codes.
*
* - controller_rule_action_type_restart
* - controller_rule_action_type_start
* - controller_rule_action_type_stop
- * @param options
- * A number using bits to represent specific boolean options.
- * If no bits set, then operate normally in a synchronous manner.
- * If bit controller_rule_option_simulate, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
- * If bit controller_rule_option_asynchronous, then run asynchronously.
* @param main
* The main data.
* @param process
* F_signal on (exit) signal received.
*/
#ifndef _di_controller_rule_process_
- extern f_status_t controller_rule_process(const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
+ extern f_status_t controller_rule_process(const uint8_t action, const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_process_
/**
const controller_main_t *main = (controller_main_t *) arguments;
+ if (!main->thread->enabled) f_thread_exit(0);
+
const unsigned int interval = main->data->parameters[controller_parameter_test].result == f_console_result_found ? controller_thread_cleanup_interval_short : controller_thread_cleanup_interval_long;
while (main->thread->enabled) {
if (process->id_thread) {
f_thread_join(process->id_thread, 0);
+
+ f_thread_lock_write(&process->lock);
+
process->state = controller_process_state_idle;
process->id_thread = 0;
+
+ f_thread_unlock(&process->lock);
}
// deallocate dynamic portions of the structure that are only ever needed while the process is running.
if (process->id_thread) {
f_thread_join(process->id_thread, 0);
+
+ f_thread_lock_write(&process->lock);
+
process->state = controller_process_state_idle;
process->id_thread = 0;
+
+ f_thread_unlock(&process->lock);
}
// deallocate dynamic portions of the structure that are only ever needed while the rule is being processed.
}
} // while
- return 0;
+ f_thread_exit(0);
}
#endif // _di_controller_thread_cleanup_
controller_main_t *main = (controller_main_t *) arguments;
- return 0;
+ if (!main->thread->enabled) f_thread_exit(0);
+
+ f_thread_exit(0);
}
#endif // _di_controller_thread_control_
controller_main_t *main = (controller_main_t *) arguments;
- sleep(controller_thread_exit_force_timeout);
+ f_thread_lock_read(&main->thread->lock.process);
- for (f_array_length_t i = 0; i < main->thread->processs.used; ++i) {
+ // @todo redesign this to use timed waits, that include a counter and a max wait such that when max wait is reached, send kill signals.
+ // this would, in theory, allow faster exits without as much waiting when there is nothing to wait for.
- if (main->thread->processs.array[i].child > 0) {
- f_signal_send(F_signal_kill, main->thread->processs.array[i].child);
- }
+ if (main->thread->processs.used) {
+ f_thread_unlock(&main->thread->lock.process);
- if (main->thread->processs.array[i].id_thread) {
- f_thread_signal(main->thread->processs.array[i].id_thread, F_signal_kill);
- }
- } // for
+ usleep(controller_thread_exit_process_force_timeout);
+ f_thread_lock_read(&main->thread->lock.process);
+
+ for (f_array_length_t i = 0; i < main->thread->processs.used; ++i) {
+
+ if (main->thread->processs.array[i].child > 0) {
+ f_signal_send(F_signal_kill, main->thread->processs.array[i].child);
+ }
+
+ if (main->thread->processs.array[i].id_thread) {
+ f_thread_signal(main->thread->processs.array[i].id_thread, F_signal_kill);
+ }
+ } // for
+ }
+
+ f_thread_unlock(&main->thread->lock.process);
+
+ usleep(controller_thread_exit_main_force_timeout);
if (main->thread->id_cleanup) {
f_thread_signal(main->thread->id_cleanup, F_signal_kill);
f_thread_signal(main->thread->id_control, F_signal_kill);
}
- if (main->thread->id_signal) {
- f_thread_signal(main->thread->id_signal, F_signal_kill);
- }
-
if (main->thread->id_rule) {
f_thread_signal(main->thread->id_rule, F_signal_kill);
}
- return 0;
+ f_thread_exit(0);
}
#endif // _di_controller_thread_exit_force_
}
if (F_status_is_error(status)) {
+ thread.id_signal = 0;
+
if (data->error.verbosity != f_console_verbosity_quiet) {
controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread);
}
else {
const controller_main_entry_t entry = controller_macro_main_entry_t_initialize(&entry_name, &main, setting);
+ // the entry processing runs using the rule thread.
status = f_thread_create(0, &thread.id_rule, &controller_thread_entry, (void *) &entry);
if (F_status_is_error(status)) {
else {
f_thread_join(thread.id_rule, 0);
+ thread.id_rule = 0;
status = thread.status;
}
}
}
- if (status != F_signal && thread.signal) {
- status = F_signal;
- }
-
// only make the rule and control threads available once any/all pre-processing and are completed.
- if (F_status_is_error_not(status) && status != F_signal && status != F_child) {
+ if (F_status_is_error_not(status) && status != F_signal && status != F_child && thread.enabled) {
+
+ if (data->parameters[controller_parameter_validate].result == f_console_result_none && thread.id_rule) {
+
+ // wait for the entry thread to complete before starting the rule thread.
+ f_thread_join(thread.id_rule, 0);
+
+ thread.id_rule = 0;
- if (data->parameters[controller_parameter_validate].result == f_console_result_none) {
- controller_rule_wait_all(main, 0);
+ if (thread.enabled) {
+ status = f_thread_create(0, &thread.id_rule, &controller_thread_rule, (void *) &main);
+ }
status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &main);
- if (F_status_is_error_not(status)) {
+ if (F_status_is_error(status)) {
+ thread.id_control = 0;
+ }
+ else {
status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &main);
}
if (F_status_is_error(status)) {
+ thread.id_cleanup = 0;
+
if (data->error.verbosity != f_console_verbosity_quiet) {
controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread);
}
}
if (F_status_is_error(status) || status == F_signal || !(data->parameters[controller_parameter_validate].result == f_console_result_none || data->parameters[controller_parameter_test].result == f_console_result_found)) {
- f_thread_cancel(thread.id_signal);
- f_thread_create(0, &thread.id_exit, &controller_thread_exit_force, (void *) &main);
- }
- // wait until signal thread exits, which happens on any termination signal.
- f_thread_join(thread.id_signal, 0);
+ if (status != F_signal && thread.id_signal) {
+ f_thread_cancel(thread.id_signal);
+ }
- if (thread.enabled) {
controller_thread_process_cancel(&main);
}
- f_thread_cancel(thread.id_cleanup);
- f_thread_cancel(thread.id_control);
- f_thread_cancel(thread.id_rule);
+ // wait until signal thread exits, which happens on any termination signal.
+ if (thread.id_signal) f_thread_join(thread.id_signal, 0);
- f_thread_join(thread.id_cleanup, 0);
- f_thread_join(thread.id_control, 0);
- f_thread_join(thread.id_rule, 0);
+ controller_thread_process_cancel(&main);
+
+ if (thread.id_cleanup) f_thread_cancel(thread.id_cleanup);
+ if (thread.id_control) f_thread_cancel(thread.id_control);
+ if (thread.id_rule) f_thread_cancel(thread.id_rule);
+
+ if (thread.id_cleanup) f_thread_join(thread.id_cleanup, 0);
+ if (thread.id_control) f_thread_join(thread.id_control, 0);
+ if (thread.id_rule) f_thread_join(thread.id_rule, 0);
// if made it here, then the threads no longer need to be killed.
f_thread_join(thread.id_exit, 0);
#ifndef _di_controller_thread_process_
void * controller_thread_process(void *arguments) {
- controller_rule_process_do(F_true, (controller_process_t *) arguments);
+ controller_process_t *process = (controller_process_t *) arguments;
+
+ {
+ controller_thread_t *thread = (controller_thread_t *) process->main_thread;
+
+ if (!thread->enabled) f_thread_exit(0);
+ }
+
+ controller_rule_process_do(F_true, process);
- return 0;
+ f_thread_exit(0);
}
#endif // _di_controller_thread_process_
#ifndef _di_controller_thread_process_cancel_
void controller_thread_process_cancel(controller_main_t *main) {
+ f_thread_lock_read(&main->thread->lock.process);
+
// only cancel when enabled.
- if (!main->thread->enabled) return;
+ if (!main->thread->enabled || main->thread->id_exit) {
+ f_thread_unlock(&main->thread->lock.process);
+
+ return;
+ }
// this must be set, regardless of lock state and only this function changes this.
main->thread->enabled = F_false;
- f_thread_lock_read(&main->thread->lock.process);
-
f_thread_create(0, &main->thread->id_exit, &controller_thread_exit_force, (void *) main);
controller_process_t *process = 0;
process = &main->thread->processs.array[i];
+ f_thread_lock_read(&process->lock);
+
if (process->child > 0) {
f_signal_send(F_signal_termination, process->child);
}
+ f_thread_unlock(&process->lock);
+ } // for
+
+ for (i = 0; i < main->thread->processs.used; ++i) {
+
+ process = &main->thread->processs.array[i];
+
+ f_thread_lock_read(&process->lock);
+
if (process->id_thread) {
f_thread_cancel(process->id_thread);
- f_thread_join(process->id_thread, 0);
-
- process->id_thread = 0;
}
+
+ f_thread_unlock(&process->lock);
} // for
- for (; i < main->thread->processs.size; ++i) {
+ for (i = 0; i < main->thread->processs.size; ++i) {
process = &main->thread->processs.array[i];
if (process->id_thread) {
- f_thread_cancel(process->id_thread);
f_thread_join(process->id_thread, 0);
+ f_thread_lock_write(&process->lock);
+
process->id_thread = 0;
+
+ f_thread_unlock(&process->lock);
}
} // for
void * controller_thread_entry(void *arguments) {
controller_main_entry_t *entry = (controller_main_entry_t *) arguments;
+
+ if (!entry->main->thread->enabled) f_thread_exit(0);
+
controller_data_t *data = entry->main->data;
controller_cache_t *cache = &entry->main->thread->cache;
f_status_t *status = &entry->main->thread->status;
}
}
- return 0;
+ f_thread_exit(0);
}
#endif // _di_controller_thread_entry_
controller_main_t *main = (controller_main_t *) arguments;
- return 0;
+ if (!main->thread->enabled) f_thread_exit(0);
+
+ f_thread_exit(0);
}
#endif // _di_controller_thread_rule_
controller_main_t *main = (controller_main_t *) arguments;
+ if (!main->thread->enabled) f_thread_exit(0);
+
for (int signal = 0; main->thread->enabled; ) {
sigwait(&main->data->signal.set, &signal);
if (main->data->parameters[controller_parameter_interruptable].result == f_console_result_found) {
if (signal == F_signal_interrupt || signal == F_signal_abort || signal == F_signal_quit || signal == F_signal_termination) {
- main->thread->signal = signal;
+ main->thread->signal = signal; // @todo determine if I need signal saved anymore.
controller_thread_process_cancel(main);
break;
}
} // for
- return 0;
+ f_thread_exit(0);
}
#endif // _di_controller_thread_signal_
start {
\#!/bin/bash
my_function() {
- echo "Hello this is the second script."
+ echo "Hello this is the last script."
return 1;
\}