]> Kevux Git Server - fll/commitdiff
Update: Implement threaded signal handler in Featureless Make.
authorKevin Day <kevin@kevux.org>
Mon, 3 Apr 2023 00:17:48 +0000 (19:17 -0500)
committerKevin Day <kevin@kevux.org>
Mon, 3 Apr 2023 00:17:48 +0000 (19:17 -0500)
Bring in the threaded signal handler design that I experimented with in the Kevux Tools project.

This works by creating a thread that waits for the signal and nothing else.
The threaded design avoids the signal check and therefore avoids period calls to kernel space.

When thread support is diabled, this falls back to the traditional approach.

This will be done for other programs as well.

18 files changed:
build/stand_alone/fake.settings
level_3/fake/c/main/build.c
level_3/fake/c/main/build/load.c
level_3/fake/c/main/build/skeleton.c
level_3/fake/c/main/common/define.h
level_3/fake/c/main/common/print.c
level_3/fake/c/main/common/print.h
level_3/fake/c/main/common/type.h
level_3/fake/c/main/fake.c
level_3/fake/c/main/fake.h
level_3/fake/c/main/main.c
level_3/fake/c/main/make/operate.c
level_3/fake/c/main/signal.c [new file with mode: 0644]
level_3/fake/c/main/signal.h [new file with mode: 0644]
level_3/fake/c/main/thread.c [new file with mode: 0644]
level_3/fake/c/main/thread.h [new file with mode: 0644]
level_3/fake/data/build/defines
level_3/fake/data/build/settings

index 25cae796eb189af8fd7c7bf9b0894a040eedb926..c7b225e40dc36b248e04edd058dfe34d1d95ea3c 100644 (file)
@@ -69,7 +69,7 @@ build_sources_program fll/level_2/fss.c fll/level_2/fss/basic.c fll/level_2/fss/
 build_sources_program fll/level_2/print.c
 build_sources_program fll/level_2/program.c fll/level_2/program/common.c fll/level_2/program/print.c fll/level_2/private-program.c
 
-build_sources_program program/fake/main/build.c program/fake/main/clean.c program/fake/main/common.c program/fake/main/fake.c program/fake/main/make.c program/fake/main/print/common.c program/fake/main/print/context.c program/fake/main/print/error.c program/fake/main/print/message.c program/fake/main/print/operation.c program/fake/main/print/warning.c program/fake/main/print/verbose.c program/fake/main/skeleton.c
+build_sources_program program/fake/main/build.c program/fake/main/clean.c program/fake/main/common.c program/fake/main/fake.c program/fake/main/make.c program/fake/main/print/common.c program/fake/main/print/context.c program/fake/main/print/error.c program/fake/main/print/message.c program/fake/main/print/operation.c program/fake/main/print/warning.c program/fake/main/print/verbose.c program/fake/main/signal.c program/fake/main/skeleton.c program/fake/main/thread.c
 build_sources_program program/fake/main/build/enumeration.c program/fake/main/build/library.c program/fake/main/build/load.c program/fake/main/build/object.c program/fake/main/build/objects.c program/fake/main/build/print/compile.c program/fake/main/build/print/error.c program/fake/main/build/print/message.c program/fake/main/build/print/verbose.c program/fake/main/build/print/warning.c program/fake/main/build/program.c program/fake/main/build/skeleton.c program/fake/main/build/string.c
 build_sources_program program/fake/main/common/define.c program/fake/main/common/enumeration.c program/fake/main/common/print.c program/fake/main/common/string.c program/fake/main/common/type.c
 build_sources_program program/fake/main/fake/path_generate.c
index 8d767acab93eb18df3649e7da452ca7841f1b651..16225883a666842f22800ec84566810ddf9f89ca 100644 (file)
@@ -163,19 +163,10 @@ extern "C" {
     if (!data || !data->main) return;
     if (data->main->setting.state.status == F_child) return;
     if (F_status_is_error(data->main->setting.state.status) || f_file_exists(file_stage, F_true) == F_true) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     f_directory_statuss_t failures = f_directory_statuss_t_initialize;
     f_string_dynamic_t path_source = f_string_dynamic_t_initialize; // @todo move this to a shared buffer.
     f_string_dynamic_t destination_file = f_string_dynamic_t_initialize;
@@ -531,12 +522,9 @@ extern "C" {
 
     main->setting.state.status = fll_execute_program(main->cache_argument, main->cache_arguments, &parameter, 0, (void *) &return_code);
 
-    if (!((++main->program.signal_check) % fake_signal_check_d) && fll_program_standard_signal_received(&main->program)) {
-      fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+    if (fake_signal_check(main)) return return_code;
 
-      main->setting.state.status = F_status_set_error(F_interrupt);
-    }
-    else if (main->setting.state.status != F_child) {
+    if (main->setting.state.status != F_child) {
       if (F_status_is_error(main->setting.state.status)) {
         if (F_status_set_fine(main->setting.state.status) == F_failure) {
           fake_print_error_failure_script(&main->program.error, main->cache_argument);
@@ -633,19 +621,10 @@ extern "C" {
   void fake_build_operate(fake_data_t * const data, const f_string_statics_t * const build_arguments, const bool process_pipe) {
 
     if (!data || !data->main) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     main->setting.state.status = F_none;
 
     f_mode_t mode = f_mode_t_initialize;
@@ -875,19 +854,10 @@ extern "C" {
 
     if (!data || !data->main) return;
     if (F_status_is_error(data->main->setting.state.status)) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     f_mode_t mode = f_mode_t_initialize;
 
     macro_f_mode_t_set_default_umask(mode, main->program.umask);
index 19e9eef2de5b7071e65c781dd30688ba9236a08e..b20ecdc31ed5b94f479544cc331684c491b1db3a 100644 (file)
@@ -66,19 +66,10 @@ extern "C" {
 
     if (!data || !data->main || !setting) return;
     if (F_status_is_error(data->main->setting.state.status)) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     // Strip the build settings name from the build arguments to generate a list of modes.
     f_string_statics_t modes_custom = f_string_statics_t_initialize;
     modes_custom.used = build_arguments && build_arguments->used > 1 ? build_arguments->used - 1 : 0;
@@ -211,19 +202,10 @@ extern "C" {
 
     if (!data || !data->main || !setting) return;
     if (F_status_is_error(data->main->setting.state.status) && buffer.used) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     bool error_printed = F_false;
 
     f_string_dynamics_t build_compiler = f_string_dynamics_t_initialize;
@@ -1335,19 +1317,10 @@ extern "C" {
 
     if (!data || !data->main || !stage) return;
     if (F_status_is_error(data->main->setting.state.status)) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     const f_string_static_t names[] = {
       fake_build_stage_library_script_s,
       fake_build_stage_library_shared_s,
index 5853343bae6d02a419bdc7f134e593a541df73d1..948db678c9739cf3b4f4e827b19a32ad012bcb47 100644 (file)
@@ -65,16 +65,7 @@ extern "C" {
       for (j = 0; j < directorys[i].used; ++j) {
 
         if (f_path_separator_s.used && directorys[i].string[j] != f_path_separator_s.string[0]) continue;
-
-        if (!((++main->program.signal_check) % fake_signal_check_d)) {
-          if (fll_program_standard_signal_received(&main->program)) {
-            fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-            main->setting.state.status = F_status_set_error(F_interrupt);
-
-            return;
-          }
-        }
+        if (fake_signal_check(data->main)) return;
 
         directorys[i].string[j] = 0;
 
index b1746e61936e47f90992a645d82848934de31e9c..059ec84ad3262b1f98c6c796faea1c02d71e2298 100644 (file)
@@ -36,14 +36,16 @@ extern "C" {
  * The program signal defines.
  *
  * fake_signal_*_d:
- *   - check:       Number of iterations before performing signal check in non-threaded signal handling.
- *   - check_tiny:  The tiny check.
- *   - check_short: The short signal check.
+ *   - check:          Number of iterations before performing signal check in non-threaded signal handling.
+ *   - check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe).
+ *   - check_tiny:     The tiny check.
+ *   - check_short:    The short signal check.
  */
 #ifndef _di_fake_signal_d_
-  #define fake_signal_check_d       500000
-  #define fake_signal_check_tiny_d  4
-  #define fake_signal_check_short_d 16
+  #define fake_signal_check_d          500000
+  #define fake_signal_check_failsafe_d 20000
+  #define fake_signal_check_tiny_d     4
+  #define fake_signal_check_short_d    16
 #endif // _di_fake_signal_d_
 
 /**
index 26e59950ec9c24105ffe1fc4e76e7319bf5f5e3a..28ba08ca368055f90404993a8b2d32fe512dc0da 100644 (file)
@@ -9,6 +9,7 @@ extern "C" {
     "f_account_group_id_by_name",
     "f_account_id_by_name",
     "f_array_lengths_increase",
+    "f_compare_dynamic_partial",
     "f_console_parameter_prioritize_right",
     "f_console_parameter_process",
     "f_conversion_number_signed_to_string",
@@ -64,6 +65,7 @@ extern "C" {
     "f_string_dynamics_increase_by",
     "f_string_dynamics_resize",
     "f_string_map_multis_resize",
+    "f_thread_create",
     "f_uint8s_increase",
     "f_uint8s_increase_by",
     "f_utf_is_word_dash_plus",
@@ -73,7 +75,6 @@ extern "C" {
     "fl_environment_load_name",
     "fl_environment_load_names",
     "fl_iki_read",
-    "f_compare_dynamic_partial",
     "fll_execute_arguments_add",
     "fll_execute_arguments_add_parameter_set",
     "fll_execute_program",
@@ -97,7 +98,6 @@ extern "C" {
     "fake_make_assure_inside_project",
     "fake_make_get_id",
     "fake_make_get_id_mode",
-    "fake_make_get_id",
     "fake_make_operate_expand_build",
     "fake_make_operate_expand_context",
     "fake_make_operate_expand_environment",
index b9ec7b0ed4f43384e69d6066f75257c2803ffdc4..7db7373b1ecab40fd0500f2d4bde278e3b02017f 100644 (file)
@@ -42,6 +42,7 @@ extern "C" {
     fake_f_f_account_group_id_by_name_e,
     fake_f_f_account_id_by_name_e,
     fake_f_f_array_lengths_increase_e,
+    fake_f_f_compare_dynamic_partial_e,
     fake_f_f_console_parameter_prioritize_right_e,
     fake_f_f_console_parameter_process_e,
     fake_f_f_conversion_number_signed_to_string_e,
@@ -97,6 +98,7 @@ extern "C" {
     fake_f_f_string_dynamics_increase_by_e,
     fake_f_f_string_dynamics_resize_e,
     fake_f_f_string_map_multis_resize_e,
+    fake_f_f_thread_create_e,
     fake_f_f_uint8s_increase_e,
     fake_f_f_uint8s_increase_by_e,
     fake_f_f_utf_is_word_dash_plus_e,
@@ -106,7 +108,6 @@ extern "C" {
     fake_f_fl_environment_load_name_e,
     fake_f_fl_environment_load_names_e,
     fake_f_fl_iki_read_e,
-    fake_f_f_compare_dynamic_partial_e,
     fake_f_fll_execute_arguments_add_e,
     fake_f_fll_execute_arguments_add_parameter_set_e,
     fake_f_fll_execute_program_e,
index 3374b6822d0f5daae5c68544bebb7f3e8dca4ec9..e155574fecd3abd40b5f3665dfdf1558434d6b5b 100644 (file)
@@ -60,7 +60,8 @@ extern "C" {
  *
  * flag: Flags passed to the main function.
  *
- * state:  The state data used when processing the FSS data.
+ * status_thread: A status used eclusively by the threaded signal handler.
+ * state:         The state data used when processing the FSS data.
  *
  * build:    The build directory.
  * data:     The data directory.
@@ -79,6 +80,7 @@ extern "C" {
   typedef struct {
     uint32_t flag;
 
+    f_status_t status_thread;
     f_state_t state;
 
     f_string_dynamic_t build;
@@ -100,6 +102,7 @@ extern "C" {
   #define fake_setting_t_initialize \
     { \
       0, \
+      F_none, \
       f_state_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
index 26a30a42bf3f6e0d5bb372e2d1b85d52e1614f45..71a2559fde1fcb62842c796d6c912df9c03a5be7 100644 (file)
@@ -285,17 +285,7 @@ extern "C" {
       fl_execute_parameter_t parameter = macro_fl_execute_parameter_t_initialize(0, 0, &environment, &signals, 0);
 
       main->setting.state.status = fll_execute_program(program, main->cache_arguments, &parameter, 0, (void *) &return_code);
-
-      if (!((++main->program.signal_check) % fake_signal_check_d)) {
-        if (fll_program_standard_signal_received(&main->program)) {
-          fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-          main->setting.state.status = F_status_set_error(F_interrupt);
-
-          return 0;
-        }
-      }
-
+      if (fake_signal_check(data->main)) return return_code;
       if (main->setting.state.status == F_child) return return_code;
     }
     else {
@@ -324,19 +314,10 @@ extern "C" {
   void fake_file_buffer(fake_data_t * const data, const f_string_static_t path_file, const bool required, f_string_dynamic_t * const buffer) {
 
     if (!data || !data->main || !buffer) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     main->setting.state.status = f_file_exists(path_file, F_true);
 
     if (F_status_is_error(main->setting.state.status)) {
@@ -432,15 +413,7 @@ extern "C" {
     clearerr(F_type_input_d);
 
     do {
-      if (!((++main->program.signal_check) % fake_signal_check_d)) {
-        if (fll_program_standard_signal_received(&main->program)) {
-          fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-          main->setting.state.status = F_status_set_error(F_interrupt);
-
-          return;
-        }
-      }
+      if (fake_signal_check(main)) return;
 
       main->setting.state.status = f_file_stream_read_block(file, buffer);
 
@@ -459,19 +432,10 @@ extern "C" {
   void fake_validate_parameter_paths(fake_data_t * const data) {
 
     if (!data || !data->main) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     const f_string_static_t names[] = {
       fake_long_build_s,
       fake_long_data_s,
index 228d888b4ccb47863ab340ed53023332eef193c0..4e5f42fa35003847140683f68ffe72ff6275c067 100644 (file)
 #include <program/fake/main/print/operation.h>
 #include <program/fake/main/print/verbose.h>
 #include <program/fake/main/print/warning.h>
+#include <program/fake/main/signal.h>
 #include <program/fake/main/skeleton.h>
+#include <program/fake/main/thread.h>
 
 #ifdef __cplusplus
 extern "C" {
index 66967436b2fe41bd79eec6e7b713ea5569946f3d..f1eefe12762b3b45fd359f0cf13cd14579863b29 100644 (file)
@@ -36,13 +36,41 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) {
 
   f_file_umask_get(&data.program.umask);
 
-  {
-    const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(argc, argv, envp);
+  #ifdef _di_thread_support_
+    {
+      const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(argc, argv, envp);
 
-    fake_setting_load(arguments, &data);
-  }
+      fake_setting_load(arguments, &data);
+    }
+
+    fake_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, &fake_thread_signal, (void *) &data);
+
+      if (F_status_is_error(data.setting.state.status)) {
+        fake_print_error(&data.program.error, macro_fake_f(f_thread_create));
+      }
+      else {
+        {
+          const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize(argc, argv, envp);
+
+          fake_setting_load(arguments, &data);
+        }
+
+        if (!fake_signal_check(&data)) {
+          fake_main(&data);
+        }
 
-  fake_main(&data);
+        f_thread_cancel(id_signal);
+        f_thread_join(id_signal, 0);
+      }
+    }
+  #endif // _di_thread_support_
 
   fake_main_delete(&data);
 
index 59a7b4db76e7db16a7c170088e83091ce7542c5e..19dd6ddd94cdc900b025e90d6aab7613a464046a 100644 (file)
@@ -8,19 +8,10 @@ extern "C" {
   void fake_make_operate(fake_data_t * const data) {
 
     if (!data || !data->main) return;
+    if (fake_signal_check(data->main)) return;
 
     fake_main_t * const main = data->main;
 
-    if (!((++main->program.signal_check) % fake_signal_check_d)) {
-      if (fll_program_standard_signal_received(&main->program)) {
-        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
-
-        main->setting.state.status = F_status_set_error(F_interrupt);
-
-        return;
-      }
-    }
-
     fake_make_print_message_now_making(&main->program.message, main->setting.fakefile);
 
     f_array_lengths_t section_stack = f_array_lengths_t_initialize;
diff --git a/level_3/fake/c/main/signal.c b/level_3/fake/c/main/signal.c
new file mode 100644 (file)
index 0000000..a401144
--- /dev/null
@@ -0,0 +1,113 @@
+#include "fake.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_fake_signal_check_) && defined(_di_thread_support_)
+  f_status_t fake_signal_check(fake_main_t * const main) {
+
+    if (!main) return F_false;
+    if (main->program.signal.id == -1) return F_false;
+
+    if (!((++main->program.signal_check) % fake_signal_check_d)) {
+      if (fll_program_standard_signal_received(&main->program)) {
+        fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+
+        main->setting.state.status = F_status_set_error(F_interrupt);
+
+        return F_true;
+      }
+
+      main->program.signal_check = 0;
+    }
+
+    return F_false;
+  }
+#endif // !defined(_di_fake_signal_check_) && defined(_di_thread_support_)
+
+#if !defined(_di_fake_signal_check_) && !defined(_di_thread_support_)
+  f_status_t fake_signal_check(fake_main_t * const main) {
+
+    if (!main) return F_false;
+    if (main->program.signal.id == -1) return F_false;
+
+    if (main->program.signal_received) {
+      fll_program_print_signal_received(&main->program.warning, main->program.signal_received);
+
+      main->setting.state.status = F_status_set_error(F_interrupt);
+
+      return F_true;
+    }
+
+    return F_false;
+  }
+#endif // !defined(_di_fake_signal_check_) && !defined(_di_thread_support_)
+
+#if !defined(_di_fake_signal_handler_) && !defined(_di_thread_support_)
+  void fake_signal_handler(fake_main_t * const main) {
+
+    if (!main) return;
+
+    siginfo_t information;
+    f_array_length_t failsafe = 0;
+
+    memset(&information, 0, sizeof(siginfo_t));
+
+    main->program.signal_received = 0;
+
+    f_signal_set_empty(&main->program.signal.set);
+    f_signal_set_add(F_signal_abort, &main->program.signal.set);
+    f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set);
+    f_signal_set_add(F_signal_hangup, &main->program.signal.set);
+    f_signal_set_add(F_signal_interrupt, &main->program.signal.set);
+    f_signal_set_add(F_signal_quit, &main->program.signal.set);
+    f_signal_set_add(F_signal_termination, &main->program.signal.set);
+
+    if (main->program.signal.id == -1) {
+      main->setting.status_thread = f_signal_open(&main->program.signal);
+
+      if (F_status_is_error(main->setting.status_thread)) {
+        main->program.signal_received = F_signal_abort;
+
+        return;
+      }
+    }
+
+    do {
+      memset(&information, 0, sizeof(siginfo_t));
+
+      main->setting.status_thread = f_signal_wait(&main->program.signal.set, &information);
+
+      if (F_status_is_error(main->setting.status_thread) && F_status_set_fine(main->setting.status_thread) != F_interrupt) {
+        if (++failsafe >= fake_signal_check_failsafe_d) break;
+      }
+
+      switch (information.si_signo) {
+        case F_signal_abort:
+        case F_signal_broken_pipe:
+        case F_signal_hangup:
+        case F_signal_interrupt:
+        case F_signal_quit:
+        case F_signal_termination:
+          main->program.signal_received = information.si_signo;
+
+          break;
+      }
+
+      failsafe = 0;
+      main->setting.status_thread = F_none;
+
+    } while (!main->program.signal_received);
+
+    f_signal_close(&main->program.signal);
+
+    if (F_status_is_error(main->setting.status_thread)) {
+      main->program.signal_received = F_signal_abort;
+    }
+  }
+#endif // !defined(_di_fake_signal_handler_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/fake/c/main/signal.h b/level_3/fake/c/main/signal.h
new file mode 100644 (file)
index 0000000..a40c0da
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Featureless Make
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides signal functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _fake_signal_h
+#define _fake_signal_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Check to see if a signal is received.
+ *
+ * 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
+ *
+ * There is a threaded and a non-threaded version of this.
+ * The non-threaded version checks periodically using fake_signal_check_d and updates main->signal_check as needed.
+ * The threaded version checks the flag state which is set by a separate thread that is blocking until signal is received.
+ *
+ * @param main
+ *   The main program and settings data.
+ *
+ *   This does not alter main.setting.state.status.
+ *
+ * @return
+ *   F_true on signal received.
+ *   F_false otherwise.
+ *
+ * @see fake_signal_handler()
+ *
+ * @see fll_program_standard_signal_received()
+ */
+#ifndef _di_fake_signal_check_
+  extern f_status_t fake_signal_check(fake_main_t * const main);
+#endif // _di_fake_signal_check_
+
+/**
+ * Signal handler for signals/interrupts.
+ *
+ * This blocks until an expected signal is recieved.
+ * When an expected signal is received it then sets the
+ *
+ * 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 main program and settings data.
+ *
+ *   This alters main.program.signal_received, setting it to a received signal.
+ *
+ *   This alters setting.status:
+ *     Errors with (error bit set) from: f_signal_open()
+ *     Errors with (error bit set) from: f_signal_wait()
+ *
+ * @see f_signal_close()
+ * @see f_signal_open()
+ * @see f_signal_wait()
+ */
+#if !defined(_di_fake_signal_handler_) && !defined(_di_thread_support_)
+  extern void fake_signal_handler(fake_main_t * const main);
+#endif // !defined(_di_fake_signal_handler_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _fake_signal_h
diff --git a/level_3/fake/c/main/thread.c b/level_3/fake/c/main/thread.c
new file mode 100644 (file)
index 0000000..110e0f7
--- /dev/null
@@ -0,0 +1,26 @@
+#include "fake.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_fake_thread_signal_) && !defined(_di_thread_support_)
+  void * fake_thread_signal(void * const main) {
+
+    f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+    if (main) {
+      fake_signal_handler((fake_main_t *) main);
+    }
+
+    return 0;
+  }
+#endif // !defined(_di_fake_thread_signal_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_3/fake/c/main/thread.h b/level_3/fake/c/main/thread.h
new file mode 100644 (file)
index 0000000..3053403
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * FLL - Level 3
+ *
+ * Project: Featureless Make
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides thread functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _fake_thread_h
+#define _fake_thread_h
+
+/**
+ * Thread handler for 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.
+ *
+ *   Must be of type fake_main_t.
+ *
+ * @return
+ *   0, always.
+ *
+ * @see f_thread_cancel_state_set()
+ *
+ * @see fake_signal_handler()
+ */
+#if !defined(_di_fake_thread_signal_) && !defined(_di_thread_support_)
+  extern void * fake_thread_signal(void * const main);
+#endif // !defined(_di_fake_thread_signal_) && !defined(_di_thread_support_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _fake_thread_h
index 546ad61163654d263d352494d0f85c19c5608ce1..e9989520f04ee5376202b6401549955445ac06f6 100644 (file)
@@ -1,6 +1,7 @@
 # fss-0000
 
 _di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
+_di_thread_support_ Disables thread support.
 
 _libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later).
 _pthread_attr_unsupported_ Disable non-portable functionality associated with pthread_attr.
index ffa6a65a2eeb55633f09995c0db32af6be00218e..b82ecd617c3386c222697f766ed43499f39f2cf2 100644 (file)
@@ -27,7 +27,7 @@ build_libraries-individual -lf_account -lf_capability -lf_color -lf_compare -lf_
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 
-build_sources_library main/build.c main/clean.c main/common.c main/fake.c main/make.c main/print/common.c main/print/context.c main/print/error.c main/print/message.c main/print/operation.c main/print/warning.c main/print/verbose.c main/skeleton.c
+build_sources_library main/build.c main/clean.c main/common.c main/fake.c main/make.c main/print/common.c main/print/context.c main/print/error.c main/print/message.c main/print/operation.c main/print/warning.c main/print/verbose.c main/signal.c main/skeleton.c main/thread.c
 build_sources_library main/build/enumeration.c main/build/library.c main/build/load.c main/build/object.c main/build/objects.c main/build/print/compile.c main/build/print/error.c main/build/print/message.c main/build/print/verbose.c main/build/print/warning.c main/build/program.c main/build/skeleton.c main/build/string.c
 build_sources_library main/common/define.c main/common/enumeration.c main/common/print.c main/common/string.c main/common/type.c
 build_sources_library main/fake/path_generate.c
@@ -35,7 +35,7 @@ build_sources_library main/make/load_fakefile.c main/make/load_parameters.c main
 
 build_sources_program main/main.c
 
-build_sources_headers main/build.h main/clean.h main/common.h main/fake.h main/make.h main/print/common.h main/print/context.h main/print/error.h main/print/message.h main/print/operation.h main/print/warning.h main/print/verbose.h main/skeleton.h
+build_sources_headers main/build.h main/clean.h main/common.h main/fake.h main/make.h main/print/common.h main/print/context.h main/print/error.h main/print/message.h main/print/operation.h main/print/warning.h main/print/verbose.h main/signal.h main/skeleton.h main/thread.h
 build_sources_headers main/build/enumeration.h main/build/library.h main/build/load.h main/build/object.h main/build/objects.h main/build/print/compile.h main/build/print/error.h main/build/print/message.h main/build/print/verbose.h main/build/print/warning.h main/build/program.h main/build/skeleton.h main/build/string.h
 build_sources_headers main/common/define.h main/common/enumeration.h main/common/print.h main/common/string.h main/common/type.h
 build_sources_headers main/fake/path_generate.h