Replace the `fll_program_standard_set_up()` call with a custom signal setup call (`controller_signal_set_up()`).
Both the init and controller programs might as well use the same signals.
The controller program should reap its own children too, even if it is not an init program.
Use a thread condition signal to communicate to the clean up thread to perform zombie reaping.
Add missing delete in the init program.
Make sure all condition signals have proper checking around the success/failure of the condition listener.
Make sure all condition broadcasts lock before sending the signal and unlocks after.
This too must be checked for success.
Send a reap condition signal to wake up the clean up thread before cancelling the instance.
Add custom thread names using recently added thread naming FLL functions.
This should make analysis and observation of threads at runtime far easier.
The clean up thread is now located sooner in the process so that the zombie reaping may be processed during entry operations.
This should allow for the init/controller programs to receive the signals.
The init program is not yet written to do anything with them yet.
I tested the serial test like this:
```
controller -s data/data/controller/example/miscellaneous/ serial
```
I noticed that the interrupt signal before the wait is reached causes the program to exit.
Once the wait is reached and an interrupt is then sent then the exit process is started before exiting.
I remember being uncertain how to handle this and left that logic to future decisions.
As of now I believe that the exit process should always be called on interrupt.
This should be addressed ideally along with this shutdown/reboot handle or at the very least immediately after that.
//#define _di_fll_program_signal_check_simple_
//#define _di_fll_program_signal_d_
//#define _di_fll_program_standard_set_down_
-//#define _di_fll_program_standard_set_up_
+#define _di_fll_program_standard_set_up_
//#define _di_fll_program_standard_signal_handle_
#define _di_fll_program_standard_signal_received_
//#define _di_fll_program_standard_signal_received_wait_
data.setting.flag |= controller_main_flag_interruptible_d;
- fll_program_standard_set_up(&data.program);
+ controller_signal_set_up(&data);
f_file_umask_get(&data.program.umask);
data.process.mode = controller_process_mode_service_e;
data.setting.flag |= controller_main_flag_interruptible_d;
- controller_init_signal_set_up(&data);
+ controller_signal_set_up(&data);
f_file_umask_get(&data.program.umask);
controller_process(&data);
+ controller_delete(&data);
+
fll_program_standard_set_down(&data.program);
if (data.setting.state.status == F_child) {
extern "C" {
#endif
-#ifndef _di_controller_init_signal_set_up_
- f_status_t controller_init_signal_set_up(controller_t * const main) {
-
- if (!main) return F_status_set_error(F_parameter);
-
- f_signal_set_empty(&main->program.signal.set);
- f_signal_set_add(F_signal_abort, &main->program.signal.set);
- f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set);
- f_signal_set_add(F_signal_child, &main->program.signal.set);
- f_signal_set_add(F_signal_continue, &main->program.signal.set);
- f_signal_set_add(F_signal_hangup, &main->program.signal.set);
- f_signal_set_add(F_signal_interrupt, &main->program.signal.set);
- f_signal_set_add(F_signal_keyboard_stop, &main->program.signal.set);
- f_signal_set_add(F_signal_power_failure, &main->program.signal.set);
- f_signal_set_add(F_signal_quit, &main->program.signal.set);
- f_signal_set_add(F_signal_stop, &main->program.signal.set);
- f_signal_set_add(F_signal_termination, &main->program.signal.set);
- f_signal_set_add(F_signal_user_1, &main->program.signal.set);
- f_signal_set_add(F_signal_user_2, &main->program.signal.set);
-
- f_status_t status = f_signal_mask(SIG_BLOCK, &main->program.signal.set, 0);
- if (F_status_is_error(status)) return status;
-
- status = f_signal_open(&main->program.signal);
-
- // If there is an error opening a signal descriptor, then do not handle signals.
- if (F_status_is_error(status)) {
- f_signal_mask(SIG_UNBLOCK, &main->program.signal.set, 0);
- f_signal_close(&main->program.signal);
-
- return status;
- }
-
- // Unblock all other signals.
- memset(&main->program.signal.set, 0, sizeof(sigset_t));
-
- f_signal_set_fill(&main->program.signal.set);
- f_signal_set_delete(F_signal_abort, &main->program.signal.set);
- f_signal_set_delete(F_signal_broken_pipe, &main->program.signal.set);
- f_signal_set_delete(F_signal_child, &main->program.signal.set);
- f_signal_set_delete(F_signal_continue, &main->program.signal.set);
- f_signal_set_delete(F_signal_hangup, &main->program.signal.set);
- f_signal_set_delete(F_signal_interrupt, &main->program.signal.set);
- f_signal_set_delete(F_signal_keyboard_stop, &main->program.signal.set);
- f_signal_set_delete(F_signal_power_failure, &main->program.signal.set);
- f_signal_set_delete(F_signal_quit, &main->program.signal.set);
- f_signal_set_delete(F_signal_stop, &main->program.signal.set);
- f_signal_set_delete(F_signal_termination, &main->program.signal.set);
- f_signal_set_delete(F_signal_user_1, &main->program.signal.set);
- f_signal_set_delete(F_signal_user_2, &main->program.signal.set);
-
- status = f_signal_mask(SIG_UNBLOCK, &main->program.signal.set, 0);
- if (F_status_is_error(status)) return status;
-
- return F_okay;
- }
-#endif // _di_controller_init_signal_set_up_
-
#ifndef _di_controller_init_signal_thread_
void controller_init_signal_thread(controller_t * const main, const uint8_t is_normal) {
// Prevent thread from being interrupted and auto-cancelled.
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
- // Reap zombie processes.
- if (information.si_signo == F_signal_child) {
- // @todo verify that this process id is a valid child process.
- // @todo send F_signal_terminate first?
- // @todo a waitpid() needs to be performed to check to see how to handle the child signal.
- //f_signal_send(F_signal_kill, information.si_pid);
- // @todo move this to a function and identify any pid files and clear it from the process array (see calls like: status = controller_file_pid_read(instance->path_pids.array[j], &pid););
+ // Send F_signal_reserved_35 to cleanup process to reap child processes.
+ if (information.si_signo == F_signal_child || information.si_signo == F_signal_reserved_35) {
+
+ if (f_thread_mutex_lock(&main->thread.lock.reap) == F_okay) {
+ f_thread_condition_signal_all(&main->thread.lock.reap_condition);
+ f_thread_mutex_unlock(&main->thread.lock.reap);
+ }
+
+ continue;
}
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;
+ if (f_thread_mutex_lock_try(&main->thread.lock.reap) == F_okay) {
+ f_thread_condition_signal_all(&main->thread.lock.reap_condition);
+ f_thread_mutex_unlock(&main->thread.lock.reap);
+ }
+
controller_thread_instance_cancel(main, is_normal, controller_thread_cancel_signal_e);
break;
#endif
/**
- * Perform standard setup with custom signals.
- *
- * This is a modified version of fll_program_standard_set_up().
- *
- * @param main
- * The main program data.
- *
- * Must not be NULL.
- *
- * @return
- * F_okay on success.
- *
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * Errors (with error bit) from: f_signal_mask().
- * Errors (with error bit) from: f_signal_open().
- *
- * @see f_signal_mask()
- * @see f_signal_open()
- * @see f_signal_set_add()
- * @see f_signal_set_delete()
- * @see f_signal_set_empty()
- * @see f_signal_set_fill()
- */
-#ifndef _di_controller_init_signal_set_up_
- extern f_status_t controller_init_signal_set_up(controller_t * const main);
-#endif // _di_controller_init_signal_set_up_
-
-/**
* Thread for handling signals/interrupts for the init program.
*
* @param main
* Controller lock defines.
*
* controller_lock_*_d:
+ * - max_reap: The maximum number of processes to reap in one loop pass (currently the type is a uint8_t).
* - mutex_max_retry: The maximum amount of times to retry the mutex lock before giving up.
*/
#ifndef _di_controller_lock_d_
+ #define controller_lock_max_reap_d 100
#define controller_lock_mutex_max_retry_d 1000000
#endif // _di_controller_lock_d_
const f_string_static_t controller_rule_wished_s = macro_f_string_static_t_initialize_1(CONTROLLER_rule_wished_s, 0, CONTROLLER_rule_wished_s_length);
#endif // _di_controller_rule_s_
+#ifndef _di_controller_thread_s_
+ const f_string_static_t controller_thread_cleanup_s = macro_f_string_static_t_initialize_1(CONTROLLER_thread_cleanup_s, 0, CONTROLLER_thread_cleanup_s_length);
+ const f_string_static_t controller_thread_control_s = macro_f_string_static_t_initialize_1(CONTROLLER_thread_control_s, 0, CONTROLLER_thread_control_s_length);
+ const f_string_static_t controller_thread_entry_s = macro_f_string_static_t_initialize_1(CONTROLLER_thread_entry_s, 0, CONTROLLER_thread_entry_s_length);
+ const f_string_static_t controller_thread_instance_s = macro_f_string_static_t_initialize_1(CONTROLLER_thread_instance_s, 0, CONTROLLER_thread_instance_s_length);
+ const f_string_static_t controller_thread_rule_s = macro_f_string_static_t_initialize_1(CONTROLLER_thread_rule_s, 0, CONTROLLER_thread_rule_s_length);
+ const f_string_static_t controller_thread_signal_s = macro_f_string_static_t_initialize_1(CONTROLLER_thread_signal_s, 0, CONTROLLER_thread_signal_s_length);
+#endif // _di_controller_thread_s_
+
#ifdef __cplusplus
} // extern "C"
#endif
extern const f_string_static_t controller_rule_wished_s;
#endif // _di_controller_rule_s_
+/**
+ * The program thread name strings.
+ */
+#ifndef _di_controller_thread_s_
+ #define CONTROLLER_thread_cleanup_s "cleanup"
+ #define CONTROLLER_thread_control_s "control"
+ #define CONTROLLER_thread_entry_s "entry"
+ #define CONTROLLER_thread_instance_s "instance"
+ #define CONTROLLER_thread_rule_s "rule"
+ #define CONTROLLER_thread_signal_s "signal"
+
+ #define CONTROLLER_thread_cleanup_s_length 7
+ #define CONTROLLER_thread_control_s_length 7
+ #define CONTROLLER_thread_entry_s_length 5
+ #define CONTROLLER_thread_instance_s_length 8
+ #define CONTROLLER_thread_rule_s_length 4
+ #define CONTROLLER_thread_signal_s_length 6
+
+ extern const f_string_static_t controller_thread_cleanup_s;
+ extern const f_string_static_t controller_thread_control_s;
+ extern const f_string_static_t controller_thread_entry_s;
+ extern const f_string_static_t controller_thread_instance_s;
+ extern const f_string_static_t controller_thread_rule_s;
+ extern const f_string_static_t controller_thread_signal_s;
+#endif // _di_controller_thread_s_
+
#ifdef __cplusplus
} // extern "C"
#endif
f_thread_mutex_delete(&lock->alert);
f_thread_mutex_delete(&lock->cancel);
f_thread_mutex_delete(&lock->print);
+ f_thread_mutex_delete(&lock->reap);
f_thread_lock_delete(&lock->instance);
f_thread_lock_delete(&lock->rule);
f_thread_condition_delete(&lock->alert_condition);
+ f_thread_condition_delete(&lock->reap_condition);
lock->flag |= controller_lock_flag_setup_not_d;
}
* - alert: The alert mutex lock for waking up on alerts.
* - cancel: The cancel mutex lock for locking the cancel operation.
* - print: The print mutex lock.
+ * - reap: The reap_condition mutex lock.
* - instance: The instance r/w lock.
* - rule: The Rule r/w lock.
* - alert_condition: The condition used to trigger alerts.
+ * - reap_condition: The condition used to trigger zombie reaping.
*/
#ifndef _di_controller_lock_t_
typedef struct {
f_thread_mutex_t alert;
f_thread_mutex_t cancel;
f_thread_mutex_t print;
+ f_thread_mutex_t reap;
f_thread_lock_t instance;
f_thread_lock_t rule;
f_thread_condition_t alert_condition;
+ f_thread_condition_t reap_condition;
} controller_lock_t;
#define controller_lock_t_initialize { \
f_thread_mutex_t_initialize, \
f_thread_mutex_t_initialize, \
f_thread_mutex_t_initialize, \
+ f_thread_mutex_t_initialize, \
f_thread_lock_t_initialize, \
f_thread_lock_t_initialize, \
f_thread_condition_t_initialize, \
+ f_thread_condition_t_initialize, \
}
#endif // _di_controller_lock_t_
#include <program/controller/main/print/warning/rule/action.h>
#include <program/controller/main/print/warning/rule/item.h>
#include <program/controller/main/print/warning/rule/setting.h>
+#include <program/controller/main/signal.h>
#include <program/controller/main/status.h>
#include <program/controller/main/time.h>
#include <program/controller/main/thread/cleanup.h>
uint8_t count = 0;
do {
- f_thread_mutex_lock(&instance->wait_lock);
+ status = f_thread_mutex_lock(&instance->wait_lock);
- if (count < controller_thread_timeout_wait_1_before_d) {
- controller_time_now(controller_thread_timeout_wait_1_seconds_d, controller_thread_timeout_wait_1_nanoseconds_d, &time);
- }
- else if (count < controller_thread_timeout_wait_2_before_d) {
- controller_time_now(controller_thread_timeout_wait_2_seconds_d, controller_thread_timeout_wait_2_nanoseconds_d, &time);
- }
- else if (count < controller_thread_timeout_wait_3_before_d) {
- controller_time_now(controller_thread_timeout_wait_3_seconds_d, controller_thread_timeout_wait_3_nanoseconds_d, &time);
- }
- else {
- controller_time_now(controller_thread_timeout_wait_4_seconds_d, controller_thread_timeout_wait_4_nanoseconds_d, &time);
- }
+ if (status == F_okay) {
+ if (count < controller_thread_timeout_wait_1_before_d) {
+ controller_time_now(controller_thread_timeout_wait_1_seconds_d, controller_thread_timeout_wait_1_nanoseconds_d, &time);
+ }
+ else if (count < controller_thread_timeout_wait_2_before_d) {
+ controller_time_now(controller_thread_timeout_wait_2_seconds_d, controller_thread_timeout_wait_2_nanoseconds_d, &time);
+ }
+ else if (count < controller_thread_timeout_wait_3_before_d) {
+ controller_time_now(controller_thread_timeout_wait_3_seconds_d, controller_thread_timeout_wait_3_nanoseconds_d, &time);
+ }
+ else {
+ controller_time_now(controller_thread_timeout_wait_4_seconds_d, controller_thread_timeout_wait_4_nanoseconds_d, &time);
+ }
- status = f_thread_condition_wait_timed(&time, &instance->wait, &instance->wait_lock);
+ status = f_thread_condition_wait_timed(&time, &instance->wait, &instance->wait_lock);
- f_thread_mutex_unlock(&instance->wait_lock);
+ f_thread_mutex_unlock(&instance->wait_lock);
+ }
if (!controller_thread_is_enabled_instance(instance)) return F_status_set_error(F_interrupt);
if (F_status_is_error(status)) break;
status = f_thread_mutex_create(0, &lock->cancel);
- if (F_status_is_error(status)) {
- f_thread_mutex_delete(&lock->alert);
-
- return status;
- }
+ if (F_status_is_error_not(status)) {
+ status = f_thread_mutex_create(0, &lock->print);
- status = f_thread_mutex_create(0, &lock->print);
+ if (F_status_is_error_not(status)) {
+ status = f_thread_mutex_create(0, &lock->reap);
- if (F_status_is_error(status)) {
- f_thread_mutex_delete(&lock->alert);
- f_thread_mutex_delete(&lock->cancel);
+ if (F_status_is_error_not(status)) {
+ status = f_thread_lock_create(0, &lock->instance);
- return status;
- }
+ if (F_status_is_error_not(status)) {
+ status = f_thread_lock_create(0, &lock->rule);
- status = f_thread_lock_create(0, &lock->instance);
+ if (F_status_is_error_not(status)) {
+ status = f_thread_condition_create(0, &lock->alert_condition);
- if (F_status_is_error(status)) {
- f_thread_mutex_delete(&lock->alert);
- f_thread_mutex_delete(&lock->cancel);
- f_thread_mutex_delete(&lock->print);
+ if (F_status_is_error_not(status)) {
+ status = f_thread_condition_create(0, &lock->reap_condition);
- return status;
- }
+ if (F_status_is_error(status)) {
+ f_thread_condition_delete(&lock->alert_condition);
+ }
+ }
- status = f_thread_lock_create(0, &lock->rule);
+ if (F_status_is_error(status)) {
+ f_thread_lock_delete(&lock->rule);
+ }
+ }
- if (F_status_is_error(status)) {
- f_thread_mutex_delete(&lock->alert);
- f_thread_mutex_delete(&lock->cancel);
- f_thread_mutex_delete(&lock->print);
- f_thread_lock_delete(&lock->instance);
+ if (F_status_is_error(status)) {
+ f_thread_lock_delete(&lock->instance);
+ }
+ }
- return status;
- }
+ if (F_status_is_error(status)) {
+ f_thread_mutex_delete(&lock->reap);
+ }
+ }
+ if (F_status_is_error(status)) {
+ f_thread_mutex_delete(&lock->print);
+ }
+ }
- status = f_thread_condition_create(0, &lock->alert_condition);
+ if (F_status_is_error(status)) {
+ f_thread_mutex_delete(&lock->cancel);
+ }
+ }
if (F_status_is_error(status)) {
f_thread_mutex_delete(&lock->alert);
- f_thread_mutex_delete(&lock->cancel);
- f_thread_mutex_delete(&lock->print);
- f_thread_lock_delete(&lock->instance);
- f_thread_lock_delete(&lock->rule);
return status;
}
else {
status = f_thread_create(0, &main->thread.id_signal, &controller_thread_signal_normal, (void *) main);
+ if (F_status_is_error_not(status)) {
+ // Start the clean up thread so that it can handle any zombie reaping.
+ if (!(main->setting.flag & controller_main_flag_validate_d) && main->process.mode == controller_process_mode_service_e) {
+ if (!main->thread.id_cleanup) {
+ status = f_thread_create(0, &main->thread.id_cleanup, &controller_thread_cleanup, (void *) main);
+ }
+ }
+ }
+
if (F_status_is_error(status)) {
main->thread.id_signal = 0;
+ main->thread.id_cleanup = 0;
controller_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status);
}
if (F_status_is_error(status)) {
main->thread.id_rule = 0;
}
- else {
- status = f_thread_create(0, &main->thread.id_cleanup, &controller_thread_cleanup, (void *) main);
- }
if (F_status_is_error(status)) {
- main->thread.id_cleanup = 0;
-
controller_print_error_status(&main->program.error, macro_controller_f(f_thread_create), status);
}
}
if (instance->state == controller_instance_state_done_e) {
controller_thread_join(&instance->id_thread);
- f_thread_mutex_lock(&instance->wait_lock);
- f_thread_condition_signal_all(&instance->wait);
- f_thread_mutex_unlock(&instance->wait_lock);
+ if (f_thread_mutex_lock(&instance->wait_lock) == F_okay) {
+ f_thread_condition_signal_all(&instance->wait);
+ f_thread_mutex_unlock(&instance->wait_lock);
+ }
}
instance->id = at;
instance->state = controller_instance_state_idle_e;
}
- f_thread_mutex_lock(&instance->wait_lock);
- f_thread_condition_signal_all(&instance->wait);
- f_thread_mutex_unlock(&instance->wait_lock);
+ if (f_thread_mutex_lock(&instance->wait_lock) == F_okay) {
+ f_thread_condition_signal_all(&instance->wait);
+ f_thread_mutex_unlock(&instance->wait_lock);
+ }
f_thread_unlock(&instance->lock);
}
instance->state = (options_force & controller_instance_option_asynchronous_e) ? controller_instance_state_done_e : controller_instance_state_idle_e;
instance->stack.used = used_original_stack;
- // inform all things waiting that the instance has finished running.
- f_thread_mutex_lock(&instance->wait_lock);
- f_thread_condition_signal_all(&instance->wait);
- f_thread_mutex_unlock(&instance->wait_lock);
+ // Inform all things waiting that the instance has finished running.
+ if (f_thread_mutex_lock(&instance->wait_lock) == F_okay) {
+ f_thread_condition_signal_all(&instance->wait);
+ f_thread_mutex_unlock(&instance->wait_lock);
+ }
f_thread_unlock(&instance->lock);
f_thread_unlock(&instance_list[i]->active);
- f_thread_mutex_lock(&instance_list[i]->wait_lock);
- f_thread_condition_signal_all(&instance_list[i]->wait);
- f_thread_mutex_unlock(&instance_list[i]->wait_lock);
+ if (f_thread_mutex_lock(&instance_list[i]->wait_lock) == F_okay) {
+ f_thread_condition_signal_all(&instance_list[i]->wait);
+ f_thread_mutex_unlock(&instance_list[i]->wait_lock);
+ }
}
status_lock = controller_lock_read(is_normal, F_true, &main->thread, &instance_list[i]->active);
f_signal_set_empty(&main->program.signal.set);
f_signal_set_add(F_signal_abort, &main->program.signal.set);
f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set);
+ f_signal_set_add(F_signal_child, &main->program.signal.set);
+ f_signal_set_add(F_signal_continue, &main->program.signal.set);
f_signal_set_add(F_signal_hangup, &main->program.signal.set);
f_signal_set_add(F_signal_interrupt, &main->program.signal.set);
+ f_signal_set_add(F_signal_keyboard_stop, &main->program.signal.set);
+ f_signal_set_add(F_signal_power_failure, &main->program.signal.set);
f_signal_set_add(F_signal_quit, &main->program.signal.set);
+ f_signal_set_add(F_signal_stop, &main->program.signal.set);
f_signal_set_add(F_signal_termination, &main->program.signal.set);
+ f_signal_set_add(F_signal_user_1, &main->program.signal.set);
+ f_signal_set_add(F_signal_user_2, &main->program.signal.set);
+
+ // Explicitly support all free signals.
+ f_signal_set_add(F_signal_reserved_35, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_36, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_37, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_38, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_39, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_40, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_41, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_42, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_43, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_44, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_45, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_46, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_47, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_48, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_49, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_50, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_51, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_52, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_53, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_54, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_55, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_56, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_57, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_58, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_59, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_60, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_61, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_62, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_63, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_64, &main->program.signal.set);
fll_program_standard_signal_received_wait(&main->program, controller_signal_check_failsafe_d);
}
#endif // !defined(_di_controller_signal_handler_) && !defined(_di_thread_support_)
+#ifndef _di_controller_signal_set_up_
+ f_status_t controller_signal_set_up(controller_t * const main) {
+
+ if (!main) return F_status_set_error(F_parameter);
+
+ f_signal_set_empty(&main->program.signal.set);
+ f_signal_set_add(F_signal_abort, &main->program.signal.set);
+ f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set);
+ f_signal_set_add(F_signal_child, &main->program.signal.set);
+ f_signal_set_add(F_signal_continue, &main->program.signal.set);
+ f_signal_set_add(F_signal_hangup, &main->program.signal.set);
+ f_signal_set_add(F_signal_interrupt, &main->program.signal.set);
+ f_signal_set_add(F_signal_keyboard_stop, &main->program.signal.set);
+ f_signal_set_add(F_signal_power_failure, &main->program.signal.set);
+ f_signal_set_add(F_signal_quit, &main->program.signal.set);
+ f_signal_set_add(F_signal_stop, &main->program.signal.set);
+ f_signal_set_add(F_signal_termination, &main->program.signal.set);
+ f_signal_set_add(F_signal_user_1, &main->program.signal.set);
+ f_signal_set_add(F_signal_user_2, &main->program.signal.set);
+
+ // Explicitly support all free signals.
+ f_signal_set_add(F_signal_reserved_35, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_36, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_37, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_38, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_39, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_40, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_41, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_42, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_43, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_44, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_45, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_46, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_47, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_48, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_49, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_50, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_51, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_52, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_53, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_54, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_55, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_56, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_57, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_58, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_59, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_60, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_61, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_62, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_63, &main->program.signal.set);
+ f_signal_set_add(F_signal_reserved_64, &main->program.signal.set);
+
+ f_status_t status = f_signal_mask(SIG_BLOCK, &main->program.signal.set, 0);
+ if (F_status_is_error(status)) return status;
+
+ status = f_signal_open(&main->program.signal);
+
+ // If there is an error opening a signal descriptor, then do not handle signals.
+ if (F_status_is_error(status)) {
+ f_signal_mask(SIG_UNBLOCK, &main->program.signal.set, 0);
+ f_signal_close(&main->program.signal);
+
+ return status;
+ }
+
+ // Unblock all other signals.
+ memset(&main->program.signal.set, 0, sizeof(sigset_t));
+
+ f_signal_set_fill(&main->program.signal.set);
+ f_signal_set_delete(F_signal_abort, &main->program.signal.set);
+ f_signal_set_delete(F_signal_broken_pipe, &main->program.signal.set);
+ f_signal_set_delete(F_signal_child, &main->program.signal.set);
+ f_signal_set_delete(F_signal_continue, &main->program.signal.set);
+ f_signal_set_delete(F_signal_hangup, &main->program.signal.set);
+ f_signal_set_delete(F_signal_interrupt, &main->program.signal.set);
+ f_signal_set_delete(F_signal_keyboard_stop, &main->program.signal.set);
+ f_signal_set_delete(F_signal_power_failure, &main->program.signal.set);
+ f_signal_set_delete(F_signal_quit, &main->program.signal.set);
+ f_signal_set_delete(F_signal_stop, &main->program.signal.set);
+ f_signal_set_delete(F_signal_termination, &main->program.signal.set);
+ f_signal_set_delete(F_signal_user_1, &main->program.signal.set);
+ f_signal_set_delete(F_signal_user_2, &main->program.signal.set);
+
+ // Explicitly support all free signals.
+ f_signal_set_delete(F_signal_reserved_35, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_36, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_37, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_38, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_39, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_40, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_41, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_42, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_43, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_44, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_45, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_46, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_47, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_48, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_49, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_50, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_51, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_52, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_53, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_54, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_55, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_56, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_57, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_58, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_59, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_60, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_61, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_62, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_63, &main->program.signal.set);
+ f_signal_set_delete(F_signal_reserved_64, &main->program.signal.set);
+
+ status = f_signal_mask(SIG_UNBLOCK, &main->program.signal.set, 0);
+ if (F_status_is_error(status)) return status;
+
+ return F_okay;
+ }
+#endif // _di_controller_signal_set_up_
+
#ifdef __cplusplus
} // extern "C"
#endif
extern void controller_signal_handler(controller_t * const main);
#endif // !defined(_di_controller_signal_handler_) && !defined(_di_thread_support_)
+/**
+ * Perform standard setup with custom signals.
+ *
+ * This is a modified version of fll_program_standard_set_up().
+ *
+ * @param main
+ * The main program data.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * Errors (with error bit) from: f_signal_mask().
+ * Errors (with error bit) from: f_signal_open().
+ *
+ * @see f_signal_mask()
+ * @see f_signal_open()
+ * @see f_signal_set_add()
+ * @see f_signal_set_delete()
+ * @see f_signal_set_empty()
+ * @see f_signal_set_fill()
+ */
+#ifndef _di_controller_signal_set_up_
+ extern f_status_t controller_signal_set_up(controller_t * const main);
+#endif // _di_controller_signal_set_up_
+
#ifdef __cplusplus
} // extern "C"
#endif
if (!argument) return 0;
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_cleanup_s);
controller_t * const main = (controller_t *) argument;
- if (main->thread.enabled != controller_thread_enabled_e) return 0;
-
- const f_time_spec_t delay = macro_f_time_spec_t_initialize_1(
- (main->setting.flag & controller_main_flag_simulate_d)
- ? controller_thread_cleanup_interval_short_d
- : controller_thread_cleanup_interval_long_d,
- 0
- );
+ f_time_spec_t delay = f_time_spec_t_initialize;
+ siginfo_t signal_data;
+ uint8_t reap_count = 0;
+ f_status_t status = F_okay;
while (main->thread.enabled == controller_thread_enabled_e) {
- // Allow thread to be interrupted and auto-cancelled while sleeping.
- f_thread_cancel_state_set(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+ controller_time_now(
+ main->setting.flag & controller_main_flag_simulate_d
+ ? controller_thread_cleanup_interval_short_d
+ : controller_thread_cleanup_interval_long_d,
+ 0,
+ &delay
+ );
+
+ // Use mutex lock and conditional wait, but if that fails fall back to a regular timed wait.
+ if (f_thread_mutex_lock(&main->thread.lock.reap) == F_okay) {
+ status = f_thread_condition_wait_timed(&delay, &main->thread.lock.reap_condition, &main->thread.lock.reap);
+
+ if (F_status_is_error_not(status)) {
+ f_thread_mutex_unlock(&main->thread.lock.reap);
+ }
+ }
+ else {
+ status = F_okay;
+
+ // Allow thread to be interrupted and auto-cancelled while sleeping.
+ f_thread_cancel_state_set(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
- f_time_sleep_spec(delay, 0);
+ f_time_sleep_spec(delay, 0);
- // Prevent thread from being interrupted and auto-cancelled.
- f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ // Prevent thread from being interrupted and auto-cancelled.
+ f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ }
- if (main->thread.enabled != controller_thread_enabled_e) break;
+ // 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)) {
+
+ memset((void *) &signal_data, 0, sizeof(siginfo_t));
+
+ reap_count = 0;
+ do {
+ if (!waitid(P_ALL, 0, &signal_data, WEXITED | WNOHANG)) {
+ if (signal_data.si_pid) {
+ if (++reap_count < controller_lock_max_reap_d) continue;
+ }
+ }
+
+ } while (F_false);
+ }
+
+ if (main->thread.enabled != controller_thread_enabled_e) {
+ if (main->thread.enabled == controller_thread_enabled_exit_e) continue;
+
+ break;
+ }
if (f_thread_lock_write_try(&main->thread.lock.instance) == F_okay) {
- f_status_t status = F_okay;
controller_instance_t *instance = 0;
f_number_unsigned_t i = 0;
- for (; i < main->thread.instances.size && main->thread.enabled == controller_thread_enabled_e; ++i) {
+ for (status = F_okay; i < main->thread.instances.size && main->thread.enabled == controller_thread_enabled_e; ++i) {
if (!main->thread.instances.array[i]) continue;
instance->state = controller_instance_state_idle_e;
instance->id_thread = 0;
- f_thread_mutex_lock(&instance->wait_lock);
- f_thread_condition_signal_all(&instance->wait);
- f_thread_mutex_unlock(&instance->wait_lock);
+ if (f_thread_mutex_lock(&instance->wait_lock) == F_okay) {
+ f_thread_condition_signal_all(&instance->wait);
+ f_thread_mutex_unlock(&instance->wait_lock);
+ }
f_thread_unlock(&instance->lock);
}
if (!argument) return 0;
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_control_s);
controller_t * const main = (controller_t *) argument;
if (!argument) return 0;
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_entry_s);
controller_t * const main = (controller_t *) argument;
// According to the manpages, pthread_exit() calls exit(0), which the value of main->program.child should be returned instead.
if (main->program.child) exit(main->program.child);
} else {
- f_thread_condition_signal_all(&main->thread.lock.alert_condition);
+ if (f_thread_mutex_lock(&main->thread.lock.alert) == F_okay) {
+ f_thread_condition_signal_all(&main->thread.lock.alert_condition);
+ f_thread_mutex_unlock(&main->thread.lock.alert);
+ }
}
return 0;
else {
controller_thread_instance_force_set_disable(main);
- f_thread_condition_signal_all(&main->thread.lock.alert_condition);
+ if (f_thread_mutex_lock(&main->thread.lock.alert) == F_okay) {
+ f_thread_condition_signal_all(&main->thread.lock.alert_condition);
+ f_thread_mutex_unlock(&main->thread.lock.alert);
+ }
}
return 0;
f_thread_create(0, &main->thread.id_signal, &controller_thread_signal_other, (void *) main);
}
+ // Restart the cleanup thread to allow for reaping zombies while operating the Exit.
+ if (!main->thread.id_cleanup) {
+ f_thread_create(0, &main->thread.id_cleanup, &controller_thread_cleanup, (void *) main);
+ }
+
f_status_t status = f_thread_create(0, &main->thread.id_entry, &controller_thread_exit, (void *) main);
if (F_status_is_error(status)) {
if (!argument) return 0;
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_instance_s);
controller_thread_instance((controller_instance_t * const) argument, F_true);
if (!argument) return 0;
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_instance_s);
controller_thread_instance((controller_instance_t * const) argument, F_false);
if (!argument) return 0;
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_rule_s);
controller_t * const main = (controller_t *) argument;
void * controller_thread_signal_normal(void * const argument) {
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_signal_s);
if (argument && ((controller_t *) argument)->callback.process_thread_signal) {
((controller_t *) argument)->callback.process_thread_signal((controller_t *) argument, F_true);
void * controller_thread_signal_other(void * const argument) {
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+ f_thread_name_set(f_thread_caller(), controller_thread_signal_s);
if (argument && ((controller_t *) argument)->callback.process_thread_signal) {
((controller_t *) argument)->callback.process_thread_signal((controller_t *) argument, F_false);