f_status_t controller_lock_write(controller_thread_t * const thread, f_thread_lock_t *lock) {
struct timespec time;
- time.tv_sec = 0;
- time.tv_nsec = controller_thread_lock_timeout;
f_status_t status = F_none;
for (;;) {
+
+ controller_time(0, controller_thread_lock_timeout, &time);
+
status = f_thread_lock_write_timed(&time, lock);
if (status == F_time) {
#endif // _di_controller_process_delete_simple_
#ifndef _di_controller_process_wait_
- void controller_process_wait(const controller_main_t main, controller_process_t *process) {
+ f_status_t controller_process_wait(const controller_main_t main, controller_process_t *process) {
- if (!main.thread->enabled) return;
+ if (!main.thread->enabled) {
+ return F_signal;
+ }
struct timespec time;
- time.tv_sec = controller_thread_wait_timeout_seconds;
- time.tv_nsec = controller_thread_wait_timeout_nanoseconds;
f_status_t status = F_none;
do {
f_thread_mutex_lock(&process->wait_lock);
+ controller_time(controller_thread_wait_timeout_seconds, controller_thread_wait_timeout_nanoseconds, &time);
+
status = f_thread_condition_wait_timed(&time, &process->wait, &process->wait_lock);
f_thread_mutex_unlock(&process->wait_lock);
- if (!main.thread->enabled) break;
+ if (!main.thread->enabled) {
+ return F_signal;
+ }
f_thread_lock_read(&process->lock);
if (process->status != F_known_not || !(process->state == controller_process_state_active || process->state == controller_process_state_busy)) {
f_thread_unlock(&process->lock);
- break;
+ return F_none;
}
f_thread_unlock(&process->lock);
- } while (main.thread->enabled);
+ } while (status == F_time && main.thread->enabled);
+
+ return status;
}
#endif // _di_controller_process_wait_
processs->size = length;
return status;
}
+ else {
+ process->status = F_known_not;
+ process->rule.status = F_known_not;
+ }
} // for
processs->size = length;
}
#endif // _di_controller_thread_delete_simple_
+#ifndef _di_controller_time_
+ void controller_time(const time_t seconds, const long nanos, struct timespec *time) {
+
+ struct timeval now;
+
+ gettimeofday(&now, 0);
+
+ time->tv_sec = now.tv_sec + seconds;
+ time->tv_nsec = now.tv_usec * 1000 + nanos;
+ }
+#endif // _di_controller_time_
+
#ifdef __cplusplus
} // extern "C"
#endif
#define controller_thread_exit_process_cancel_total 150 // 9 seconds in multiples of wait.
#define controller_thread_lock_timeout 100000000 // 0.1 seconds in nanoseconds.
#define controller_thread_simulation_timeout 200000 // 0.2 seconds in microseconds.
- #define controller_thread_wait_timeout_seconds 10
+
+ // @todo implement a staged incrementing wait that waits a short amount of time for say 3 times, then waits a longer amount of time for say 3 times, and then wait a long period of time.
+ // example: wait 0.02 seconds for 4 times, then
+ // wait 0.2 seconds for 8 times, then
+ // wait 2 seconds for 16 times, then
+ // wait 20 seconds for every time thereafter.
+ #define controller_thread_wait_timeout_seconds 5
#define controller_thread_wait_timeout_nanoseconds 0
typedef struct {
* @param process
* The process to wait on.
*
+ * @return
+ * F_none on success.
+ * F_signal on success and signal found.
+ *
+ * Success from f_thread_condition_wait_timed().
+ *
+ * Errors (with error bit) from: f_thread_condition_wait_timed().
+ *
* @see f_thread_condition_wait_timed()
*/
#ifndef _di_controller_process_wait_
- extern void controller_process_wait(const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
+ extern f_status_t controller_process_wait(const controller_main_t main, controller_process_t *process) f_gcc_attribute_visibility_internal;
#endif // _di_controller_process_wait_
/**
extern void controller_thread_delete_simple(controller_thread_t *thread) f_gcc_attribute_visibility_internal;
#endif // _di_controller_thread_delete_simple_
+/**
+ * Get the current time, plus the given offset.
+ *
+ * @todo this is basic enough that there needs to be an f_time class with this function f_time_now(), f_time_future(), f_time_past().
+ * "struct timespec" -> f_time_nano_t, "struct timeval" -> f_time_micro_t.
+ *
+ * @param seconds
+ * The seconds to add to current time.
+ * @param nanos
+ * The nanoseconds to add to current time.
+ * @param time
+ * The resulting current time.
+ */
+#ifndef _di_controller_time_
+ void controller_time(const time_t seconds, const long nanos, struct timespec *time) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_time_
+
#ifdef __cplusplus
} // extern "C"
#endif
f_array_length_t k = 0;
f_array_length_t id_rule = 0;
f_array_length_t id_process = 0;
+
bool found = F_false;
+ bool busy = F_false;
controller_process_t *process_other = 0;
+ uint8_t rule_options = 0;
+
f_string_dynamics_t * const dynamics[] = {
&process->rule.need,
&process->rule.want,
for (j = 0; j < dynamics[i]->used; ++j) {
+ process_other = 0;
+ found = F_false;
+
f_thread_lock_read(&main.thread->lock.process);
status = controller_find_process(dynamics[i]->array[j], main.thread->processs, &id_process);
+ if (status == F_true) {
+ process_other = main.thread->processs.array[id_process];
+
+ f_thread_lock_read(&process_other->active);
+ }
+
f_thread_unlock(&main.thread->lock.process);
if (status == F_true) {
if (!(process->options & controller_rule_option_simulate)) {
f_thread_unlock(&main.thread->lock.rule);
+ if (process_other) {
+ f_thread_unlock(&process_other->active);
+ }
+
break;
}
}
controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
}
}
-
- f_thread_unlock(&main.thread->lock.rule);
+ }
+ else {
+ f_thread_lock_read(&main.thread->lock.rule);
}
- f_thread_lock_read(&main.thread->lock.rule);
+ if (found) {
- if (status == F_true && found) {
- f_thread_unlock(&main.thread->lock.rule);
- f_thread_lock_read(&main.thread->lock.process);
+ // the process_other may have write locks, which needs to be avoided, so copy the alias from the rule.
+ char alias_other_buffer[main.setting->rules.array[id_rule].alias.used + 1];
- process_other = main.thread->processs.array[id_process];
+ memcpy(alias_other_buffer, main.setting->rules.array[id_rule].alias.string, sizeof(char) * main.setting->rules.array[id_rule].alias.used);
+ alias_other_buffer[main.setting->rules.array[id_rule].alias.used] = 0;
- f_thread_lock_read(&process_other->active);
- f_thread_lock_read(&process_other->lock);
+ const f_string_static_t alias_other = f_macro_string_static_t_initialize(alias_other_buffer, main.setting->rules.array[id_rule].alias.used);
- if (process_other->status == F_known_not && (process_other->state == controller_process_state_active || process_other->state == controller_process_state_busy)) {
- f_thread_unlock(&process_other->lock);
+ f_thread_unlock(&main.thread->lock.rule);
- controller_process_wait(main, process_other);
+ busy = F_false;
+
+ status = f_thread_lock_read_try(&process_other->lock);
+
+ if (status == F_busy) {
+ busy = F_true;
}
else {
+ if (process_other->status == F_known_not || process_other->state == controller_process_state_active || process_other->state == controller_process_state_busy) {
+ busy = F_true;
+ }
+
f_thread_unlock(&process_other->lock);
}
- f_thread_unlock(&main.thread->lock.process);
-
- if (!main.thread->enabled) {
- f_thread_unlock(&process_other->active);
-
- status = F_signal;
- break;
+ if (busy) {
+ controller_process_wait(main, process_other);
}
+ else {
+ rule_options = 0;
- f_thread_lock_read(&main.thread->lock.rule);
-
- char alias_other_buffer[main.setting->rules.array[id_rule].alias.used + 1];
-
- memcpy(alias_other_buffer, main.setting->rules.array[id_rule].alias.string, sizeof(char) * main.setting->rules.array[id_rule].alias.used);
- alias_other_buffer[main.setting->rules.array[id_rule].alias.used] = 0;
-
- // attempt to (synchronously) execute the rule when the status is unknown (the rule has not yet been run).
- 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);
-
- f_thread_unlock(&main.thread->lock.rule);
+ if (main.data->parameters[controller_parameter_test].result == f_console_result_found) {
+ rule_options |= controller_rule_option_simulate;
+ }
- status = controller_rule_process_begin(controller_process_option_execute, alias_other, action, process->options & controller_rule_option_asynchronous ? process->options - controller_rule_option_asynchronous : process->options, process->stack, main, process->cache);
+ // synchronously execute dependency.
+ status = controller_rule_process_begin(controller_process_option_execute, alias_other, controller_rule_action_type_start, controller_process_option_execute, process->stack, main, process_other->cache);
if (status == F_child || status == F_signal) {
f_thread_unlock(&process_other->active);
controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
- if (!(process->options & controller_rule_option_simulate) || F_status_set_fine(status) == F_memory_not) {
+ if (!(process_other->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);
+ if (!main.thread->enabled) {
+ f_thread_unlock(&process_other->active);
+
+ break;
}
+ f_thread_lock_read(&main.thread->lock.rule);
+
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);
controller_print_unlock_flush(main.data->output.stream, &main.thread->lock.print);
- if (!(process->options & controller_rule_option_simulate)) {
+ if (!(process_other->options & controller_rule_option_simulate)) {
f_thread_unlock(&main.thread->lock.rule);
- f_thread_unlock(&process_other->active);
+
+ if (process_other) {
+ f_thread_unlock(&process_other->active);
+ }
+
break;
}
}
}
f_thread_unlock(&main.thread->lock.rule);
- f_thread_unlock(&process_other->active);
}
else {
f_thread_unlock(&main.thread->lock.rule);
}
+ if (process_other) {
+ f_thread_unlock(&process_other->active);
+ }
+
if (!main.thread->enabled) break;
} // for
return F_signal;
}
- if (!(process->options & controller_rule_option_wait) && F_status_is_error_not(status)) {
- controller_rule_wait_all(main, process);
+ if ((process->options & controller_rule_option_wait) && F_status_is_error_not(status)) {
+ controller_rule_wait_all(main, process); // @fixme review this, it needs to check anything depending on itself!
if (!main.thread->enabled) {
return F_signal;
process->stack.used = used_original_stack;
+ // inform all things waiting that the process has finished running.
+ f_thread_mutex_lock(&process->wait_lock);
+ f_thread_condition_signal_all(&process->wait);
+ f_thread_mutex_unlock(&process->wait_lock);
+
f_thread_unlock(&process->lock);
if (options & controller_process_option_asynchronous) {
}
if (main.thread->enabled) {
- if (options & controller_process_option_execute) {
-
- // inform all things waiting that the process has finished running.
- f_thread_mutex_lock(&process->wait_lock);
- f_thread_condition_signal_all(&process->wait);
- f_thread_mutex_unlock(&process->wait_lock);
- }
- }
- else {
- return F_signal;
+ return status;
}
- return status;
+ return F_signal;
}
#endif // _di_controller_rule_process_do_
if (caller) {
f_thread_lock_read(&main.thread->lock.rule);
- for (j = 0; j < caller->stack.used; ++j) {
+ for (j = 0; j < caller->stack.used && main.thread->enabled; ++j) {
if (main.thread->processs.array[caller->stack.array[j]] && fl_string_dynamic_compare(process->rule.alias, main.thread->processs.array[caller->stack.array[j]]->rule.alias) == F_equal_to) {
skip = F_true;
f_thread_unlock(&main.thread->lock.rule);
+ if (!main.thread->enabled) break;
if (skip) continue;
}
}
if (process->state == controller_process_state_done) {
- f_thread_unlock(&process->active);
-
if (f_thread_lock_write_try(&process->active) == F_none) {
f_thread_join(process->id_thread, 0);
+
process->state = controller_process_state_idle;
process->id_thread = 0;
}
- else {
- f_thread_lock_read(&process->active);
- }
}
}