From 386aac8b2b7abd772504dbf6c1d1518cb19fe3e4 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 8 Mar 2023 20:31:39 -0600 Subject: [PATCH] Bugfix: Multiple cancellations may occur, use mutex lock to prevent. There is an existing check that prevents the cancellation from being called more than once. What is not being considered is that if the main thread calls cancellation while another cancellation is active then the controller_thread_process_exit() gets called. The controller_thread_process_exit() function will begin more forcibly shutting things down. Avoid this by providing a mutex lock to lock the cancellation. Only once the first cancellation is complete will the second (or more) then return without doing anything. --- level_3/controller/c/common/private-lock.c | 1 + level_3/controller/c/common/private-lock.h | 4 ++++ level_3/controller/c/lock/private-lock.c | 3 +++ level_3/controller/c/thread/private-thread_process.c | 7 +++++++ 4 files changed, 15 insertions(+) diff --git a/level_3/controller/c/common/private-lock.c b/level_3/controller/c/common/private-lock.c index 84cc685..eec15c2 100644 --- a/level_3/controller/c/common/private-lock.c +++ b/level_3/controller/c/common/private-lock.c @@ -45,6 +45,7 @@ extern "C" { void controller_lock_delete_simple(controller_lock_t * const lock) { controller_lock_delete_mutex(&lock->alert); + controller_lock_delete_mutex(&lock->cancel); controller_lock_delete_mutex(&lock->print); controller_lock_delete_rw(&lock->process); diff --git a/level_3/controller/c/common/private-lock.h b/level_3/controller/c/common/private-lock.h index ef1e73b..ee7baee 100644 --- a/level_3/controller/c/common/private-lock.h +++ b/level_3/controller/c/common/private-lock.h @@ -16,11 +16,13 @@ extern "C" { * A structure for sharing mutexes globally between different threads. * * The alert lock is intended for a generic waiting on alerts operations. + * The cancel lock is intended for preventing double cancellation calls (which can happen due to interrupts). * The print lock is intended to lock any activity printing to stdout/stderr. * The process lock is intended to lock any activity on the processs structure. * The rule lock is intended to lock any activity on the rules structure. * * 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. * process: The process r/w lock. * rule: The rule r/w lock. @@ -29,6 +31,7 @@ extern "C" { #ifndef _di_controller_lock_t_ typedef struct { f_thread_mutex_t alert; + f_thread_mutex_t cancel; f_thread_mutex_t print; f_thread_lock_t process; @@ -40,6 +43,7 @@ extern "C" { #define controller_lock_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, \ diff --git a/level_3/controller/c/lock/private-lock.c b/level_3/controller/c/lock/private-lock.c index ee3c08f..311d2e8 100644 --- a/level_3/controller/c/lock/private-lock.c +++ b/level_3/controller/c/lock/private-lock.c @@ -14,6 +14,9 @@ extern "C" { f_status_t status = f_thread_mutex_create(0, &lock->alert); if (F_status_is_error(status)) return status; + status = f_thread_mutex_create(0, &lock->cancel); + if (F_status_is_error(status)) return status; + status = f_thread_mutex_create(0, &lock->print); if (F_status_is_error(status)) return status; diff --git a/level_3/controller/c/thread/private-thread_process.c b/level_3/controller/c/thread/private-thread_process.c index ceb0193..750f17a 100644 --- a/level_3/controller/c/thread/private-thread_process.c +++ b/level_3/controller/c/thread/private-thread_process.c @@ -45,8 +45,13 @@ extern "C" { #ifndef _di_controller_thread_process_cancel_ void controller_thread_process_cancel(const controller_global_t global, const bool is_normal, const uint8_t by, controller_process_t * const caller) { + f_thread_mutex_lock(&global.thread->lock.cancel); + // Only cancel when enabled. if (!controller_thread_is_enabled(is_normal, global.thread)) { + + f_thread_mutex_unlock(&global.thread->lock.cancel); + return; } @@ -300,6 +305,8 @@ extern "C" { --process->path_pids.used; } // while } // for + + f_thread_mutex_unlock(&global.thread->lock.cancel); } #endif // _di_controller_thread_process_cancel_ -- 1.8.3.1