Add a read/write `signal` lock property to the locks.
Use read and write locks on `signal` and `signal_received` as appropriate.
}
if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) {
- main->thread.signal = information.si_signo;
+ controller_thread_signal_set(&main->thread, information.si_signo);
f_thread_condition_signal_all(&main->thread.lock.reap_condition);
+
controller_thread_instance_cancel(main, is_normal, controller_thread_cancel_signal_e);
break;
* The print lock is intended to lock any activity printing to stdout/stderr.
* The instance lock is intended to lock any activity on the instance structure.
* The rule lock is intended to lock any activity on the rules structure.
+ * The signal lock is intended to lock any activity on the thread.signal and the program signal_received properties.
*
* Properties:
* - flag: A set of flags associated with the locks.
* - enable: The enable r/w lock.
* - instance: The instance r/w lock.
* - rule: The rule r/w lock.
+ * - signal: The signal r/w lock.
* - alert_condition: The condition used to trigger alerts.
* - reap_condition: The condition used to trigger zombie reaping.
*/
f_thread_lock_t enable;
f_thread_lock_t instance;
f_thread_lock_t rule;
+ f_thread_lock_t signal;
f_thread_condition_t alert_condition;
f_thread_condition_t reap_condition;
f_thread_lock_t_initialize, \
f_thread_lock_t_initialize, \
f_thread_lock_t_initialize, \
+ f_thread_lock_t_initialize, \
f_thread_condition_t_initialize, \
f_thread_condition_t_initialize, \
}
fll_program_print_copyright(&main->program.message, fll_program_copyright_year_author_s);
}
+ // Threads are not enabled at this point so it is safe to directly access signal_received.
if (main->program.signal_received) {
fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
}
if (F_status_set_fine(status) == F_interrupt) {
status = F_status_set_error(F_interrupt);
+ // No threads are enabled, so it should be safe to access thread.signal and alter signal_received.
if (main->thread.signal) {
main->program.signal_received = main->thread.signal;
}
status = F_status_is_error(status) ? F_status_set_error(F_failure) : F_okay;
}
+ // No threads are enabled, so it should be safe to alter signal_received.
if (main->program.signal_received) {
fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
}
}
// Reaping child processes is not critical, so don't care if the reap flag cannot be unset.
- if (!main->thread.signal && F_status_is_error_not(status)) {
+ if (!controller_thread_signal_get(&main->thread) && F_status_is_error_not(status)) {
memset((void *) &signal_data, 0, sizeof(siginfo_t));
reap_count = 0;
return;
}
- for (; i < main->thread.instances.used; ++i) {
+ for (int signal = 0; i < main->thread.instances.used; ++i) {
if (!main->thread.instances.array[i]) continue;
for (j = 0; j < instance->childs.used; ++j) {
if (instance->childs.array[j] > 0) {
- f_signal_send(main->thread.signal ? main->thread.signal : F_signal_termination, instance->childs.array[j]);
+ signal = controller_thread_signal_get(&main->thread);
+
+ f_signal_send(signal ? signal : F_signal_termination, instance->childs.array[j]);
}
} // for
status = controller_file_pid_read(instance->path_pids.array[j], &pid);
if (pid) {
- f_signal_send(main->thread.signal ? main->thread.signal : F_signal_termination, pid);
+ signal = controller_thread_signal_get(&main->thread);
+
+ f_signal_send(signal ? signal : F_signal_termination, pid);
}
}
} // for
}
if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) {
- main->thread.signal = information.si_signo;
+ controller_thread_signal_set(&main->thread, information.si_signo);
f_thread_condition_signal_all(&main->thread.lock.reap_condition);
+
controller_thread_instance_cancel(main, is_normal, controller_thread_cancel_signal_e);
break;
}
#endif // _di_controller_thread_signal_
+#ifndef _di_controller_thread_signal_get_
+ int controller_thread_signal_get(controller_thread_t * const thread) {
+
+ if (!thread) return 0;
+
+ if (f_thread_lock_read_try(&thread->lock.signal) != F_okay) {
+ for (f_time_spec_t time; ; ) {
+
+ memset(&time, 0, sizeof(f_time_spec_t));
+
+ controller_time_now(controller_thread_timeout_lock_read_seconds_d, controller_thread_timeout_lock_read_nanoseconds_d, &time);
+ if (f_thread_lock_read_timed(&time, &thread->lock.signal) == F_okay) break;
+ } // for
+ }
+
+ const int signal = thread->signal;
+
+ f_thread_unlock(&thread->lock.signal);
+
+ return signal;
+ }
+#endif // _di_controller_thread_signal_get_
+
+#ifndef _di_controller_thread_signal_received_set_
+ f_status_t controller_thread_signal_received_set(controller_t * const main, const uint32_t value) {
+
+ if (!main) return F_status_set_error(F_parameter);
+
+ if (f_thread_lock_write_try(&main->thread.lock.signal) != F_okay) {
+ for (f_time_spec_t time; ; ) {
+
+ memset(&time, 0, sizeof(f_time_spec_t));
+
+ controller_time_now(controller_thread_timeout_lock_write_seconds_d, controller_thread_timeout_lock_write_nanoseconds_d, &time);
+ if (f_thread_lock_write_timed(&time, &main->thread.lock.signal) == F_okay) break;
+ } // for
+ }
+
+ main->program.signal_received = value;
+
+ f_thread_unlock(&main->thread.lock.signal);
+
+ return F_okay;
+ }
+#endif // _di_controller_thread_signal_received_set_
+
+#ifndef _di_controller_thread_signal_set_
+ f_status_t controller_thread_signal_set(controller_thread_t * const thread, const int value) {
+
+ if (!thread) return F_status_set_error(F_parameter);
+
+ if (f_thread_lock_write_try(&thread->lock.signal) != F_okay) {
+ for (f_time_spec_t time; ; ) {
+
+ memset(&time, 0, sizeof(f_time_spec_t));
+
+ controller_time_now(controller_thread_timeout_lock_write_seconds_d, controller_thread_timeout_lock_write_nanoseconds_d, &time);
+ if (f_thread_lock_write_timed(&time, &thread->lock.signal) == F_okay) break;
+ } // for
+ }
+
+ thread->signal = value;
+
+ f_thread_unlock(&thread->lock.signal);
+
+ return F_okay;
+ }
+#endif // _di_controller_thread_signal_set_
+
#ifndef _di_controller_thread_signal_state_fss_
void controller_thread_signal_state_fss(f_state_t * const state, void * const internal) {
if (!interrupt->main) return;
if (!controller_thread_enable_is(&interrupt->main->thread, interrupt->is_normal)) {
- interrupt->main->program.signal_received = F_signal_abort;
+ controller_thread_signal_received_set(interrupt->main, F_signal_abort);
}
- else if (interrupt->main->thread.signal == F_signal_interrupt || interrupt->main->thread.signal == F_signal_abort || interrupt->main->thread.signal == F_signal_quit || interrupt->main->thread.signal == F_signal_termination) {
- interrupt->main->program.signal_received = F_signal_abort;
+ else {
+ const int signal = controller_thread_signal_get(&interrupt->main->thread);
+
+ if (signal == F_signal_interrupt || signal == F_signal_abort || signal == F_signal_quit || signal == F_signal_termination) {
+ controller_thread_signal_received_set(interrupt->main, F_signal_abort);
+ }
}
}
#endif // _di_controller_thread_signal_state_fss_
if (!interrupt->main) return;
if (!controller_thread_enable_is(&interrupt->main->thread, interrupt->is_normal)) {
- interrupt->main->program.signal_received = F_signal_abort;
+ controller_thread_signal_received_set(interrupt->main, F_signal_abort);
}
- else if (interrupt->main->thread.signal == F_signal_interrupt || interrupt->main->thread.signal == F_signal_abort || interrupt->main->thread.signal == F_signal_quit || interrupt->main->thread.signal == F_signal_termination) {
- interrupt->main->program.signal_received = F_signal_abort;
+ else {
+ const int signal = controller_thread_signal_get(&interrupt->main->thread);
+
+ if (signal == F_signal_interrupt || signal == F_signal_abort || signal == F_signal_quit || signal == F_signal_termination) {
+ controller_thread_signal_received_set(interrupt->main, F_signal_abort);
+ }
}
}
#endif // _di_controller_thread_signal_state_iki_
#endif // _di_controller_thread_signal_
/**
+ * Get the signal state of the thread in a thread-safe manner.
+ *
+ * This infinitely tries to obtain the read lock.
+ *
+ * Locks used on run:
+ * - main.thread.lock.signal (read lock).
+ *
+ * Locks held on exit:
+ * - None.
+ *
+ * @param thread
+ * The thread data.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * The current signal code.
+ *
+ * @see controller_time_now()
+ *
+ * @see f_thread_lock_read_timed()
+ * @see f_thread_lock_read_try()
+ * @see f_thread_unlock()
+ */
+#ifndef _di_controller_thread_signal_get_
+ extern int controller_thread_signal_get(controller_thread_t * const thread);
+#endif // _di_controller_thread_signal_get_
+
+/**
+ * Set the signal received of the main program in a thread-safe manner.
+ *
+ * This infinitely tries to obtain the write lock.
+ *
+ * Locks used on run:
+ * - main.thread.lock.signal (write lock).
+ *
+ * Locks held on exit:
+ * - None.
+ *
+ * @param main
+ * The main program data.
+ *
+ * Must not be NULL.
+ *
+ * This does not alter main.setting.state.status.
+ * @param value
+ * The new value to assign to the thread signal.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_parameter (with error bit) if a parmeter is invalid.
+ *
+ * @see f_thread_lock_write_timed()
+ * @see f_thread_lock_write_try()
+ * @see f_thread_unlock()
+ */
+#ifndef _di_controller_thread_signal_received_set_
+ extern f_status_t controller_thread_signal_received_set(controller_t * const main, const uint32_t value);
+#endif // _di_controller_thread_signal_received_set_
+
+/**
+ * Set the signal of the thread in a thread-safe manner.
+ *
+ * This infinitely tries to obtain the write lock.
+ *
+ * Locks used on run:
+ * - main.thread.lock.signal (write lock).
+ *
+ * Locks held on exit:
+ * - None.
+ *
+ * @param thread
+ * The thread data.
+ *
+ * Must not be NULL.
+ * @param value
+ * The new value to assign to the thread signal.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_parameter (with error bit) if a parmeter is invalid.
+ *
+ * @see f_thread_lock_write_timed()
+ * @see f_thread_lock_write_try()
+ * @see f_thread_unlock()
+ */
+#ifndef _di_controller_thread_signal_set_
+ extern f_status_t controller_thread_signal_set(controller_thread_t * const thread, const int value);
+#endif // _di_controller_thread_signal_set_
+
+/**
* Callback passed to FSS functions for checking for interrupts.
*
* @param state