]> Kevux Git Server - fll/commitdiff
Update: Provide fallback should the locks on exit fail to catch and update function...
authorKevin Day <Kevin@kevux.org>
Wed, 10 Jul 2024 02:30:32 +0000 (21:30 -0500)
committerKevin Day <Kevin@kevux.org>
Wed, 10 Jul 2024 02:32:44 +0000 (21:32 -0500)
The previous commit 49a3d41d1c17734b0a8299b356f1e299386f4a42 removed the forced fallback to avoid potential race conditions.
The reason for having that fallback is to ensure that the exit process is guaranteed and not potentially blocked by a lock.

Provide an alternative that makes several attempts to properly lock on exit.
Only when those extra attempts fails should the failsafe/fallback be used.

Update controller_thread_process_cancel() to have the global data as a pointer.

level_3/controller/c/common/private-thread.h
level_3/controller/c/entry/private-entry.c
level_3/controller/c/thread/private-thread.c
level_3/controller/c/thread/private-thread_entry.c
level_3/controller/c/thread/private-thread_process.c
level_3/controller/c/thread/private-thread_process.h
level_3/controller/c/thread/private-thread_signal.c

index 6b48d1ccd27ffde63b7a7602ac7abbb228a8363b..ea3a232bee4a58dfe02cc7f327e455b088bd9fbb 100644 (file)
@@ -66,6 +66,10 @@ extern "C" {
   #define controller_thread_exit_ready_timeout_seconds_d     0
   #define controller_thread_exit_ready_timeout_nanoseconds_d 500000000 // 0.5 seconds in nanoseconds.
 
+  #define controller_thread_exit_disable_force_times                 12
+  #define controller_thread_exit_disable_force_timeout_nanoseconds_d 10000000  // 0.01 seconds in nanoseconds.
+  #define controller_thread_exit_disable_force_timeout_seconds_d     0
+
   /**
    * States for enabled, designating how to stop the process.
    *
index 7188b6921648cb323b6259e36fd06569f805365f..8742d43d7f73e23c53bb9bfd3322736d4d52f029 100644 (file)
@@ -1330,7 +1330,7 @@ extern "C" {
             return F_execute;
           }
 
-          controller_thread_process_cancel(*global, is_entry, is_entry ? controller_thread_cancel_execute_e : controller_thread_cancel_exit_execute_e, 0);
+          controller_thread_process_cancel(global, is_entry, is_entry ? controller_thread_cancel_execute_e : controller_thread_cancel_exit_execute_e, 0);
 
           int result = 0;
           int option = FL_execute_parameter_option_path_d;
index e8cb336d3f43955d9f959624a2afd65eefb7f299..3aa9c74e06b8a2d8818b221802f7366eb5139c3c 100644 (file)
@@ -311,7 +311,7 @@ extern "C" {
       }
     }
 
-    controller_thread_process_cancel(global, F_true, controller_thread_cancel_call_e, 0);
+    controller_thread_process_cancel(&global, F_true, controller_thread_cancel_call_e, 0);
 
     controller_thread_process_exit(&global);
 
index 8284345ef134c7681e8ea2e62996ebbda4ff9edb..e204f3f7a54e8459b23bc458711909ece0e769c9 100644 (file)
@@ -125,7 +125,7 @@ extern "C" {
 
           nanosleep(&time, 0);
 
-          controller_thread_process_cancel(*(entry->global), F_true, controller_thread_cancel_exit_e, 0);
+          controller_thread_process_cancel(entry->global, F_true, controller_thread_cancel_exit_e, 0);
         }
       }
     }
@@ -260,11 +260,7 @@ extern "C" {
       return 0;
     }
 
-    if (F_status_is_error_not(f_thread_mutex_lock(&entry->global->thread->lock.alert))) {
-      entry->global->thread->enabled = controller_thread_enabled_not_e;
-
-      f_thread_mutex_unlock(&entry->global->thread->lock.alert);
-    }
+    controller_thread_process_exit_force_set_disable(entry->global);
 
     f_thread_condition_signal_all(&entry->global->thread->lock.alert_condition);
 
index e11dae05ae09c5c4f1801fd9f503a0c896272e51..5e5c87b197ee21dbf0c34495873bae69ec47da6e 100644 (file)
@@ -43,13 +43,15 @@ extern "C" {
 #endif // _di_controller_thread_process_
 
 #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) {
+  void controller_thread_process_cancel(const controller_global_t * const global, const bool is_normal, const uint8_t by, controller_process_t * const caller) {
 
-    f_thread_mutex_lock(&global.thread->lock.cancel);
+    if (!global) return;
+
+    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);
+    if (!controller_thread_is_enabled(is_normal, global->thread)) {
+      f_thread_mutex_unlock(&global->thread->lock.cancel);
 
       return;
     }
@@ -65,10 +67,10 @@ extern "C" {
     pid_t pid = 0;
 
     if (is_normal) {
-      entry = &global.setting->entry;
+      entry = &global->setting->entry;
     }
     else {
-      entry = &global.setting->exit;
+      entry = &global->setting->exit;
     }
 
     // A simple but inaccurate interval counter (expect this to be replaced in the future).
@@ -78,16 +80,16 @@ extern "C" {
     time.tv_sec = 0;
     time.tv_nsec = interval_nanoseconds;
 
-    if (global.setting->mode == controller_setting_mode_helper_e && global.main->parameters.array[controller_parameter_validate_e].result == f_console_result_none_e) {
+    if (global->setting->mode == controller_setting_mode_helper_e && global->main->parameters.array[controller_parameter_validate_e].result == f_console_result_none_e) {
       int value = 0;
       f_number_unsigned_t lapsed = 0;
 
-      for (i = 0; i < global.thread->processs.used; ++i) {
+      for (i = 0; i < global->thread->processs.used; ++i) {
 
-        if (!global.thread->processs.array[i]) continue;
+        if (!global->thread->processs.array[i]) continue;
         if (caller && i == caller->id) continue;
 
-        process = global.thread->processs.array[i];
+        process = global->thread->processs.array[i];
 
         if (!process->id_thread) continue;
 
@@ -98,72 +100,72 @@ extern "C" {
     }
 
     // Use the alert lock to toggle enabled (using it as if it is a write like and a signal lock).
-    status = f_thread_mutex_lock(&global.thread->lock.alert);
+    status = f_thread_mutex_lock(&global->thread->lock.alert);
 
     if (F_status_is_error(status)) {
-      global.thread->enabled = controller_thread_enabled_not_e;
+      global->thread->enabled = controller_thread_enabled_not_e;
     }
     else {
       if (by == controller_thread_cancel_execute_e) {
-        global.thread->enabled = controller_thread_enabled_execute_e;
+        global->thread->enabled = controller_thread_enabled_execute_e;
       }
       else if (by == controller_thread_cancel_exit_e) {
-        global.thread->enabled = controller_thread_enabled_not_e;
+        global->thread->enabled = controller_thread_enabled_not_e;
       }
       else if (by == controller_thread_cancel_exit_execute_e) {
-        global.thread->enabled = controller_thread_enabled_exit_execute_e;
+        global->thread->enabled = controller_thread_enabled_exit_execute_e;
       }
       else {
-        global.thread->enabled = controller_thread_enabled_exit_e;
+        global->thread->enabled = controller_thread_enabled_exit_e;
       }
 
-      f_thread_mutex_unlock(&global.thread->lock.alert);
+      f_thread_mutex_unlock(&global->thread->lock.alert);
     }
 
-    if (global.thread->id_cleanup) {
-      f_thread_cancel(global.thread->id_cleanup);
-      f_thread_join(global.thread->id_cleanup, 0);
+    if (global->thread->id_cleanup) {
+      f_thread_cancel(global->thread->id_cleanup);
+      f_thread_join(global->thread->id_cleanup, 0);
 
-      global.thread->id_cleanup = 0;
+      global->thread->id_cleanup = 0;
     }
 
-    if (global.thread->id_control) {
-      f_thread_cancel(global.thread->id_control);
-      f_thread_join(global.thread->id_control, 0);
+    if (global->thread->id_control) {
+      f_thread_cancel(global->thread->id_control);
+      f_thread_join(global->thread->id_control, 0);
 
-      global.thread->id_control = 0;
+      global->thread->id_control = 0;
     }
 
     // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
-    if (by != controller_thread_cancel_signal_e && global.thread->id_signal) {
-      f_thread_cancel(global.thread->id_signal);
-      f_thread_join(global.thread->id_signal, 0);
+    if (by != controller_thread_cancel_signal_e && global->thread->id_signal) {
+      f_thread_cancel(global->thread->id_signal);
+      f_thread_join(global->thread->id_signal, 0);
 
-      global.thread->id_signal = 0;
+      global->thread->id_signal = 0;
     }
 
-    if (global.setting->mode == controller_setting_mode_helper_e && global.main->parameters.array[controller_parameter_validate_e].result == f_console_result_none_e) {
-      f_thread_mutex_unlock(&global.thread->lock.cancel);
+    if (global->setting->mode == controller_setting_mode_helper_e && global->main->parameters.array[controller_parameter_validate_e].result == f_console_result_none_e) {
+      f_thread_mutex_unlock(&global->thread->lock.cancel);
 
       return;
     }
 
-    for (; i < global.thread->processs.used; ++i) {
+    for (; i < global->thread->processs.used; ++i) {
 
-      if (!global.thread->processs.array[i]) continue;
+      if (!global->thread->processs.array[i]) continue;
       if (caller && i == caller->id) continue;
 
-      process = global.thread->processs.array[i];
+      process = global->thread->processs.array[i];
 
       // Do not cancel exit processes, when not performing "execute" during exit.
-      if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) {
+      if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) {
         continue;
       }
 
       for (j = 0; j < process->childs.used; ++j) {
 
         if (process->childs.array[j] > 0) {
-          f_signal_send(global.thread->signal ? global.thread->signal : F_signal_termination, process->childs.array[j]);
+          f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, process->childs.array[j]);
         }
       } // for
 
@@ -173,7 +175,7 @@ extern "C" {
           status = controller_file_pid_read(process->path_pids.array[j], &pid);
 
           if (pid) {
-            f_signal_send(global.thread->signal ? global.thread->signal : F_signal_termination, pid);
+            f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, pid);
           }
         }
       } // for
@@ -182,15 +184,15 @@ extern "C" {
     if (entry->timeout_exit && !(entry->flag & controller_entry_flag_timeout_exit_no_e)) {
       f_number_unsigned_t lapsed = 0;
 
-      for (i = 0; i < global.thread->processs.used && lapsed < entry->timeout_exit; ++i) {
+      for (i = 0; i < global->thread->processs.used && lapsed < entry->timeout_exit; ++i) {
 
-        if (!global.thread->processs.array[i]) continue;
+        if (!global->thread->processs.array[i]) continue;
         if (caller && i == caller->id) continue;
 
-        process = global.thread->processs.array[i];
+        process = global->thread->processs.array[i];
 
         // Do not wait for processes, when not performing "execute" during exit.
-        if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) {
+        if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) {
           continue;
         }
 
@@ -244,15 +246,15 @@ extern "C" {
       } // for
     }
 
-    for (i = 0; i < global.thread->processs.size; ++i) {
+    for (i = 0; i < global->thread->processs.size; ++i) {
 
-      if (!global.thread->processs.array[i]) continue;
+      if (!global->thread->processs.array[i]) continue;
       if (caller && i == caller->id) continue;
 
-      process = global.thread->processs.array[i];
+      process = global->thread->processs.array[i];
 
       // Do not kill exit processes, when not performing "execute" during exit.
-      if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+      if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
 
       if (process->id_thread) {
         if (process->childs.used) {
@@ -280,7 +282,7 @@ extern "C" {
         for (j = 0; j < process->childs.size; ++j) {
 
           // Do not kill exit processes, when not performing "execute" during exit.
-          if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+          if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
 
           if (process->childs.array[j]) {
 
@@ -298,7 +300,7 @@ extern "C" {
         for (j = 0; j < process->path_pids.used; ++j) {
 
           // Do not kill exit processes, when not performing "execute" during exit.
-          if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+          if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
 
           if (f_file_exists(process->path_pids.array[j], F_true) == F_true) {
             status = controller_file_pid_read(process->path_pids.array[j], &pid);
@@ -317,7 +319,7 @@ extern "C" {
       while (process->childs.used) {
 
         // Do not shrink below an exit processes, when not performing "execute" during exit.
-        if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) break;
+        if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) break;
         if (process->childs.array[j] > 0) break;
 
         --process->childs.used;
@@ -327,14 +329,14 @@ extern "C" {
       while (process->path_pids.used) {
 
         // Do not shrink below an exit processes, when not performing "execute" during exit.
-        if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) break;
+        if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) break;
         if (process->path_pids.array[j].used) break;
 
         --process->path_pids.used;
       } // while
     } // for
 
-    f_thread_mutex_unlock(&global.thread->lock.cancel);
+    f_thread_mutex_unlock(&global->thread->lock.cancel);
   }
 #endif // _di_controller_thread_process_cancel_
 
@@ -369,11 +371,7 @@ extern "C" {
           controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_thread_create", F_true);
         }
 
-        if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) {
-          global->thread->enabled = controller_thread_enabled_not_e;
-
-          f_thread_mutex_unlock(&global->thread->lock.alert);
-        }
+        controller_thread_process_exit_force_set_disable(global);
       }
       else {
         struct timespec time;
@@ -390,13 +388,7 @@ extern "C" {
 
         } while (F_status_is_error_not(status) && global->thread->enabled == controller_thread_enabled_exit_e);
 
-        if (F_status_is_error(status)) {
-          if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) {
-            global->thread->enabled = controller_thread_enabled_not_e;
-
-            f_thread_mutex_unlock(&global->thread->lock.alert);
-          }
-        }
+        if (F_status_is_error(status)) controller_thread_process_exit_force_set_disable(global);
       }
 
       // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
@@ -407,17 +399,48 @@ extern "C" {
         global->thread->id_signal = 0;
       }
 
-      controller_thread_process_cancel(*global, F_false, controller_thread_cancel_exit_e, 0);
+      controller_thread_process_cancel(global, F_false, controller_thread_cancel_exit_e, 0);
     }
     else {
-      if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) {
+      controller_thread_process_exit_force_set_disable(global);
+    }
+  }
+#endif // _di_controller_thread_process_exit_
+
+#ifndef _di_controller_thread_process_exit_force_set_disable_
+  void controller_thread_process_exit_force_set_disable(const controller_global_t * const global) {
+
+    if (!global) return;
+
+    if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) {
+      global->thread->enabled = controller_thread_enabled_not_e;
+
+      f_thread_mutex_unlock(&global->thread->lock.alert);
+
+      return;
+    }
+
+    struct timespec time;
+
+    for (uint8_t i = 0; i < controller_thread_exit_disable_force_times; ++i) {
+
+      memset((void *) &time, 0, sizeof(struct timespec));
+
+      controller_time(controller_thread_exit_disable_force_timeout_seconds_d, controller_thread_exit_disable_force_timeout_nanoseconds_d, &time);
+
+      if (F_status_is_error_not(f_thread_mutex_lock_timed(&time, &global->thread->lock.alert))) {
         global->thread->enabled = controller_thread_enabled_not_e;
 
         f_thread_mutex_unlock(&global->thread->lock.alert);
+
+        return;
       }
-    }
+    } // for
+
+    // Forcibly set disable regardless of the risk.
+    global->thread->enabled = controller_thread_enabled_not_e;
   }
-#endif // _di_controller_thread_process_exit_
+#endif // _di_controller_thread_process_exit_force_set_disable_
 
 #ifndef _di_controller_thread_process_normal_
   void * controller_thread_process_normal(void * const arguments) {
index a636cba1c892f60fca72707264a1bd9851d6860a..97b4e29adf92837fd2347652aa0a3c86759f58b9 100644 (file)
@@ -46,7 +46,7 @@ extern "C" {
  *   Set to NULL to not use.
  */
 #ifndef _di_controller_thread_process_cancel_
-  extern void controller_thread_process_cancel(const controller_global_t global, const bool is_normal, const uint8_t by, controller_process_t * const caller) F_attribute_visibility_internal_d;
+  extern void controller_thread_process_cancel(const controller_global_t * const global, const bool is_normal, const uint8_t by, controller_process_t * const caller) F_attribute_visibility_internal_d;
 #endif // _di_controller_thread_process_cancel_
 
 /**
@@ -60,6 +60,24 @@ extern "C" {
 #endif // _di_controller_thread_process_exit_
 
 /**
+ * Set the execution state to disabled during exiting and force the case if need be.
+ *
+ * The program must exit during the Exit process.
+ * The state must be properly set.
+ * Perform a limited number of attempts to set the state to exiting.
+ * Should this fail, then force the case regardless of the risk.
+ *
+ * @param global
+ *   The global thread data.
+ *
+ *   The global.thread.lock.alert lock will be set and then unset if possible.
+ *   The global.thread.enabled will be updated and set to controller_thread_enabled_not_e.
+ */
+#ifndef _di_controller_thread_process_exit_force_set_disable_
+  extern void controller_thread_process_exit_force_set_disable(const controller_global_t * const global) F_attribute_visibility_internal_d;
+#endif // _di_controller_thread_process_exit_force_set_disable_
+
+/**
  * Asynchronously execute a Rule process during normal operations.
  *
  * @param arguments
index 75cbc29aae999308d9eba3175d54111bf5db4ca7..04f70b0b8384fe91771239b8506809ff3b53d065 100644 (file)
@@ -33,7 +33,7 @@ extern "C" {
         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) {
           global->thread->signal = information.si_signo;
 
-          controller_thread_process_cancel(*global, is_normal, controller_thread_cancel_signal_e, 0);
+          controller_thread_process_cancel(global, is_normal, controller_thread_cancel_signal_e, 0);
 
           break;
         }