From: Kevin Day Date: Sat, 2 Aug 2025 21:04:46 +0000 (-0500) Subject: Progress: Continue setup for granting init program the ability to handle shutdown... X-Git-Tag: 0.7.3~41 X-Git-Url: https://www.git.kevux.org/?a=commitdiff_plain;h=f17cb61f534f9ead8ee4effa858c86f9faf09dea;p=controller Progress: Continue setup for granting init program the ability to handle shutdown/reboot. 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. --- diff --git a/data/build/stand_alone/config.h b/data/build/stand_alone/config.h index d7287a0..07cf2f5 100644 --- a/data/build/stand_alone/config.h +++ b/data/build/stand_alone/config.h @@ -2251,7 +2251,7 @@ //#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_ diff --git a/sources/c/program/controller/controller/main.c b/sources/c/program/controller/controller/main.c index 987872d..ffc0948 100644 --- a/sources/c/program/controller/controller/main.c +++ b/sources/c/program/controller/controller/main.c @@ -31,7 +31,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { 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); diff --git a/sources/c/program/controller/init/main.c b/sources/c/program/controller/init/main.c index 02650d5..9c79927 100644 --- a/sources/c/program/controller/init/main.c +++ b/sources/c/program/controller/init/main.c @@ -34,7 +34,7 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { 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); @@ -46,6 +46,8 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { controller_process(&data); + controller_delete(&data); + fll_program_standard_set_down(&data.program); if (data.setting.state.status == F_child) { diff --git a/sources/c/program/controller/init/signal.c b/sources/c/program/controller/init/signal.c index 0ff5693..8133620 100644 --- a/sources/c/program/controller/init/signal.c +++ b/sources/c/program/controller/init/signal.c @@ -4,64 +4,6 @@ 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) { @@ -86,18 +28,25 @@ extern "C" { // 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; diff --git a/sources/c/program/controller/init/signal.h b/sources/c/program/controller/init/signal.h index 02b7e86..9ac91d4 100644 --- a/sources/c/program/controller/init/signal.h +++ b/sources/c/program/controller/init/signal.h @@ -17,35 +17,6 @@ extern "C" { #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 diff --git a/sources/c/program/controller/main/common/define.h b/sources/c/program/controller/main/common/define.h index 053b1a7..2e69c07 100644 --- a/sources/c/program/controller/main/common/define.h +++ b/sources/c/program/controller/main/common/define.h @@ -40,9 +40,11 @@ extern "C" { * 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_ diff --git a/sources/c/program/controller/main/common/string.c b/sources/c/program/controller/main/common/string.c index 175010d..e7b9f95 100644 --- a/sources/c/program/controller/main/common/string.c +++ b/sources/c/program/controller/main/common/string.c @@ -47,6 +47,15 @@ extern "C" { 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 diff --git a/sources/c/program/controller/main/common/string.h b/sources/c/program/controller/main/common/string.h index a4b57e8..413c7a9 100644 --- a/sources/c/program/controller/main/common/string.h +++ b/sources/c/program/controller/main/common/string.h @@ -257,6 +257,32 @@ extern "C" { 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 diff --git a/sources/c/program/controller/main/common/type/lock.c b/sources/c/program/controller/main/common/type/lock.c index 03c5366..d7b45db 100644 --- a/sources/c/program/controller/main/common/type/lock.c +++ b/sources/c/program/controller/main/common/type/lock.c @@ -12,11 +12,13 @@ extern "C" { 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; } diff --git a/sources/c/program/controller/main/common/type/lock.h b/sources/c/program/controller/main/common/type/lock.h index 0f368ee..34ce5e5 100644 --- a/sources/c/program/controller/main/common/type/lock.h +++ b/sources/c/program/controller/main/common/type/lock.h @@ -30,9 +30,11 @@ extern "C" { * - 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 { @@ -41,11 +43,13 @@ extern "C" { 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 { \ @@ -53,9 +57,11 @@ extern "C" { 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_ diff --git a/sources/c/program/controller/main/controller.h b/sources/c/program/controller/main/controller.h index 272e9c8..d020314 100644 --- a/sources/c/program/controller/main/controller.h +++ b/sources/c/program/controller/main/controller.h @@ -143,6 +143,7 @@ #include #include #include +#include #include #include #include diff --git a/sources/c/program/controller/main/instance/wait.c b/sources/c/program/controller/main/instance/wait.c index 6f031fb..938a383 100644 --- a/sources/c/program/controller/main/instance/wait.c +++ b/sources/c/program/controller/main/instance/wait.c @@ -18,24 +18,26 @@ extern "C" { 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; diff --git a/sources/c/program/controller/main/lock.c b/sources/c/program/controller/main/lock.c index 9bdaa3f..ad15289 100644 --- a/sources/c/program/controller/main/lock.c +++ b/sources/c/program/controller/main/lock.c @@ -14,51 +14,56 @@ extern "C" { 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; } diff --git a/sources/c/program/controller/main/process.c b/sources/c/program/controller/main/process.c index 7ce4b08..cb35290 100644 --- a/sources/c/program/controller/main/process.c +++ b/sources/c/program/controller/main/process.c @@ -57,8 +57,18 @@ extern "C" { 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); } @@ -102,13 +112,8 @@ extern "C" { 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); } } diff --git a/sources/c/program/controller/main/rule/instance.c b/sources/c/program/controller/main/rule/instance.c index 418a15b..12b5f04 100644 --- a/sources/c/program/controller/main/rule/instance.c +++ b/sources/c/program/controller/main/rule/instance.c @@ -534,9 +534,10 @@ extern "C" { 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; @@ -664,9 +665,10 @@ extern "C" { 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); } @@ -916,10 +918,11 @@ extern "C" { 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); diff --git a/sources/c/program/controller/main/rule/wait.c b/sources/c/program/controller/main/rule/wait.c index 314d17a..51de49d 100644 --- a/sources/c/program/controller/main/rule/wait.c +++ b/sources/c/program/controller/main/rule/wait.c @@ -107,9 +107,10 @@ extern "C" { 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); diff --git a/sources/c/program/controller/main/signal.c b/sources/c/program/controller/main/signal.c index f598dbd..50ef3f2 100644 --- a/sources/c/program/controller/main/signal.c +++ b/sources/c/program/controller/main/signal.c @@ -12,10 +12,49 @@ extern "C" { 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); @@ -25,6 +64,128 @@ extern "C" { } #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 diff --git a/sources/c/program/controller/main/signal.h b/sources/c/program/controller/main/signal.h index c341fe9..6e159bf 100644 --- a/sources/c/program/controller/main/signal.h +++ b/sources/c/program/controller/main/signal.h @@ -50,6 +50,35 @@ extern "C" { 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 diff --git a/sources/c/program/controller/main/thread/cleanup.c b/sources/c/program/controller/main/thread/cleanup.c index 04f628b..3f7c1de 100644 --- a/sources/c/program/controller/main/thread/cleanup.c +++ b/sources/c/program/controller/main/thread/cleanup.c @@ -10,37 +10,73 @@ extern "C" { 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; @@ -104,9 +140,10 @@ extern "C" { 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); } diff --git a/sources/c/program/controller/main/thread/control.c b/sources/c/program/controller/main/thread/control.c index 0093c79..cd2f222 100644 --- a/sources/c/program/controller/main/thread/control.c +++ b/sources/c/program/controller/main/thread/control.c @@ -10,6 +10,7 @@ extern "C" { 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; diff --git a/sources/c/program/controller/main/thread/entry.c b/sources/c/program/controller/main/thread/entry.c index 9d86391..adbf53e 100644 --- a/sources/c/program/controller/main/thread/entry.c +++ b/sources/c/program/controller/main/thread/entry.c @@ -10,6 +10,7 @@ extern "C" { 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; @@ -112,7 +113,10 @@ extern "C" { // 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; @@ -215,7 +219,10 @@ extern "C" { 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; diff --git a/sources/c/program/controller/main/thread/instance.c b/sources/c/program/controller/main/thread/instance.c index 9886932..fba2a57 100644 --- a/sources/c/program/controller/main/thread/instance.c +++ b/sources/c/program/controller/main/thread/instance.c @@ -344,6 +344,11 @@ extern "C" { 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)) { @@ -428,6 +433,7 @@ extern "C" { 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); @@ -441,6 +447,7 @@ extern "C" { 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); diff --git a/sources/c/program/controller/main/thread/rule.c b/sources/c/program/controller/main/thread/rule.c index 7c54c04..4506f59 100644 --- a/sources/c/program/controller/main/thread/rule.c +++ b/sources/c/program/controller/main/thread/rule.c @@ -10,6 +10,7 @@ extern "C" { 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; diff --git a/sources/c/program/controller/main/thread/signal.c b/sources/c/program/controller/main/thread/signal.c index 7a59741..7810d36 100644 --- a/sources/c/program/controller/main/thread/signal.c +++ b/sources/c/program/controller/main/thread/signal.c @@ -83,6 +83,7 @@ extern "C" { 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); @@ -96,6 +97,7 @@ extern "C" { 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);