]> Kevux Git Server - controller/commitdiff
Progress: Continue migrating the project.
authorKevin Day <kevin@kevux.org>
Sat, 27 Apr 2024 06:01:38 +0000 (01:01 -0500)
committerKevin Day <kevin@kevux.org>
Sat, 27 Apr 2024 06:01:38 +0000 (01:01 -0500)
39 files changed:
data/build/defines
data/build/settings
sources/c/controller/controller.c
sources/c/controller/controller.h
sources/c/controller/main.c
sources/c/init/init.c
sources/c/init/init.h
sources/c/init/main.c
sources/c/main/common.c
sources/c/main/common.h
sources/c/main/common/enumeration/instance.h [new file with mode: 0644]
sources/c/main/common/enumeration/program.h [moved from sources/c/main/common/enumeration/process.h with 58% similarity]
sources/c/main/common/type/control.c
sources/c/main/common/type/control.h
sources/c/main/common/type/entry.c
sources/c/main/common/type/entry.h
sources/c/main/common/type/global.c [new file with mode: 0644]
sources/c/main/common/type/global.h [new file with mode: 0644]
sources/c/main/common/type/instance.c [new file with mode: 0644]
sources/c/main/common/type/instance.h [new file with mode: 0644]
sources/c/main/common/type/lock.c
sources/c/main/common/type/lock.h
sources/c/main/common/type/process.c [deleted file]
sources/c/main/common/type/program.c [new file with mode: 0644]
sources/c/main/common/type/program.h [moved from sources/c/main/common/type/process.h with 72% similarity]
sources/c/main/common/type/rule.h
sources/c/main/common/type/thread.c
sources/c/main/common/type/thread.h
sources/c/main/controller.h
sources/c/main/print/error.c
sources/c/main/print/error.h
sources/c/main/thread.c
sources/c/main/thread.h
sources/c/main/thread/instance.c [new file with mode: 0644]
sources/c/main/thread/instance.h [new file with mode: 0644]
sources/c/main/thread/is.c [new file with mode: 0644]
sources/c/main/thread/is.h [new file with mode: 0644]
sources/c/main/time.c [new file with mode: 0644]
sources/c/main/time.h [new file with mode: 0644]

index 345bd450588f6bd03d67d3aa56d1c8d2278509dc..f282d0fd2c18a98b66378bf3304f41246e6ce24c 100644 (file)
@@ -5,14 +5,14 @@ _di_thread_support_ Disables thread support.
 
 _libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later).
 
-_override_controller_default_engine_            Provide a custom scripting engine name string to execute (such as php).
-_override_controller_path_pid_                  Use this as the default custom directory path representing the location of the controller program pid.
-_override_controller_path_pid_prefix_           Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
-_override_controller_path_pid_suffix_           Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
-_override_controller_path_settings_             Use this as the default custom settings path, such as /etc/settings.
-_override_controller_path_socket_               Use this as the default custom directory path representing the location of the controller program socket.
-_override_controller_path_socket_prefix_        Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
-_override_controller_path_socket_suffix_        Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+_override_controller_default_engine_     Provide a custom scripting engine name string to execute (such as php).
+_override_controller_path_pid_           Use this as the default custom directory path representing the location of the controller program pid.
+_override_controller_path_pid_prefix_    Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
+_override_controller_path_pid_suffix_    Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
+_override_controller_path_settings_      Use this as the default custom settings path, such as /etc/settings.
+_override_controller_path_socket_        Use this as the default custom directory path representing the location of the controller program socket.
+_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
 
 _override_controller_default_engine_length_     The number of bytes representing the string in _override_controller_default_engine_ (not including the terminating NULL).
 _override_controller_path_pid_length_           The number of bytes representing the string in _override_controller_path_pid_ (not including the terminating NULL).
index bbaed75d69f0c0de3a6037c86eb6ecc8dcef9676..bed0aab0920f3b451c441be978cbf7d5445f34fd 100644 (file)
@@ -41,20 +41,20 @@ build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 
 build_sources_library main/common.c main/common/define.c main/common/enumeration.c main/common/print.c main/common/string.c main/common/type.c
-build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.c main/common/type/lock.c main/common/type/process.c main/common/type/rule.c main/common/type/thread.c
+build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.c main/common/type/global.c main/common/type/lock.c main/common/type/instance.c main/common/type/program.c main/common/type/rule.c main/common/type/thread.c
 build_sources_library main/common/string/general.c main/common/string/rule.c
 build_sources_library main/path.c
 build_sources_library main/print/data.c main/print/debug.c main/print/error.c main/print/lock.c main/print/message.c main/print/verbose.c main/print/warning.c
-build_sources_library main/signal.c main/thread.c
+build_sources_library main/signal.c main/thread.c main/thread/instance.c main/thread/is.c
 
-build_sources_headers main/common.h main/controller.h main/common/define.h main/common/enumeration.h main/common/print.h main/common/string.h main/common/type.h
+build_sources_headers main/common.h main/controller.h main/common/define.h main/common/enumeration.h main/common/print.h main/common/string.h main/common/thread.h main/common/type.h
 build_sources_headers main/common/define/control.h main/common/define/entry.h main/common/define/rule.h main/common/define/thread.h
-build_sources_headers main/common/enumeration/control.h main/common/enumeration/entry.h main/common/enumeration/process.h main/common/enumeration/rule.h main/common/enumeration/thread.h
+build_sources_headers main/common/enumeration/control.h main/common/enumeration/entry.h main/common/enumeration/instance.h main/common/enumeration/program.h main/common/enumeration/rule.h main/common/enumeration/thread.h
 build_sources_headers main/common/string/general.h main/common/string/rule.h
-build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/entry.h main/common/type/lock.h main/common/type/process.h main/common/type/rule.h main/common/type/thread.h
+build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/entry.h main/common/type/global.h main/common/type/lock.h main/common/type/instance.h main/common/type/program.h main/common/type/rule.h main/common/type/thread.h
 build_sources_headers main/path.h
 build_sources_headers main/print/data.h main/print/debug.h main/print/error.h main/print/lock.h main/print/message.h main/print/verbose.h main/print/warning.h
-build_sources_headers main/signal.h main/thread.h
+build_sources_headers main/signal.h main/thread.h main/thread/instance.h main/thread/is.h
 
 build_sources_documentation man
 
index 579f58bd9d7622d3c8221548f68c681656453fc9..13aa16f018c5ef9cd5462de93f68c8ce5fe68b46 100644 (file)
@@ -5,9 +5,9 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_controller_main_
-  void controller_controller_main(controller_main_t * const main, controller_process_t * const process) {
+  void controller_controller_main(controller_main_t * const main, controller_program_t * const program) {
 
-    if (!main || !process) return;
+    if (!main || !program) return;
 
     if (F_status_is_error(main->setting.state.status)) {
       if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
@@ -41,6 +41,9 @@ extern "C" {
       return;
     }
 
+    // @todo controller_main(&data, &program);
+    if (main->setting.state.status == F_status_set_error(F_child)) return;
+
     if (main->setting.state.status == F_status_set_error(F_interrupt)) {
       fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
     }
index 94832c56a6f05ddf16b08fe123c530036b11862f..e7184c89191693ad3c33582342bb37aea37d6bb5 100644 (file)
 #ifndef _controller_controller_h
 #define _controller_controller_h
 
-// Include pre-requirements.
-#ifndef _GNU_SOURCE
-  #define _GNU_SOURCE
-#endif // _GNU_SOURCE
-
-// Libc includes.
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-// FLL-0 includes.
-#include <fll/level_0/type.h>
-#include <fll/level_0/status.h>
-#include <fll/level_0/memory.h>
-#include <fll/level_0/string.h>
-#include <fll/level_0/utf.h>
-#include <fll/level_0/capability.h>
-#include <fll/level_0/color.h>
-#include <fll/level_0/compare.h>
-#include <fll/level_0/console.h>
-#include <fll/level_0/control_group.h>
-#include <fll/level_0/conversion.h>
-#include <fll/level_0/execute.h>
-#include <fll/level_0/iki.h>
-#include <fll/level_0/limit.h>
-#include <fll/level_0/path.h>
-#include <fll/level_0/pipe.h>
-#include <fll/level_0/print.h>
-#include <fll/level_0/rip.h>
-#include <fll/level_0/signal.h>
-#include <fll/level_0/socket.h>
-
-#ifndef _di_thread_support_
-  #include <fll/level_0/thread.h>
-#endif // _di_thread_support_
-
-// FLL-1 includes.
-#include <fll/level_1/conversion.h>
-#include <fll/level_1/path.h>
-#include <fll/level_1/print.h>
-
-// FLL-2 includes.
-#include <fll/level_2/error.h>
-#include <fll/level_2/print.h>
-#include <fll/level_2/program.h>
-
 // Controller includes.
-#include <program/controller/main/common/define.h>
-#include <program/controller/main/common/enumeration.h>
-#include <program/controller/main/common/print.h>
-#include <program/controller/main/common/string.h>
-#include <program/controller/main/common/string/general.h>
-#include <program/controller/main/common/string/rule.h>
-#include <program/controller/main/common/define/control.h>
-#include <program/controller/main/common/define/entry.h>
-#include <program/controller/main/common/define/rule.h>
-#include <program/controller/main/common/define/thread.h>
-#include <program/controller/main/common/enumeration/control.h>
-#include <program/controller/main/common/enumeration/entry.h>
-#include <program/controller/main/common/enumeration/rule.h>
-#include <program/controller/main/common/enumeration/process.h>
-#include <program/controller/main/common/enumeration/thread.h>
-#include <program/controller/main/common/type/cache.h>
-#include <program/controller/main/common/type/control.h>
-#include <program/controller/main/common/type/entry.h>
-#include <program/controller/main/common/type/lock.h>
-#include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/process.h>
-#include <program/controller/main/common/type/thread.h>
-#include <program/controller/main/common/type.h>
-#include <program/controller/main/common.h>
-#include <program/controller/main/path.h>
-#include <program/controller/main/print/data.h>
-#include <program/controller/main/print/debug.h>
-#include <program/controller/main/print/error.h>
-#include <program/controller/main/print/lock.h>
-#include <program/controller/main/print/message.h>
-#include <program/controller/main/print/verbose.h>
-#include <program/controller/main/print/warning.h>
-#include <program/controller/main/signal.h>
-#include <program/controller/main/thread.h>
+#include <program/controller/main/controller.h>
 #include <program/controller/controller/string.h>
 
 #ifdef __cplusplus
@@ -123,13 +43,13 @@ extern "C" {
  *     F_interrupt on (exit) signal received.
  *
  *     F_parameter (with error bit) if main is NULL or setting is NULL.
- * @param process
- *   A pointer to the current process settings.
+ * @param program
+ *   A pointer to the current program settings.
  *
  *   Must not be NULL.
  */
 #ifndef _di_controller_controller_main_
-  extern void controller_controller_main(controller_main_t * const main, controller_process_t * const process);
+  extern void controller_controller_main(controller_main_t * const main, controller_program_t * const program);
 #endif // _di_controller_controller_main_
 
 #ifdef __cplusplus
index b424ea8cc504fce6d574eb9444e692d56261b982..1e4ae6b59c50faaab694f4c575c195e77f9b7ff4 100644 (file)
@@ -3,7 +3,7 @@
 int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
 
   controller_main_t data = controller_main_t_initialize;
-  controller_process_t process = controller_process_t_initialize;
+  controller_program_t program = controller_program_t_initialize;
 
   data.program.debug.flag |= controller_print_flag_debug_e | controller_print_flag_out_e;
   data.program.error.flag |= controller_print_flag_error_e | controller_print_flag_out_e;
@@ -32,41 +32,13 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
 
   f_file_umask_get(&data.program.umask);
 
-  #ifdef _di_thread_support_
-    {
-      const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
+  {
+    const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
 
-      controller_main_setting_load(arguments, &data, &process);
-    }
-
-    controller_controller_main(&data, &process);
-  #else
-    {
-      f_thread_id_t id_signal;
-
-      memset(&id_signal, 0, sizeof(f_thread_id_t));
-
-      data.setting.state.status = f_thread_create(0, &id_signal, &controller_main_thread_signal, (void *) &data);
-
-      if (F_status_is_error(data.setting.state.status)) {
-        controller_main_print_error(&data.program.error, macro_controller_f(f_thread_create));
-      }
-      else {
-        {
-          const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
-
-          controller_main_setting_load(arguments, &data, &process);
-        }
-
-        if (!controller_main_signal_check(&data)) {
-          controller_controller_main(&data, &process);
-        }
+    controller_main_setting_load(arguments, &data, &program);
+  }
 
-        f_thread_cancel(id_signal);
-        f_thread_join(id_signal, 0);
-      }
-    }
-  #endif // _di_thread_support_
+  controller_controller_main(&data, &program);
 
   controller_main_delete(&data);
 
index 55e3b7342caf185ba61cb1772cb8a84c19c8e180..ee22aca54a54e0a360f299dac68bcf4f77b57411 100644 (file)
@@ -5,9 +5,9 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_init_main_
-  void controller_init_main(controller_main_t * const main) {
+  void controller_init_main(controller_main_t * const main, controller_program_t * const program) {
 
-    if (!main) return;
+    if (!main || !program) return;
 
     if (F_status_is_error(main->setting.state.status)) {
       if ((main->setting.flag & controller_main_flag_print_last_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
@@ -41,6 +41,9 @@ extern "C" {
       return;
     }
 
+    // @todo controller_main(&data, &program);
+    if (main->setting.state.status == F_status_set_error(F_child)) return;
+
     if (main->setting.state.status == F_status_set_error(F_interrupt)) {
       fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
     }
index 1e639bf8cecf6b9e631f5d80653958a939a94b8d..5281b47366cbe8a77fa1a09c685c8dfe12e586a7 100644 (file)
 #ifndef _controller_init_h
 #define _controller_init_h
 
-// Include pre-requirements.
-#ifndef _GNU_SOURCE
-  #define _GNU_SOURCE
-#endif // _GNU_SOURCE
-
-// Libc includes.
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-// FLL-0 includes.
-#include <fll/level_0/type.h>
-#include <fll/level_0/status.h>
-#include <fll/level_0/memory.h>
-#include <fll/level_0/string.h>
-#include <fll/level_0/utf.h>
-#include <fll/level_0/capability.h>
-#include <fll/level_0/color.h>
-#include <fll/level_0/compare.h>
-#include <fll/level_0/console.h>
-#include <fll/level_0/control_group.h>
-#include <fll/level_0/conversion.h>
-#include <fll/level_0/execute.h>
-#include <fll/level_0/iki.h>
-#include <fll/level_0/limit.h>
-#include <fll/level_0/path.h>
-#include <fll/level_0/pipe.h>
-#include <fll/level_0/print.h>
-#include <fll/level_0/rip.h>
-#include <fll/level_0/signal.h>
-#include <fll/level_0/socket.h>
-
-#ifndef _di_thread_support_
-  #include <fll/level_0/thread.h>
-#endif // _di_thread_support_
-
-// FLL-1 includes.
-#include <fll/level_1/conversion.h>
-#include <fll/level_1/path.h>
-#include <fll/level_1/print.h>
-
-// FLL-2 includes.
-#include <fll/level_2/error.h>
-#include <fll/level_2/print.h>
-#include <fll/level_2/program.h>
-
 // Controller includes.
-#include <program/controller/main/common/define.h>
-#include <program/controller/main/common/enumeration.h>
-#include <program/controller/main/common/print.h>
-#include <program/controller/main/common/string.h>
-#include <program/controller/main/common/string/general.h>
-#include <program/controller/main/common/string/rule.h>
-#include <program/controller/main/common/define/control.h>
-#include <program/controller/main/common/define/entry.h>
-#include <program/controller/main/common/define/rule.h>
-#include <program/controller/main/common/define/thread.h>
-#include <program/controller/main/common/enumeration/control.h>
-#include <program/controller/main/common/enumeration/entry.h>
-#include <program/controller/main/common/enumeration/rule.h>
-#include <program/controller/main/common/enumeration/process.h>
-#include <program/controller/main/common/enumeration/thread.h>
-#include <program/controller/main/common/type/cache.h>
-#include <program/controller/main/common/type/control.h>
-#include <program/controller/main/common/type/entry.h>
-#include <program/controller/main/common/type/lock.h>
-#include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/process.h>
-#include <program/controller/main/common/type/thread.h>
-#include <program/controller/main/common/type.h>
-#include <program/controller/main/common.h>
-#include <program/controller/main/path.h>
-#include <program/controller/main/print/data.h>
-#include <program/controller/main/print/debug.h>
-#include <program/controller/main/print/error.h>
-#include <program/controller/main/print/lock.h>
-#include <program/controller/main/print/message.h>
-#include <program/controller/main/print/verbose.h>
-#include <program/controller/main/print/warning.h>
-#include <program/controller/main/signal.h>
-#include <program/controller/main/thread.h>
+#include <program/controller/main/controller.h>
 #include <program/controller/init/string.h>
 
 #ifdef __cplusplus
@@ -121,9 +41,13 @@ extern "C" {
  *     F_interrupt on (exit) signal received.
  *
  *     F_parameter (with error bit) if main is NULL or setting is NULL.
+ * @param program
+ *   A pointer to the current program settings.
+ *
+ *   Must not be NULL.
  */
 #ifndef _di_controller_init_main_
-  extern void controller_init_main(controller_main_t * const main);
+  extern void controller_init_main(controller_main_t * const main, controller_program_t * const program);
 #endif // _di_controller_init_main_
 
 #ifdef __cplusplus
index deb3e076c65c0622d8839540b3eb358625f9b831..64c3bf521c261d95196a000555fddb6ea3142014 100644 (file)
@@ -3,7 +3,7 @@
 int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
 
   controller_main_t data = controller_main_t_initialize;
-  controller_process_t process = controller_process_t_initialize;
+  controller_program_t program = controller_program_t_initialize;
 
   data.program.debug.flag |= controller_print_flag_debug_e | controller_print_flag_out_e;
   data.program.error.flag |= controller_print_flag_error_e | controller_print_flag_out_e;
@@ -27,50 +27,21 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
   }
 
   data.setting.flag &= ~controller_main_flag_interruptible_e;
-  process.entry.pid = controller_entry_pid_disable_e;
-  process.entry.show = controller_entry_show_init_e;
+  program.entry.pid = controller_entry_pid_disable_e;
+  program.entry.show = controller_entry_show_init_e;
+  program.mode = controller_program_mode_service_e;
 
   fll_program_standard_set_up(&data.program);
 
   f_file_umask_get(&data.program.umask);
 
-  #ifdef _di_thread_support_
-    {
-      const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
+  {
+    const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
 
-      controller_main_setting_load(arguments, &data, &process);
-    }
-
-    controller_init_main(&data);
-  #else
-    {
-      f_thread_id_t id_signal;
-
-      memset(&id_signal, 0, sizeof(f_thread_id_t));
-
-      data.setting.state.status = f_thread_create(0, &id_signal, &controller_main_thread_signal, (void *) &data);
-
-      if (F_status_is_error(data.setting.state.status)) {
-        controller_main_print_error(&data.program.error, macro_controller_f(f_thread_create));
-      }
-      else {
-        {
-          const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp);
-
-          controller_main_setting_load(arguments, &data, &process);
-        }
-
-        if (!controller_main_signal_check(&data)) {
-          controller_init_main(&data);
-        }
-
-        f_thread_cancel(id_signal);
-        f_thread_join(id_signal, 0);
-      }
-    }
-  #endif // _di_thread_support_
+    controller_main_setting_load(arguments, &data, &program);
+  }
 
-  controller_main_delete(&data);
+  controller_init_main(&data, &program);
 
   fll_program_standard_set_down(&data.program);
 
index 89ba73495d3c779334b6a7c8b0f46fe7b1b3013b..8d81a1120fc90faa026b05ef97cf39f4f191046d 100644 (file)
@@ -5,9 +5,9 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_main_setting_load_
-  void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_process_t * const process) {
+  void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_program_t * const program) {
 
-    if (!main || !process) return;
+    if (!main || !program) return;
 
     main->setting.state.step_small = controller_allocation_console_d;
 
@@ -91,11 +91,11 @@ extern "C" {
     f_string_static_t * const args = main->program.parameters.arguments.array;
     f_number_unsigned_t index = 0;
 
-    process->control.server.domain = f_socket_protocol_family_local_e;
-    process->control.server.type = f_socket_type_stream_e;
-    process->control.server.form = f_socket_address_form_local_e;
+    program->control.server.domain = f_socket_protocol_family_local_e;
+    program->control.server.type = f_socket_type_stream_e;
+    program->control.server.form = f_socket_address_form_local_e;
 
-    memset(&process->control.server.address, 0, sizeof(f_socket_address_t));
+    memset(&program->control.server.address, 0, sizeof(f_socket_address_t));
 
     {
       const uint8_t codes[] = {
@@ -129,7 +129,7 @@ extern "C" {
     }
 
     // The first remaining argument represents the entry name.
-    main->setting.state.status = f_string_dynamic_append(main->program.parameters.remaining.used ? args[main->program.parameters.remaining.array[0]] : controller_default_s, &process->name_entry);
+    main->setting.state.status = f_string_dynamic_append(main->program.parameters.remaining.used ? args[main->program.parameters.remaining.array[0]] : controller_default_s, &program->name_entry);
 
     if (F_status_is_error(main->setting.state.status)) {
       if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
@@ -141,7 +141,7 @@ extern "C" {
       return;
     }
 
-    main->setting.state.status = f_path_current(F_false, &process->path_current);
+    main->setting.state.status = f_path_current(F_false, &program->path_current);
 
     if (F_status_is_error(main->setting.state.status)) {
       if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
@@ -153,15 +153,15 @@ extern "C" {
       return;
     }
 
-    process->path_setting.used = 0;
+    program->path_setting.used = 0;
 
     if (main->program.parameters.array[controller_parameter_settings_e].locations.used) {
       index = main->program.parameters.array[controller_parameter_settings_e].values.array[main->program.parameters.array[controller_parameter_settings_e].values.used - 1];
 
-      controller_path_canonical_relative(main, process->path_current, args[index], &process->path_setting);
+      controller_path_canonical_relative(main, program->path_current, args[index], &program->path_setting);
     }
     else {
-      main->setting.state.status = f_string_dynamic_append(controller_default_path_settings_s, &process->path_setting);
+      main->setting.state.status = f_string_dynamic_append(controller_default_path_settings_s, &program->path_setting);
     }
 
     if (F_status_is_error(main->setting.state.status)) {
@@ -179,23 +179,23 @@ extern "C" {
       return;
     }
 
-    if (!process->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) {
-      main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_s, &process->path_pid);
+    if (!program->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) {
+      main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_s, &program->path_pid);
 
       if (F_status_is_error_not(main->setting.state.status)) {
-        main->setting.state.status = f_string_dynamic_append(f_path_separator_s, &process->path_pid);
+        main->setting.state.status = f_string_dynamic_append(f_path_separator_s, &program->path_pid);
       }
 
       if (F_status_is_error_not(main->setting.state.status)) {
-        main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_prefix_s, &process->path_pid);
+        main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_prefix_s, &program->path_pid);
       }
 
       if (F_status_is_error_not(main->setting.state.status)) {
-        main->setting.state.status = f_string_dynamic_append(process->name_entry, &process->path_pid);
+        main->setting.state.status = f_string_dynamic_append(program->name_entry, &program->path_pid);
       }
 
       if (F_status_is_error_not(main->setting.state.status)) {
-        main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_suffix_s, &process->path_pid);
+        main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_suffix_s, &program->path_pid);
       }
 
       if (F_status_is_error(main->setting.state.status)) {
@@ -213,7 +213,7 @@ extern "C" {
       index = main->program.parameters.array[controller_parameter_cgroup_e].values.array[main->program.parameters.array[controller_parameter_cgroup_e].values.used - 1];
 
       if (args[index].used) {
-        controller_path_canonical_relative(main, process->path_current, args[index], &process->path_cgroup);
+        controller_path_canonical_relative(main, program->path_current, args[index], &program->path_cgroup);
 
         if (F_status_is_error(main->setting.state.status)) {
           if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
@@ -225,7 +225,7 @@ extern "C" {
           return;
         }
 
-        main->setting.state.status = f_string_append_assure(F_path_separator_s, 1, &process->path_cgroup);
+        main->setting.state.status = f_string_append_assure(F_path_separator_s, 1, &program->path_cgroup);
 
         if (F_status_is_error(main->setting.state.status)) {
           if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
index e320498b9c431307ea19769db6e1ddccf977ea38..62f5c176211635690a04edce8947356f2ca32449 100644 (file)
@@ -17,14 +17,14 @@ extern "C" {
 #endif
 
 /**
- * Perform the standard program setting load process.
+ * Perform the standard program setting load settings.
  *
  * This prints error messages as appropriate.
  *
  * If either main or setting is NULL, then this immediately returns without doing anything.
  *
  * @param arguments
- *   The parameters passed to the process (often referred to as command line arguments).
+ *   The parameters passed to the program (often referred to as command line arguments).
  * @param main
  *   The program and settings data.
  *
@@ -35,8 +35,8 @@ extern "C" {
  *
  *     Errors (with error bit) from: f_console_parameter_process().
  *     Errors (with error bit) from: fll_program_parameter_process_context().
- * @param process
- *   A pointer to the current process settings.
+ * @param program
+ *   A pointer to the current program settings.
  *
  *   Must not be NULL.
  *
@@ -44,7 +44,7 @@ extern "C" {
  * @see fll_program_parameter_process_context()
  */
 #ifndef _di_controller_main_setting_load_
-  extern void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_process_t * const process);
+  extern void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_program_t * const program);
 #endif // _di_controller_main_setting_load_
 
 #ifdef __cplusplus
diff --git a/sources/c/main/common/enumeration/instance.h b/sources/c/main/common/enumeration/instance.h
new file mode 100644 (file)
index 0000000..a54d954
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common instance enumerations.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_enumeration_instance_h
+#define _controller_main_common_enumeration_instance_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Instance options.
+ *
+ * controller_instance_option_*_e:
+ *   - asynchronous: The Instance runs asynchronously.
+ *   - require:      The Instance is required.
+ *   - simulate:     The Instance is being simulated.
+ *   - validate:     The Instance is being validated.
+ *   - wait:         The Instance is blocking (waiting) for all asynchronous Instances before it to complete before running.
+ */
+#ifndef _di_controller_instance_option_e_
+  enum {
+    controller_instance_option_asynchronous_e = 0x1,
+    controller_instance_option_require_e      = 0x2,
+    controller_instance_option_simulate_e     = 0x4,
+    controller_instance_option_validate_e     = 0x8,
+    controller_instance_option_wait_e         = 0x10,
+  }; // enum
+#endif // _di_controller_instance_option_e_
+
+/**
+ * Instance states.
+ *
+ * controller_instance_state_*_e:
+ *   - idle:   No instance is running for this rule.
+ *   - busy:   A instance is actively using this, and is running synchronously.
+ *   - active: A instance is actively using this, and is running asynchronously.
+ *   - done:   A instance has finished running on this and there is a thread that needs to be cleaned up.
+ */
+#ifndef _di_controller_instance_state_e_
+  enum {
+    controller_instance_state_idle_e = 1,
+    controller_instance_state_busy_e,
+    controller_instance_state_active_e,
+    controller_instance_state_done_e,
+  }; // enum
+#endif // _di_controller_instance_state_e_
+
+/**
+ * Instance types.
+ *
+ * controller_instance_type_*_e:
+ *   - entry:   The instance is started from an entry.
+ *   - exit:    The instance is started from an exit.
+ *   - control: The instance is started from a control operation.
+ */
+#ifndef _di_controller_instance_type_e_
+  enum {
+    controller_instance_type_entry_e = 1,
+    controller_instance_type_exit_e,
+    controller_instance_type_control_e,
+  }; // enum
+#endif // _di_controller_instance_type_e_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_enumeration_instance_h
similarity index 58%
rename from sources/c/main/common/enumeration/process.h
rename to sources/c/main/common/enumeration/program.h
index 7f1f98f237663f267f7df92be9b58356ecd11ade..105998021dafdd566c2efbde26c80d3985151c38 100644 (file)
@@ -5,53 +5,53 @@
  * API Version: 0.7
  * Licenses: lgpl-2.1-or-later
  *
- * Provides the common process enumerations.
+ * Provides the common program enumerations.
  *
  * This is auto-included and should not need to be explicitly included.
  */
-#ifndef _controller_main_common_enumeration_process_h
-#define _controller_main_common_enumeration_process_h
+#ifndef _controller_main_common_enumeration_program_h
+#define _controller_main_common_enumeration_program_h
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * Controller process flags.
+ * Controller program flags.
  *
  * controller_setting_flag_*_e:
  *   - interruptible: When specified, program responds to interrupt signals, otherwise block/ignore interrupt signals.
  *   - pid_created:   When specified, the program responds to interrupt signals, otherwise block/ignore interrupt signals.
  *   - failsafe:      When specified, failsafe mode is enabled, otherwise failsafe mode is disabled.
  */
-#ifndef _di_controller_process_flag_e_
+#ifndef _di_controller_program_flag_e_
   enum {
-    controller_process_flag_interruptible_e = 0x1,
-    controller_process_flag_pid_created_e   = 0x2,
-    controller_process_flag_failsafe_e      = 0x4,
+    controller_program_flag_interruptible_e = 0x1,
+    controller_program_flag_pid_created_e   = 0x2,
+    controller_program_flag_failsafe_e      = 0x4,
   }; // enum
-#endif // _di_controller_process_flag_e_
+#endif // _di_controller_program_flag_e_
 
 /**
- * Controller process mode enumeration.
+ * Controller program mode enumeration.
  *
  * controller_setting_mode_*:
  *   - helper:  Run as a helper, exiting when finished prrocess entry (and any respective exit).
  *   - program: Run as a program, exiting when finished prrocess entry (and any respective exit).
  *   - service: Run as a service, listening for requests after processing entry.
  */
-#ifndef _di_controller_process_mode_e_
+#ifndef _di_controller_program_mode_e_
   enum {
-    controller_process_mode_service_e = 0,
-    controller_process_mode_helper_e,
-    controller_process_mode_program_e,
+    controller_program_mode_service_e = 0,
+    controller_program_mode_helper_e,
+    controller_program_mode_program_e,
   }; // enum
-#endif // _di_controller_process_mode_e_
+#endif // _di_controller_program_mode_e_
 
 /**
  * Controller Process ready enumeration.
  *
- * controller_process_ready_*_e:
+ * controller_program_ready_*_e:
  *   - no:    Entry/Exit is not ready.
  *   - wait:  Entry/Exit has "ready" somewhere in the file but is not yet ready.
  *   - yes:   Entry/Exit is now ready (Entry/Exit is still being processed).
@@ -59,19 +59,19 @@ extern "C" {
  *   - fail:  Entry/Exit processing failed.
  *   - abort: Abort received before finished processing Entry/Exit.
  */
-#ifndef _di_controller_process_ready_e_
+#ifndef _di_controller_program_ready_e_
   enum {
-    controller_process_ready_no_e = 0,
-    controller_process_ready_wait_e,
-    controller_process_ready_yes_e,
-    controller_process_ready_done_e,
-    controller_process_ready_fail_e,
-    controller_process_ready_abort_e,
+    controller_program_ready_no_e = 0,
+    controller_program_ready_wait_e,
+    controller_program_ready_yes_e,
+    controller_program_ready_done_e,
+    controller_program_ready_fail_e,
+    controller_program_ready_abort_e,
   }; // enum
-#endif // _di_controller_process_ready_e_
+#endif // _di_controller_program_ready_e_
 
 #ifdef __cplusplus
 } // extern "C"
 #endif
 
-#endif // _controller_main_common_enumeration_process_h
+#endif // _controller_main_common_enumeration_program_h
index aac9a39479581fdcc82c40a3c0b5b776ac233b32..6e289c94f809e1cc5e7109f1a592b69505f98810 100644 (file)
@@ -5,17 +5,15 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_control_delete_
-  f_status_t controller_control_delete(controller_control_t * const control) {
+  void controller_control_delete(controller_control_t * const control) {
 
-    if (!control) return F_status_set_error(F_parameter);
+    if (!control) return;
 
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->cache_1.string, &control->cache_1.used, &control->cache_1.size);
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->cache_2.string, &control->cache_2.used, &control->cache_2.size);
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->cache_3.string, &control->cache_3.used, &control->cache_3.size);
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->input.string, &control->input.used, &control->input.size);
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &control->output.string, &control->output.used, &control->output.size);
-
-    return F_okay;
   }
 #endif // _di_controller_control_delete_
 
index 17fbf402673d244bb4575f4e41b8fd52df9fd6b6..23d1f58d7b624c6ea94d29b54acc80c7aba63ae1 100644 (file)
@@ -72,14 +72,9 @@ extern "C" {
  *
  * @param control
  *   The controller control data.
- *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
  */
 #ifndef _di_controller_control_delete_
-  extern f_status_t controller_control_delete(controller_control_t * const control);
+  extern void controller_control_delete(controller_control_t * const control);
 #endif // _di_controller_control_delete_
 
 #ifdef __cplusplus
index af4b6a32f9f29f560cee56ec22c537b34c5b9aa6..dc253ae2ed2dd8f419e123f373e60e64babc936b 100644 (file)
@@ -5,20 +5,18 @@ extern "C" {
 #endif
 
 #ifndef _di_controller_entry_action_delete_
-  f_status_t controller_entry_action_delete(controller_entry_action_t * const action) {
+  void controller_entry_action_delete(controller_entry_action_t * const action) {
 
-    if (!action) return F_status_set_error(F_parameter);
+    if (!action) return;
 
     f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &action->parameters.array, &action->parameters.used, &action->parameters.size, &f_string_dynamics_delete_callback);
-
-    return F_okay;
   }
 #endif // _di_controller_entry_action_delete_
 
 #ifndef _di_controller_entry_actions_delete_
-  f_status_t controller_entry_actions_delete(controller_entry_actions_t * const actions) {
+  void controller_entry_actions_delete(controller_entry_actions_t * const actions) {
 
-    if (!actions) return F_status_set_error(F_parameter);
+    if (!actions) return;
 
     actions->used = actions->size;
 
@@ -27,28 +25,24 @@ extern "C" {
     } // while
 
     f_memory_array_resize(0, sizeof(controller_entry_action_t), (void **) &actions->array, &actions->used, &actions->size);
-
-    return F_okay;
   }
 #endif // _di_controller_entry_actions_delete_
 
 #ifndef _di_controller_entry_item_delete_
-  f_status_t controller_entry_item_delete(controller_entry_item_t * const item) {
+  void controller_entry_item_delete(controller_entry_item_t * const item) {
 
-    if (!item) return F_status_set_error(F_parameter);
+    if (!item) return;
 
     f_memory_array_resize(0, sizeof(f_char_t), (void **) &item->name.string, &item->name.used, &item->name.size);
 
     controller_entry_actions_delete(&item->actions);
-
-    return F_okay;
   }
 #endif // _di_controller_entry_item_delete_
 
 #ifndef _di_controller_entry_items_delete_
-  f_status_t controller_entry_items_delete(controller_entry_items_t * const items) {
+  void controller_entry_items_delete(controller_entry_items_t * const items) {
 
-    if (!items) return F_status_set_error(F_parameter);
+    if (!items) return;
 
     items->used = items->size;
 
@@ -57,8 +51,6 @@ extern "C" {
     } // while
 
     f_memory_array_resize(0, sizeof(controller_entry_item_t), (void **) &items->array, &items->used, &items->size);
-
-    return F_okay;
   }
 #endif // _di_controller_entry_items_delete_
 
index e4874da1a4f034f0f698f543797afa9ed8bd3aa3..46c2ab13ef9f20b3c7d4627bcdddf4a7debe0ccc 100644 (file)
@@ -185,15 +185,10 @@ extern "C" {
  * @param actions
  *   The Controller Entry Action.
  *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
- *
  * @see f_memory_arrays_resize()
  */
 #ifndef _di_controller_entry_action_delete_
-  extern f_status_t controller_entry_action_delete(controller_entry_action_t * const action);
+  extern void controller_entry_action_delete(controller_entry_action_t * const action);
 #endif // _di_controller_entry_action_delete_
 
 /**
@@ -202,17 +197,12 @@ extern "C" {
  * @param actions
  *   The Controller Entry Actions.
  *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
- *
  * @see controller_entry_action_delete()
  *
  * @see f_memory_array_resize()
  */
 #ifndef _di_controller_entry_actions_delete_
-  extern f_status_t controller_entry_actions_delete(controller_entry_actions_t * const actions);
+  extern void controller_entry_actions_delete(controller_entry_actions_t * const actions);
 #endif // _di_controller_entry_actions_delete_
 
 /**
@@ -221,15 +211,10 @@ extern "C" {
  * @param item
  *   The Controller Entry Item.
  *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
- *
  * @see f_memory_array_resize()
  */
 #ifndef _di_controller_entry_item_delete_
-  extern f_status_t controller_entry_item_delete(controller_entry_item_t * const item);
+  extern void controller_entry_item_delete(controller_entry_item_t * const item);
 #endif // _di_controller_entry_item_delete_
 
 /**
@@ -238,16 +223,11 @@ extern "C" {
  * @param items
  *   The Controller Entry Items.
  *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
- *
  * @see controller_entry_item_delete()
  * @see f_memory_delete()
  */
 #ifndef _di_controller_entry_items_delete_
-  extern f_status_t controller_entry_items_delete(controller_entry_items_t * const items);
+  extern void controller_entry_items_delete(controller_entry_items_t * const items);
 #endif // _di_controller_entry_items_delete_
 
 #ifdef __cplusplus
diff --git a/sources/c/main/common/type/global.c b/sources/c/main/common/type/global.c
new file mode 100644 (file)
index 0000000..1362473
--- /dev/null
@@ -0,0 +1,9 @@
+#include "../../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/type/global.h b/sources/c/main/common/type/global.h
new file mode 100644 (file)
index 0000000..ad98ec2
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common global type structures.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_type_global_h
+#define _controller_main_common_type_global_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A wrapper used for passing a common set of all data, particularly for sharing between threads.
+ *
+ * main:    The main program data.
+ * program: The program data.
+ * thread:  The thread data.
+ */
+#ifndef _di_controller_global_t_
+  typedef struct {
+    controller_main_t *main;
+    controller_program_t *program;
+    controller_thread_t *thread;
+  } controller_global_t;
+
+  #define controller_global_t_initialize { 0, 0, 0 }
+
+  #define macro_controller_global_t_initialize(main, program, thread) { \
+    main, \
+    program, \
+    thread, \
+  }
+#endif // _di_controller_global_t_
+
+/**
+ * A structure for passing data to the interrupt state function.
+ *
+ * is_normal: Boolean designating if this is operating in a normal state.
+ * thread:    The thread data.
+ */
+#ifndef _di_controller_interrupt_t_
+  typedef struct {
+    bool is_normal;
+
+    controller_thread_t *thread;
+  } controller_interrupt_t;
+
+  #define controller_interrupt_t_initialize { \
+    F_true, \
+    0, \
+  }
+
+  #define macro_controller_interrupt_t_initialize_1(is_normal, thread) { \
+    is_normal, \
+    thread, \
+  }
+#endif // _di_controller_interrupt_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_type_global_h
diff --git a/sources/c/main/common/type/instance.c b/sources/c/main/common/type/instance.c
new file mode 100644 (file)
index 0000000..1a837a3
--- /dev/null
@@ -0,0 +1,33 @@
+#include "../../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_instance_delete_
+  void controller_instance_delete(controller_instance_t * const instance) {
+
+    if (!instance) return;
+
+    controller_cache_delete(&instance->cache);
+  }
+#endif // _di_controller_instance_delete_
+
+#ifndef _di_f_instances_delete_callback_
+  f_status_t f_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const void_array) {
+
+    {
+      controller_instance_t * const instances = (controller_instance_t *) void_array;
+
+      for (f_number_unsigned_t i = start; i < stop; ++i) {
+        controller_instance_delete(&instances[i]);
+      } // for
+    }
+
+    return F_okay;
+  }
+#endif // _di_f_instances_delete_callback_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/common/type/instance.h b/sources/c/main/common/type/instance.h
new file mode 100644 (file)
index 0000000..858dc8a
--- /dev/null
@@ -0,0 +1,171 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the common instance type structures.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_common_type_instance_h
+#define _controller_main_common_type_instance_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Controller Instance.
+ *
+ * A Controller Instance represents the processing of a single Rule for some given Rule ID.
+ *
+ * The "cache" should only be used by the function processing/executing the process and as such should not require a write lock normally needed for thread-safety.
+ * There must only be a single thread running any given Instance at a time, guaranteeing that the cache does not need read/write locks.
+ *
+ * id:        The ID of this process relative to the processes array.
+ * id_thread: The thread ID, a valid ID when state is "active", and an invalid ID when the state is "busy".
+ *
+ * action:  The action being performed.
+ * options: Configuration options for this thread.
+ * state:   The state of the process.
+ * type:    The currently active process type (from the controller_data_type_*_e).
+ * result:  The last return code from an execution of a process.
+ *
+ * active:    A read/write lock representing that something is currently using this (read locks = in use, write lock = begin deleting).
+ * lock:      A read/write lock on the structure.
+ * wait:      A thread condition to tell a process waiting process that the rule has is done being processed.
+ * wait_lock: A mutex lock for working with "wait".
+ *
+ * child:     The process id of a child process, if one is running (when forking to execute a child process).
+ * path_pids: An array of paths representing PID files.
+ * stack:     A stack used to represent dependencies as Rule ID's to avoid circular Rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
+ *
+ * rule:  A copy of the rule actively being executed.
+ * cache: The cache used by this Instance.
+ *
+ * main:    The associated main program data (of type controller_main_t).
+ * program: The associated program data.
+ * thread:  The associated thread data (of type f_thread_t).
+ */
+#ifndef _di_controller_instance_t_
+  typedef struct {
+    f_number_unsigned_t id;
+    f_thread_id_t id_thread;
+
+    uint8_t action;
+    uint8_t options;
+    uint8_t state;
+    uint8_t type;
+    int result;
+
+    f_thread_lock_t active;
+    f_thread_lock_t lock;
+    f_thread_condition_t wait;
+    f_thread_mutex_t wait_lock;
+
+    f_pids_t childs;
+    f_string_dynamics_t path_pids;
+    f_number_unsigneds_t stack;
+
+    controller_rule_t rule;
+    controller_cache_t cache;
+
+    void *main;
+    controller_program_t *program;
+    void *thread;
+  } controller_instance_t;
+
+  #define controller_instance_t_initialize { \
+    0, \
+    f_thread_id_t_initialize, \
+    0, \
+    0, \
+    0, \
+    0, \
+    0, \
+    f_thread_lock_t_initialize, \
+    f_thread_lock_t_initialize, \
+    f_thread_condition_t_initialize, \
+    f_thread_mutex_t_initialize, \
+    f_pids_t_initialize, \
+    f_string_dynamics_t_initialize, \
+    f_number_unsigneds_t_initialize, \
+    controller_rule_t_initialize, \
+    controller_cache_t_initialize, \
+    0, \
+    0, \
+    0, \
+  }
+#endif // _di_controller_instance_t_
+
+/**
+ * An array of Controller Instances.
+ *
+ * This has a circular dependency with controller_thread_t.
+ *
+ * array: An array of Instances.
+ * size:  Total amount of allocated space.
+ * used:  Total number of allocated spaces used.
+ */
+#ifndef _di_controller_instances_t_
+  typedef struct {
+    controller_instance_t **array;
+
+    f_number_unsigned_t size;
+    f_number_unsigned_t used;
+  } controller_instances_t;
+
+  #define controller_instances_t_initialize { \
+    0, \
+    0, \
+    0, \
+  }
+#endif // _di_controller_instances_t_
+
+/**
+ * Delete the Controller Instance.
+ *
+ * @param instance
+ *   The Controller Instance.
+ *
+ *   Must not be NULL.
+ *
+ * @see controller_cache_delete()
+ */
+#ifndef _di_controller_instance_delete_
+  extern void controller_instance_delete(controller_instance_t * const instance);
+#endif // _di_controller_instance_delete_
+
+/**
+ * A callback intended to be passed to f_memory_arrays_resize() for an f_instances_t structure.
+ *
+ * This is only called when shrinking the array and generally should perform de-allocations.
+ *
+ * This does not do parameter checking.
+ *
+ * @param start
+ *   The inclusive start position in the array to start deleting.
+ * @param stop
+ *   The exclusive stop position in the array to stop deleting.
+ * @param array
+ *   The array structure to delete all values of.
+ *   Must not be NULL.
+ *
+ * @return
+ *   F_okay on success.
+ *
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_instance_delete()
+ */
+#ifndef _di_f_instances_delete_callback_
+  extern f_status_t f_instances_delete_callback(const f_number_unsigned_t start, const f_number_unsigned_t stop, void * const array);
+#endif // _di_f_instances_delete_callback_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_common_type_process_h
index 563cf6e99cf77c940b845f03d89426c96a227ced..40a868c1414a1889d24edb2f4838e222f0d3cbd5 100644 (file)
@@ -4,53 +4,26 @@
 extern "C" {
 #endif
 
-#ifndef _di_controller_lock_delete_mutex_
-  void controller_lock_delete_mutex(f_thread_mutex_t *mutex) {
-
-    const f_status_t status = f_thread_mutex_delete(mutex);
-
-    if (F_status_is_error(status)) {
-      if (F_status_set_fine(status) == F_busy) {
-        if (f_thread_mutex_delete(mutex) == F_okay) {
-          mutex = 0;
-        }
-      }
-    }
-    else {
-      mutex = 0;
-    }
-  }
-#endif // _di_controller_lock_delete_mutex_
-
-#ifndef _di_controller_lock_delete_rw_
-  void controller_lock_delete_rw(f_thread_lock_t *lock) {
-
-    const f_status_t status = f_thread_lock_delete(lock);
-
-    if (F_status_is_error(status)) {
-      if (F_status_set_fine(status) == F_busy) {
-        if (f_thread_lock_delete(lock) == F_okay) {
-          lock = 0;
-        }
-      }
-    }
-    else {
-      lock = 0;
-    }
-  }
-#endif // _di_controller_lock_delete_rw_
-
 #ifndef _di_controller_lock_delete_
   void controller_lock_delete(controller_lock_t * const lock) {
 
-    controller_lock_delete_mutex(&lock->alert);
-    controller_lock_delete_mutex(&lock->cancel);
-    controller_lock_delete_mutex(&lock->print);
+    f_thread_mutex_delete(&lock->alert);
+    f_thread_mutex_delete(&lock->cancel);
+    f_thread_mutex_delete(&lock->print);
 
-    controller_lock_delete_rw(&lock->process);
-    controller_lock_delete_rw(&lock->rule);
+    f_thread_lock_delete(&lock->process);
+    f_thread_lock_delete(&lock->rule);
 
     f_thread_condition_delete(&lock->alert_condition);
+
+    memset(&lock->alert, 0, sizeof(f_thread_mutex_t));
+    memset(&lock->cancel, 0, sizeof(f_thread_mutex_t));
+    memset(&lock->print, 0, sizeof(f_thread_mutex_t));
+
+    memset(&lock->process, 0, sizeof(f_thread_lock_t));
+    memset(&lock->rule, 0, sizeof(f_thread_lock_t));
+
+    memset(&lock->alert_condition, 0, sizeof(f_thread_condition_t));
   }
 #endif // _di_controller_lock_delete_
 
index 9bd5a9048598cd791ded072b034b2636be6fc6c4..6e1b291cb4d33a7e0b542a0f48508de14286b5c1 100644 (file)
@@ -54,36 +54,6 @@ extern "C" {
 #endif // _di_controller_lock_t_
 
 /**
- * Delete the mutex lock and if the mutex lock is busy, forcibly unlock it and then delete it.
- *
- * @param mutex
- *   The mutex lock to delete.
- *   Will be set to NULL if delete succeeded.
- *
- *   This pointer cannot be "* const" because of pthread_mutex_destroy().
- *
- * @see f_thread_mutex_delete()
- */
-#ifndef _di_controller_lock_delete_mutex_
-  extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex);
-#endif // _di_controller_lock_delete_mutex_
-
-/**
- * Delete the r/w lock and if the r/w lock is busy, forcibly unlock it and then delete it.
- *
- * @param lock
- *   The r/w lock to delete.
- *   Will be set to NULL if delete succeeded.
- *
- *   This pointer cannot be "* const" because of pthread_rwlock_destroy().
- *
- * @see f_thread_lock_delete()
- */
-#ifndef _di_controller_lock_delete_rw_
-  extern void controller_lock_delete_rw(f_thread_lock_t *lock);
-#endif // _di_controller_lock_delete_rw_
-
-/**
  * Fully deallocate all memory for the given lock without caring about return status.
  *
  * @param lock
diff --git a/sources/c/main/common/type/process.c b/sources/c/main/common/type/process.c
deleted file mode 100644 (file)
index f2b4b00..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "../../controller.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _di_controller_process_delete_
-  f_status_t controller_process_delete(controller_process_t * const process) {
-
-    if (!process) return F_status_set_error(F_parameter);
-
-    f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->name_entry.string, &process->name_entry.used, &process->name_entry.size);
-    f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_cgroup.string, &process->path_cgroup.used, &process->path_cgroup.size);
-    f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_control.string, &process->path_control.used, &process->path_control.size);
-    f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_current.string, &process->path_current.used, &process->path_current.size);
-    f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_pid.string, &process->path_pid.used, &process->path_pid.size);
-    f_memory_array_resize(0, sizeof(f_char_t), (void **) &process->path_setting.string, &process->path_setting.used, &process->path_setting.size);
-
-    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->entry.define.array, &process->entry.define.used, &process->entry.define.size, &f_string_maps_delete_callback);
-    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->entry.parameter.array, &process->entry.parameter.used, &process->entry.parameter.size, &f_string_maps_delete_callback);
-    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->exit.define.array, &process->exit.define.used, &process->exit.define.size, &f_string_maps_delete_callback);
-    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &process->exit.parameter.array, &process->exit.parameter.used, &process->exit.parameter.size, &f_string_maps_delete_callback);
-
-    controller_control_delete(&process->control);
-    controller_entry_items_delete(&process->entry.items);
-    controller_entry_items_delete(&process->exit.items);
-
-    controller_rules_delete(&process->rules);
-
-    return F_okay;
-  }
-#endif // _di_controller_process_delete_
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/sources/c/main/common/type/program.c b/sources/c/main/common/type/program.c
new file mode 100644 (file)
index 0000000..6a21a67
--- /dev/null
@@ -0,0 +1,33 @@
+#include "../../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_program_delete_
+  void controller_program_delete(controller_program_t * const program) {
+
+    if (!program) return;
+
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->name_entry.string, &program->name_entry.used, &program->name_entry.size);
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_cgroup.string, &program->path_cgroup.used, &program->path_cgroup.size);
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_control.string, &program->path_control.used, &program->path_control.size);
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_current.string, &program->path_current.used, &program->path_current.size);
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_pid.string, &program->path_pid.used, &program->path_pid.size);
+    f_memory_array_resize(0, sizeof(f_char_t), (void **) &program->path_setting.string, &program->path_setting.used, &program->path_setting.size);
+
+    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->entry.define.array, &program->entry.define.used, &program->entry.define.size, &f_string_maps_delete_callback);
+    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->entry.parameter.array, &program->entry.parameter.used, &program->entry.parameter.size, &f_string_maps_delete_callback);
+    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->exit.define.array, &program->exit.define.used, &program->exit.define.size, &f_string_maps_delete_callback);
+    f_memory_arrays_resize(0, sizeof(f_string_map_t), (void **) &program->exit.parameter.array, &program->exit.parameter.used, &program->exit.parameter.size, &f_string_maps_delete_callback);
+
+    controller_control_delete(&program->control);
+    controller_entry_items_delete(&program->entry.items);
+    controller_entry_items_delete(&program->exit.items);
+    controller_rules_delete(&program->rules);
+  }
+#endif // _di_controller_program_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
similarity index 72%
rename from sources/c/main/common/type/process.h
rename to sources/c/main/common/type/program.h
index b5db1bd2b45204e82cbb2b3273aaf2aa7b27af39..01e888ed8c91812ecb8c22aa796dc8293c3e5a08 100644 (file)
@@ -5,19 +5,19 @@
  * API Version: 0.7
  * Licenses: lgpl-2.1-or-later
  *
- * Provides the common process type structures.
+ * Provides the common program type structures.
  *
  * This is auto-included and should not need to be explicitly included.
  */
-#ifndef _controller_main_common_type_process_h
-#define _controller_main_common_type_process_h
+#ifndef _controller_main_common_type_program_h
+#define _controller_main_common_type_program_h
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 /**
- * Controller process data.
+ * Controller program process data.
  *
  * ready: State representing if the settings are all loaded and is ready to run program operations.
  * mode:  Controller setting mode based on the setting mode enumerator.
@@ -36,7 +36,7 @@ extern "C" {
  * exit:    The Exit settings.
  * rules:   All rules and their respective settings.
  */
-#ifndef _di_controller_process_t_
+#ifndef _di_controller_program_t_
   typedef struct {
     uint8_t ready;
     uint8_t mode;
@@ -54,9 +54,9 @@ extern "C" {
     controller_entry_t entry;
     controller_entry_t exit;
     controller_rules_t rules;
-  } controller_process_t;
+  } controller_program_t;
 
-  #define controller_process_t_initialize { \
+  #define controller_program_t_initialize { \
     0, \
     0, \
     0, \
@@ -71,27 +71,22 @@ extern "C" {
     controller_entry_t_initialize, \
     controller_rules_t_initialize, \
   }
-#endif // _di_controller_process_t_
+#endif // _di_controller_program_t_
 
 /**
- * Delete the Controller process data.
+ * Delete the Controller program data.
  *
- * @param process
- *   A pointer to the current process settings.
+ * @param program
+ *   A pointer to the current program settings.
  *
  *   Must not be NULL.
- *
- * @return
- *   F_okay on success.
- *
- *   F_parameter (with error bit) if a parameter is invalid.
  */
-#ifndef _di_controller_process_delete_
-  extern f_status_t controller_process_delete(controller_process_t * const process);
-#endif // _di_controller_process_delete_
+#ifndef _di_controller_program_delete_
+  extern void controller_program_delete(controller_program_t * const program);
+#endif // _di_controller_program_delete_
 
 #ifdef __cplusplus
 } // extern "C"
 #endif
 
-#endif // _controller_main_common_type_process_h
+#endif // _controller_main_common_type_program_h
index f05607a926290c9f4d5e6297580dc0a54c0442ac..f4ae5a160680aca4e60256c831ed36e02e700190 100644 (file)
@@ -274,7 +274,7 @@ extern "C" {
     uid_t user;
     gid_t group;
 
-    f_time_spec_t timestamp;
+    f_time_simple_t timestamp;
 
     f_string_dynamic_t alias;
     f_string_dynamic_t engine;
@@ -323,7 +323,7 @@ extern "C" {
     0, \
     0, \
     0, \
-    f_time_spec_t_initialize, \
+    f_time_simple_t_initialize, \
     f_string_dynamic_t_initialize, \
     f_string_dynamic_t_initialize, \
     f_string_dynamic_t_initialize, \
index 8a97919f0c6ab688a3dd89c53b1c62c664259b69..1f497d2371329b00ed25c79b82503f622d7e84c6 100644 (file)
@@ -10,8 +10,9 @@ extern "C" {
     if (!thread) return;
 
     controller_lock_delete(&thread->lock);
-    controller_process_delete(&thread->process);
     controller_cache_delete(&thread->cache);
+
+    f_memory_arrays_resize(0, sizeof(controller_instance_t), (void **) &thread->instances.array, &thread->instances.used, &thread->instances.size, &f_instances_delete_callback);
   }
 #endif // _di_controller_thread_delete_
 
index a3ddd4dd9b5af9001c33befb4495eea1a1902a78..2970a3cf3196f538f10750917f5585ad843bfaf4 100644 (file)
@@ -23,7 +23,7 @@ extern "C" {
  *
  * The "enabled" and "signal" utilize the lock: lock.process.
  *
- * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE.
+ * enabled: F_true when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when F_false.
  * signal:  The code of any signal received.
  * status:  A status used by the main entry/rule processing thread for synchronous operations.
  *
@@ -33,12 +33,12 @@ extern "C" {
  * id_rule:    The thread ID representing the Rule Process.
  * id_signal:  The thread ID representing the Signal Process.
  *
- * lock:    A r/w lock for operating on this structure.
- * process: All Rule Process thread data.
- * cache:   A cache used by the main entry/rule processing thread for synchronous operations.
+ * lock:      A r/w lock for operating on this structure.
+ * instances: All Rule Instance thread data.
+ * cache:     A cache used by the main entry/rule processing thread for synchronous operations.
  */
 #ifndef _di_controller_thread_t_
-  typedef struct {
+  typedef struct controller_thread_t_ {
     uint8_t enabled;
     int signal;
     f_status_t status;
@@ -50,7 +50,7 @@ extern "C" {
     f_thread_id_t id_signal;
 
     controller_lock_t lock;
-    controller_process_t process;
+    controller_instances_t instances;
     controller_cache_t cache;
   } controller_thread_t;
 
@@ -64,7 +64,7 @@ extern "C" {
     f_thread_id_t_initialize, \
     f_thread_id_t_initialize, \
     controller_lock_t_initialize, \
-    controller_processs_t_initialize, \
+    controller_instances_t_initialize, \
     controller_cache_t_initialize, \
   }
 #endif // _di_controller_thread_t_
index 0d635086fff4cbd9a1c4da056b73bc32a88cd269..2743bcd388010e0461398245255fbc15a0495614 100644 (file)
 #include <program/controller/main/common/enumeration/entry.h>
 #include <program/controller/main/common/enumeration/rule.h>
 #include <program/controller/main/common/enumeration/process.h>
+#include <program/controller/main/common/enumeration/program.h>
 #include <program/controller/main/common/enumeration/thread.h>
 #include <program/controller/main/common/type/cache.h>
 #include <program/controller/main/common/type/control.h>
 #include <program/controller/main/common/type/entry.h>
 #include <program/controller/main/common/type/lock.h>
 #include <program/controller/main/common/type/rule.h>
-#include <program/controller/main/common/type/process.h>
+#include <program/controller/main/common/type/program.h>
+#include <program/controller/main/common/type/instance.h>
 #include <program/controller/main/common/type/thread.h>
 #include <program/controller/main/common/type.h>
+#include <program/controller/main/common/type/global.h>
 #include <program/controller/main/common.h>
 #include <program/controller/main/path.h>
 #include <program/controller/main/print/data.h>
@@ -93,6 +96,8 @@
 #include <program/controller/main/print/verbose.h>
 #include <program/controller/main/print/warning.h>
 #include <program/controller/main/signal.h>
+#include <program/controller/main/thread/is.h>
+#include <program/controller/main/thread/instance.h>
 #include <program/controller/main/thread.h>
 
 #ifdef __cplusplus
index 0ee495fd1c6ee5e56086d3d346420a2a4e64f584..5bc6c206a9dddbd5db220ec26e13f6684c18e897 100644 (file)
@@ -32,6 +32,18 @@ extern "C" {
   }
 #endif // _di_controller_main_print_error_file_
 
+#ifndef _di_controller_main_print_error_status_
+  f_status_t controller_main_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status) {
+
+    if (!print) return F_status_set_error(F_output_not);
+    if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+    fll_error_print(print, status, function, fll_error_file_flag_fallback_e);
+
+    return F_okay;
+  }
+#endif // _di_controller_main_print_error_status_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index c29205bf900c5f57a90cf852521663bf9b9ca8ff..71e866532304aa16a0fded80a44e964b039778ff 100644 (file)
@@ -21,7 +21,6 @@ extern "C" {
  *
  * @param print
  *   The output structure to print to.
- *
  *   Must not be NULL.
  *
  *   This does not alter print.custom.setting.state.status.
@@ -45,7 +44,6 @@ extern "C" {
  *
  * @param print
  *   The output structure to print to.
- *
  *   Must not be NULL.
  *
  *   The print.custom is expected to be of type fss_read_main_t.
@@ -73,6 +71,31 @@ extern "C" {
   extern f_status_t controller_main_print_error_file(fl_print_t * const print, const f_string_t function, const f_string_static_t name, const f_string_static_t operation, const uint8_t type);
 #endif // _di_controller_main_print_error_file_
 
+/**
+ * Print generic error message regarding a function failing in some way.
+ *
+ * @param print
+ *   The output structure to print to.
+ *   Must not be NULL.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param function
+ *   The name of the function associated with the error.
+ * @param status
+ *   The status code to print an error message about.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_controller_main_print_error_status_
+  extern f_status_t controller_main_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status);
+#endif // _di_controller_main_print_error_status_
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
index 2214fb7724cde75116fb435516d66c182539a703..29c20c072461882b414bbe3d1ea975e3cd290b12 100644 (file)
@@ -4,18 +4,98 @@
 extern "C" {
 #endif
 
-#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
-  void * controller_main_thread_signal(void * const main) {
+#ifndef _di_controller_main_thread_signal_
+  void controller_main_thread_signal(controller_global_t * const global, const bool is_normal) {
 
-    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+    if (!global || !global->main || !global->thread) return;
+    if (!controller_main_thread_is_enabled(is_normal, global->thread)) return;
+    if (!(global->main->setting.flag & controller_main_flag_interruptible_e)) return;
+
+    f_status_t status = F_okay;
+    siginfo_t information;
+    f_time_spec_t time = f_time_spec_t_initialize;
+
+    while (controller_main_thread_is_enabled(is_normal, global->thread)) {
+
+      controller_time_now(controller_thread_exit_ready_timeout_seconds_d, controller_thread_exit_ready_timeout_nanoseconds_d, &time);
+
+      memset((void *) &information, 0, sizeof(siginfo_t));
+
+      status = f_signal_wait_until(&global->main->program.signal.set, &time, &information);
+      if (status == F_time_out) 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) {
+        global->thread->signal = information.si_signo;
+
+        controller_thread_instance_cancel(global, is_normal, controller_thread_cancel_signal_e);
+
+        break;
+      }
+    } // while
+  }
+#endif // _di_controller_main_thread_signal_
 
-    if (main) {
-      controller_main_signal_handler((controller_main_t *) main);
+#ifndef _di_controller_main_thread_signal_state_fss_
+  f_status_t controller_main_thread_signal_state_fss(f_state_t * const state, void * const internal) {
+
+    if (!state || !state->custom || !internal) return F_interrupt_not;
+
+    controller_interrupt_t * const custom = (controller_interrupt_t *) state->custom;
+    controller_thread_t * const thread = custom->thread;
+
+    if (!controller_main_thread_is_enabled(custom->is_normal, thread)) {
+      return F_status_set_error(F_interrupt);
+    }
+
+    if (thread->signal == F_signal_interrupt || thread->signal == F_signal_abort || thread->signal == F_signal_quit || thread->signal == F_signal_termination) {
+      return F_status_set_error(F_interrupt);
     }
 
+    return F_interrupt_not;
+  }
+#endif // _di_controller_main_thread_signal_state_fss_
+
+#ifndef _di_controller_main_thread_signal_state_iki_
+  f_status_t controller_main_thread_signal_state_iki(f_state_t * const state, void * const internal) {
+
+    if (!state || !state->custom || !internal) return F_interrupt_not;
+
+    controller_interrupt_t * const custom = (controller_interrupt_t *) state->custom;
+    controller_thread_t * const thread = custom->thread;
+
+    if (!controller_main_thread_is_enabled(custom->is_normal, thread)) {
+      return F_status_set_error(F_interrupt);
+    }
+
+    if (thread->signal == F_signal_interrupt || thread->signal == F_signal_abort || thread->signal == F_signal_quit || thread->signal == F_signal_termination) {
+      return F_status_set_error(F_interrupt);
+    }
+
+    return F_interrupt_not;
+  }
+#endif // _di_controller_main_thread_signal_state_iki_
+
+#ifndef _di_controller_main_thread_signal_normal_
+  void * controller_main_thread_signal_normal(void * const global) {
+
+    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+    controller_main_thread_signal((controller_global_t *) global, F_true);
+
+    return 0;
+  }
+#endif // _di_controller_main_thread_signal_normal_
+
+#ifndef _di_controller_main_thread_signal_other_
+  void * controller_main_thread_signal_other(void * const arguments) {
+
+    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+    controller_main_thread_signal((controller_global_t *) global, F_false);
+
     return 0;
   }
-#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+#endif // _di_controller_main_thread_signal_other_
 
 #ifdef __cplusplus
 } // extern "C"
index d6fa55e1732ab65a08e8599aa8acd28594c9b9c1..3290be09a124f4725805c26d6aac63c86dc02cbb 100644 (file)
 #define _controller_main_thread_h
 
 /**
- * Thread handler for signals/interrupts.
+ * Thread for handling signals/interrupts.
  *
- * If main.signal is non-zero, then this handles the following signals:
- *   - F_signal_abort
- *   - F_signal_broken_pipe
- *   - F_signal_hangup
- *   - F_signal_interrupt
- *   - F_signal_quit
- *   - F_signal_termination
- *
- * @param main
- *   The program and settings data.
+ * @param global
+ *   The global data.
  *
  *   Must not be NULL.
+ * @param is_normal
+ *   If TRUE, then process as if this operates during a normal operation (entry and control).
+ *   If FALSE, then process as if this operates during a an exit operation.
+ */
+#ifndef _di_controller_main_thread_signal_
+  extern void controller_main_thread_signal(controller_global_t * const global, const bool is_normal);
+#endif // _di_controller_main_thread_signal_
+
+/**
+ * Callback passed to FSS functions for checking for interrupts.
+ *
+ * @param state
+ *   The state data.
+ * @param internal
+ *   Not used.
+ *
+ * @return
+ *   F_interrupt_not if not interrupted.
+ *
+ *   F_interrupt (with error bit) if interrupted.
+ */
+#ifndef _di_controller_main_thread_signal_state_fss_
+  extern f_status_t controller_main_thread_signal_state_fss(f_state_t * const state, void * const internal);
+#endif // _di_controller_main_thread_signal_state_fss_
+
+/**
+ * Callback passed to IKI functions for checking for interrupts.
+ *
+ * @param state
+ *   The state data.
+ * @param internal
+ *   Not used.
+ *
+ * @return
+ *   F_interrupt_not if not interrupted.
  *
- *   Must be of type controller_main_t.
+ *   F_interrupt (with error bit) if interrupted.
+ */
+#ifndef _di_controller_main_thread_signal_state_iki_
+  extern f_status_t controller_main_thread_signal_state_iki(f_state_t * const state, void * const internal);
+#endif // _di_controller_main_thread_signal_state_iki_
+
+/**
+ * Thread for handling signals/interrupts during normal operations.
+ *
+ * @param arguments
+ *   The thread arguments.
+ *   Must be of type controller_global_t.
  *
  * @return
  *   0, always.
  *
- * @see f_thread_cancel_state_set()
+ * @see controller_main_thread_signal()
+ */
+#ifndef _di_controller_main_thread_signal_normal_
+  extern void * controller_main_thread_signal_normal(void * const arguments);
+#endif // _di_controller_main_thread_signal_normal_
+
+/**
+ * Thread for handling signals/interrupts during other operations.
+ *
+ * @param arguments
+ *   The thread arguments.
+ *   Must be of type controller_global_t.
+ *
+ * @return
+ *   0, always.
  *
  * @see controller_main_thread_signal()
  */
-#if !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
-  extern void * controller_main_thread_signal(void * const main);
-#endif // !defined(_di_controller_main_thread_signal_) && !defined(_di_thread_support_)
+#ifndef _di_controller_main_thread_signal_other_
+  extern void * controller_main_thread_signal_other(void * const arguments);
+#endif // _di_controller_main_thread_signal_other_
 
 #ifdef __cplusplus
 } // extern "C"
diff --git a/sources/c/main/thread/instance.c b/sources/c/main/thread/instance.c
new file mode 100644 (file)
index 0000000..3da4a86
--- /dev/null
@@ -0,0 +1,434 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_thread_instance_
+  void controller_thread_instance(const uint8_t is_normal, controller_instance_t * const instance) {
+
+    if (!instance) return;
+    if (!controller_thread_is_enabled(is_normal, instance->main_thread)) return;
+
+    const f_status_t status = controller_rule_process_do(controller_process_option_asynchronous_d, instance);
+
+    // A forked child instance should deallocate memory on exit.
+    // It seems that this function doesn't return to the calling thread for a forked child instance, even with the "return 0;" below.
+    // Deallocate as much as possible.
+    if (status == F_child) {
+      controller_thread_delete_simple(instance->main_thread);
+      controller_process_delete(instance->program);
+      controller_main_delete(instance->main_data);
+
+      // According to some man pages, pthread_exit() calls exit(0), so expliticly exit to ensure a non-zero code is returned when needed.
+      if (instance->main_data->program.child) exit(instance->main_data->program.child);
+    }
+  }
+#endif // _di_controller_thread_instance_
+
+#ifndef _di_controller_thread_instance_cancel_
+  void controller_thread_instance_cancel(controller_global_t * const global, const uint8_t is_normal, const uint8_t by) {
+
+    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);
+
+      return;
+    }
+
+    controller_entry_t * const entry = is_normal ? &global->setting->entry : &global->setting->exit;
+    controller_instance_t *instance = 0;
+
+    f_time_spec_t time = f_time_spec_t_initialize;
+    f_status_t status = F_okay;
+    f_number_unsigned_t i = 0;
+    f_number_unsigned_t j = 0;
+    pid_t pid = 0;
+
+    // A simple but inaccurate interval counter (expect this to be replaced in the future).
+    const f_number_unsigned_t interval_nanoseconds = entry->timeout_exit < 1000 ? (entry->timeout_exit < 100 ? 5000000 : 100000000) : 500000000;
+    const f_number_unsigned_t interval_milliseconds = entry->timeout_exit < 1000 ? (entry->timeout_exit < 100 ? 5 : 100) : 500;
+
+    time.tv_sec = 0;
+    time.tv_nsec = interval_nanoseconds;
+
+    if (global->setting->mode == controller_setting_mode_helper_e && global->main->program.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->instances.used; ++i) {
+
+        if (!global->thread->instances.array[i]) continue;
+
+        instance = global->thread->instances.array[i];
+
+        if (!instance->id_thread) continue;
+
+        controller_thread_detach(&instance->id_thread);
+
+        instance->id_thread = 0;
+      } // for
+    }
+
+    // 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);
+
+    if (F_status_is_error(status)) {
+      global->thread->enabled = controller_thread_enabled_not_e;
+    }
+    else {
+      if (by == controller_thread_cancel_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;
+      }
+      else if (by == controller_thread_cancel_exit_execute_e) {
+        global->thread->enabled = controller_thread_enabled_exit_execute_e;
+      }
+      else {
+        global->thread->enabled = controller_thread_enabled_exit_e;
+      }
+
+      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);
+
+      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);
+
+      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);
+
+      global->thread->id_signal = 0;
+    }
+
+    if (global->setting->mode == controller_setting_mode_helper_e && global->main->program.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->instances.used; ++i) {
+
+      if (!global->thread->instances.array[i]) continue;
+
+      instance = global->thread->instances.array[i];
+
+      // Do not cancel exit instances, when not performing "execute" during exit.
+      if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) {
+        continue;
+      }
+
+      for (j = 0; j < instance->childs.used; ++j) {
+
+        if (instance->childs.array[j] > 0) {
+          f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, instance->childs.array[j]);
+        }
+      } // for
+
+      for (j = 0; j < instance->path_pids.used; ++j) {
+
+        if (instance->path_pids.array[j].used && f_file_exists(instance->path_pids.array[j], F_true) == F_true) {
+          status = controller_file_pid_read(instance->path_pids.array[j], &pid);
+
+          if (pid) {
+            f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, pid);
+          }
+        }
+      } // for
+    } // for
+
+    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->instances.used && lapsed < entry->timeout_exit; ++i) {
+
+        if (!global->thread->instances.array[i]) continue;
+
+        instance = global->thread->instances.array[i];
+
+        // Do not wait for instances, when not performing "execute" during exit.
+        if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) {
+          continue;
+        }
+
+        for (j = 0; j < instance->childs.used && lapsed < entry->timeout_exit; ++j) {
+
+          while (instance->childs.array[j] > 0 && lapsed < entry->timeout_exit) {
+
+            // A hackish way to determine if the child instance exists while waiting.
+            if (getpgid(instance->childs.array[j]) >= 0) {
+              time.tv_sec = 0;
+              time.tv_nsec = interval_nanoseconds;
+
+              f_time_sleep_spec(&time, 0);
+
+              lapsed += interval_milliseconds;
+            }
+            else {
+              instance->childs.array[j] = 0;
+
+              break;
+            }
+          } // while
+        } // for
+
+        for (j = 0; j < instance->path_pids.used && lapsed < entry->timeout_exit; ++j) {
+
+          if (instance->path_pids.array[j].used && f_file_exists(instance->path_pids.array[j], F_true) == F_true) {
+            status = controller_file_pid_read(instance->path_pids.array[j], &pid);
+
+            if (pid) {
+              while (lapsed < entry->timeout_exit) {
+
+                // A hackish way to determine if the instance exists while waiting.
+                if (getpgid(pid) >= 0) {
+                  time.tv_sec = 0;
+                  time.tv_nsec = interval_nanoseconds;
+
+                  f_time_sleep_spec(&time, 0);
+
+                  lapsed += interval_milliseconds;
+                }
+                else {
+                  instance->path_pids.array[j].used = 0;
+
+                  break;
+                }
+              } // while
+            }
+          }
+        } // for
+      } // for
+    }
+
+    for (i = 0; i < global->thread->instances.size; ++i) {
+
+      if (!global->thread->instances.array[i]) continue;
+
+      instance = global->thread->instances.array[i];
+
+      // Do not kill exit instances, when not performing "execute" during exit.
+      if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+
+      if (instance->id_thread) {
+        if (instance->childs.used) {
+          for (j = 0; j < instance->childs.used; ++j) {
+
+            if (instance->childs.array[j] > 0) {
+              f_signal_send(F_signal_kill, instance->childs.array[j]);
+
+              time.tv_sec = 0;
+              time.tv_nsec = controller_thread_exit_process_cancel_wait_d;
+
+              instance->childs.array[j] = 0;
+            }
+          } // for
+
+          f_time_sleep_spec(&time, 0);
+        }
+
+        f_thread_join(instance->id_thread, 0);
+
+        instance->id_thread = 0;
+      }
+
+      if (!(entry->flag & controller_entry_flag_timeout_exit_no_e)) {
+        for (j = 0; j < instance->childs.size; ++j) {
+
+          // Do not kill exit processes, when not performing "execute" during exit.
+          if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+
+          if (instance->childs.array[j]) {
+
+            // A hackish way to determine if the child instance exists, and if it does then forcibly terminate it.
+            if (getpgid(instance->childs.array[j]) >= 0) {
+              f_signal_send(F_signal_kill, instance->childs.array[j]);
+            }
+
+            instance->childs.array[j] = 0;
+          }
+        } // for
+      }
+
+      if (!(entry->flag & controller_entry_flag_timeout_exit_no_e)) {
+        for (j = 0; j < instance->path_pids.used; ++j) {
+
+          // Do not kill exit processes, when not performing "execute" during exit.
+          if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+
+          if (f_file_exists(instance->path_pids.array[j], F_true) == F_true) {
+            status = controller_file_pid_read(instance->path_pids.array[j], &pid);
+
+            if (pid) {
+              f_signal_send(F_signal_kill, pid);
+            }
+
+            f_file_remove(instance->path_pids.array[j]);
+            instance->path_pids.array[j].used = 0;
+          }
+        } // for
+      }
+
+      // Shrink the child pids as much as possible.
+      while (instance->childs.used) {
+
+        // Do not shrink below an exit instances, when not performing "execute" during exit.
+        if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) break;
+        if (instance->childs.array[j] > 0) break;
+
+        --instance->childs.used;
+      } // while
+
+      // Shrink the path pids as much as possible.
+      while (instance->path_pids.used) {
+
+        // Do not shrink below an exit instances, when not performing "execute" during exit.
+        if (instance->type == controller_data_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) break;
+        if (instance->path_pids.array[j].used) break;
+
+        --instance->path_pids.used;
+      } // while
+    } // for
+
+    f_thread_mutex_unlock(&global->thread->lock.cancel);
+  }
+#endif // _di_controller_thread_instance_cancel_
+
+#ifndef _di_controller_thread_instance_exit_
+  void controller_thread_instance_exit(controller_global_t * const global) {
+
+    if (!global) return;
+
+    if (global->thread->enabled != controller_thread_enabled_exit_e) return;
+
+    if (global->setting->ready == controller_setting_ready_done_e) {
+
+      // The exit processing runs using the entry thread.
+      if (global->thread->id_entry) {
+        f_thread_cancel(global->thread->id_entry);
+        f_thread_join(global->thread->id_entry, 0);
+
+        global->thread->id_entry = 0;
+      }
+
+      // Restart the signal thread to allow for signals while operating the Exit.
+      if (!global->thread->id_signal) {
+        f_thread_create(0, &global->thread->id_signal, &controller_thread_signal_other, (void *) global);
+      }
+
+      const controller_main_entry_t entry = macro_controller_main_entry_t_initialize_1(global, global->setting);
+
+      f_status_t status = f_thread_create(0, &global->thread->id_entry, &controller_thread_exit, (void *) &entry);
+
+      if (F_status_is_error(status)) {
+        if (global->main->program.error.verbosity > f_console_verbosity_quiet_e) {
+          controller_main_print_error_status(&global->main->program.error, macro_controller_f(f_thread_create), F_status_set_fine(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);
+        }
+        else {
+          global->thread->enabled = controller_thread_enabled_not_e;
+        }
+      }
+      else {
+        f_time_spec_t time = f_time_spec_t_initialize;
+
+        do {
+          status = f_thread_mutex_lock(&global->thread->lock.alert);
+
+          if (F_status_is_error(status)) {
+            global->thread->enabled = controller_thread_enabled_not_e;
+
+            break;
+          }
+
+          controller_time(controller_thread_exit_ready_timeout_seconds_d, controller_thread_exit_ready_timeout_nanoseconds_d, &time);
+
+          status = f_thread_condition_wait_timed(&time, &global->thread->lock.alert_condition, &global->thread->lock.alert);
+
+          f_thread_mutex_unlock(&global->thread->lock.alert);
+
+        } 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);
+          }
+          else {
+            global->thread->enabled = controller_thread_enabled_not_e;
+          }
+        }
+      }
+
+      // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
+      if (global->thread->id_signal) {
+        f_thread_cancel(global->thread->id_signal);
+        f_thread_join(global->thread->id_signal, 0);
+
+        global->thread->id_signal = 0;
+      }
+
+      controller_thread_instance_cancel(*global, F_false, controller_thread_cancel_exit_e);
+    }
+    else {
+      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);
+      }
+      else {
+        global->thread->enabled = controller_thread_enabled_not_e;
+      }
+    }
+  }
+#endif // _di_controller_thread_instance_exit_
+
+#ifndef _di_controller_thread_instance_normal_
+  void * controller_thread_instance_normal(void * const arguments) {
+
+    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+    controller_thread_instance(F_true, (controller_instance_t *) arguments);
+
+    return 0;
+  }
+#endif // _di_controller_thread_instance_normal_
+
+#ifndef _di_controller_thread_instance_other_
+  void * controller_thread_instance_other(void * const arguments) {
+
+    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+    controller_thread_instance(F_false, (controller_instance_t *) arguments);
+
+    return 0;
+  }
+#endif // _di_controller_thread_instance_other_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/thread/instance.h b/sources/c/main/thread/instance.h
new file mode 100644 (file)
index 0000000..ee13a82
--- /dev/null
@@ -0,0 +1,103 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the thread "instance" functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_thread_instance_h
+#define _controller_main_thread_instance_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Asynchronously execute a Rule process.
+ *
+ * @param is_normal
+ *   If F_true, then process as if this operates during a normal operation (entry and control).
+ *   If F_false, then process as if this operates during a an exit operation.
+ * @param process
+ *   The process data.
+ *
+ * @see controller_rule_process_do()
+ */
+#ifndef _di_controller_thread_instance_
+  extern void controller_thread_instance(const uint8_t is_normal, controller_instance_t * const instance);
+#endif // _di_controller_thread_instance_
+
+/**
+ * Cancel all process threads.
+ *
+ * @param global
+ *   The global thread data.
+ *
+ *   This does not alter global.main.setting.state.status.
+ * @param is_normal
+ *   If F_true, then process as if this operates during a normal operation (entry and control).
+ *   If F_false, then process as if this operates during a an exit operation.
+ * @param by
+ *   Designate the way in which the cancellation should operate.
+ *
+ *   If controller_thread_cancel_signal_e, then this was called from within the signal handling thread, so do not cancel the signal thread.
+ *   If controller_thread_cancel_call_e, then this was not called from within the signal handling thread, so cancel the signal thread.
+ *   If controller_thread_cancel_execute_e, then this was called from within the Entry/Exit for executing a process, so cancel the signal thread but not the Entry thread.
+ */
+#ifndef _di_controller_thread_instance_cancel_
+  extern void controller_thread_instance_cancel(controller_global_t * const global, const uint8_t is_normal, const uint8_t by);
+#endif // _di_controller_thread_instance_cancel_
+
+/**
+ * Process the Exit file, if applicable.
+ *
+ * @param global
+ *   The global thread data.
+ *
+ *   This does not alter global.main.setting.state.status.
+ */
+#ifndef _di_controller_thread_instance_exit_
+  extern void controller_thread_instance_exit(controller_global_t * const global);
+#endif // _di_controller_thread_instance_exit_
+
+/**
+ * Asynchronously execute a Rule process during normal operations.
+ *
+ * @param arguments
+ *   The thread arguments.
+ *   Must be of type controller_data_t.
+ *
+ * @return
+ *   0, always.
+ *
+ * @see controller_thread_instance()
+ */
+#ifndef _di_controller_thread_instance_normal_
+  extern void * controller_thread_instance_normal(void * const arguments);
+#endif // _di_controller_thread_instance_normal_
+
+/**
+ * Asynchronously execute a Rule process during other operations.
+ *
+ * @param arguments
+ *   The thread arguments.
+ *   Must be of type controller_data_t.
+ *
+ * @return
+ *   0, always.
+ *
+ * @see controller_thread_instance()
+ */
+#ifndef _di_controller_thread_instance_other_
+  extern void * controller_thread_instance_other(void * const arguments);
+#endif // _di_controller_thread_instance_other_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_thread_instance_h
diff --git a/sources/c/main/thread/is.c b/sources/c/main/thread/is.c
new file mode 100644 (file)
index 0000000..bfa4d09
--- /dev/null
@@ -0,0 +1,34 @@
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_main_thread_is_enabled_
+  f_status_t controller_main_thread_is_enabled(const uint8_t is_normal, controller_thread_t * const thread) {
+
+    if (!thread) return F_false;
+
+    return is_normal ? thread->enabled == controller_thread_enabled_e : thread->enabled;
+  }
+#endif // _di_controller_main_thread_is_enabled_
+
+#ifndef _di_controller_main_thread_is_enabled_process_
+  f_status_t controller_main_thread_is_enabled_process(controller_instance_t * const instance, controller_thread_t * const thread) {
+
+    if (!instance) return F_false;
+
+    return controller_main_thread_is_enabled_process_type(instance->type, thread);
+  }
+#endif // _di_controller_main_thread_is_enabled_process_
+
+#ifndef _di_controller_main_thread_is_enabled_process_type_
+  f_status_t controller_main_thread_is_enabled_process_type(const uint8_t type, controller_thread_t * const thread) {
+
+    return controller_main_thread_is_enabled(type != controller_data_type_exit_e, thread);
+  }
+#endif // _di_controller_main_thread_is_enabled_process_type_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/thread/is.h b/sources/c/main/thread/is.h
new file mode 100644 (file)
index 0000000..3a07baa
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the thread "is" functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_thread_is_h
+#define _controller_main_thread_is_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Check to see if thread is enabled for the normal operations like entry and control or for exit operations.
+ *
+ * @param is_normal
+ *   If TRUE, then process as if this operates during a normal operation (entry and control).
+ *   If FALSE, then process as if this operates during a an exit operation.
+ * @param thread
+ *   The thread data.
+ *
+ * @return
+ *   F_true when enabled.
+ *   F_false when disabled.
+ */
+#ifndef _di_controller_main_thread_is_enabled_
+  extern f_status_t controller_main_thread_is_enabled(const uint8_t is_normal, controller_thread_t * const thread);
+#endif // _di_controller_main_thread_is_enabled_
+
+/**
+ * Check to see if thread is enabled for the normal operations like entry and control or for exit operations for some process.
+ *
+ * @param instance
+ *   The instance to use when checking if thread is enabled.
+ * @param thread
+ *   The thread data.
+ *
+ * @return
+ *   F_true when enabled.
+ *   F_false when disabled or when parameter is invalid..
+ *
+ * @see controller_main_thread_is_enabled_process_type()
+ */
+#ifndef _di_controller_main_thread_is_enabled_process_
+  extern f_status_t controller_main_thread_is_enabled_process(controller_instance_t * const instance, controller_thread_t * const thread);
+#endif // _di_controller_main_thread_is_enabled_process_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_thread_is_h
diff --git a/sources/c/main/time.c b/sources/c/main/time.c
new file mode 100644 (file)
index 0000000..99b7205
--- /dev/null
@@ -0,0 +1,79 @@
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_time_now_
+  void controller_time_now(const time_t seconds, const long nanoseconds, f_time_spec_t * const time) {
+
+    {
+      f_time_value_t now = f_time_value_t_initialize;
+
+      f_time_of_day_get(&now);
+
+      time->tv_sec = now.tv_sec + seconds;
+      time->tv_nsec = (now.tv_usec * 1000) + nanoseconds;
+    }
+
+    // If tv_nsec is 1 second or greater, then increment seconds.
+    if (time->tv_nsec >= 1000000000) {
+      ++(time->tv_sec);
+
+      time->tv_nsec -= 1000000000;
+    }
+  }
+#endif // _di_controller_time_now_
+
+/*
+#ifndef _di_controller_time_milliseconds_
+  f_time_spec_t controller_time_milliseconds(const f_number_unsigned_t milliseconds) {
+
+    f_time_spec_t time;
+
+    f_time_spec_millisecond(0, milliseconds, &time);
+
+    return time;
+  }
+#endif // _di_controller_time_milliseconds_
+
+#ifndef _di_controller_time_seconds_
+  f_time_simple_t controller_time_seconds(const f_number_unsigned_t seconds) {
+
+    f_time_spec_t time;
+
+    f_time_spec_millisecond(seconds, 0, &time);
+
+    return time;
+  }
+#endif // _di_controller_time_seconds_
+*/
+
+#ifndef _di_controller_time_sleep_nanoseconds_
+  f_status_t controller_time_sleep_nanoseconds(controller_global_t * const global, const f_time_spec_t time) {
+
+    if (!global || !global->setting) return F_status_set_error(F_parameter);
+
+    // When sleep is a second or more, instead wait for terminating signals if interruptible.
+    if ((global->main->setting.flag & controller_setting_flag_interruptible_e) && time.tv_sec) {
+      siginfo_t information;
+      f_signal_t signal = f_signal_t_initialize;
+
+      memset(&information, 0, sizeof(siginfo_t));
+
+      f_signal_set_empty(&signal.set);
+      f_signal_set_add(F_signal_abort, &signal.set);
+      f_signal_set_add(F_signal_interrupt, &signal.set);
+      f_signal_set_add(F_signal_quit, &signal.set);
+      f_signal_set_add(F_signal_termination, &signal.set);
+
+      return f_signal_wait_until(&signal.set, &time, &information);
+    }
+
+    return f_time_sleep_spec(time, remaining);
+  }
+#endif // _di_controller_time_sleep_nanoseconds_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/sources/c/main/time.h b/sources/c/main/time.h
new file mode 100644 (file)
index 0000000..644e9bb
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides time functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_time_h
+#define _controller_main_time_h
+
+/**
+ * Get the current time, plus the given offset.
+ *
+ * @param seconds
+ *   The seconds to add to current time.
+ * @param nanoseconds
+ *   The nanoseconds to add to current time.
+ * @param time
+ *   The resulting current time.
+ *
+ * @see f_time_of_day_get()
+ */
+#ifndef _di_controller_time_now_
+  extern void controller_time_now(const time_t seconds, const long nanoseconds, f_time_spec_t * const time);
+#endif // _di_controller_time_now_
+
+/**
+ * Sleep for the given time.
+ *
+ * @param global
+ *   The global data.
+ *   Must not be NULL.
+ *
+ *   This does not alter global.main.setting.state.status.
+ * @param time
+ *   The time in nanoseconds to wait.
+ *
+ * @return
+ *   Success from: f_signal_wait_until().
+ *   Success from: f_time_of_day_get().
+ *
+ *   Errors (with error bit) from: f_signal_wait_until().
+ *   Errors (with error bit) from: f_time_of_day_get().
+ *
+ * @see f_time_of_day_get()
+ */
+#ifndef _di_controller_time_sleep_nanoseconds_
+  extern f_status_t controller_time_sleep_nanoseconds(controller_global_t * const global, const f_time_spec_t time);
+#endif // _di_controller_time_sleep_nanoseconds_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_time_h