From 4a5766c4436978aabad4473cb511dbf7623851a4 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 8 Apr 2021 21:10:37 -0500 Subject: [PATCH] Progress: controller program. Copy over the rule item action statuses when the rule process completes. Update cleanup thread: - deallocate rule data in no longer used space. - make sure cache thread is being started. Implement asynchronous example rules for testing. Disable asynchronous execution when running in validation mode. This ensures consistency and cleanliness when outputting the validation data. There is no reason to run asynchronously in this mode because nothing is supposed to be run anyway. Make sure that execution (simulated or not) is not performed in validation mode. Make sure the program immediately executes at the end when in validation mode. --- documents/threads.txt | 7 +++ level_3/controller/c/private-controller.c | 6 +- level_3/controller/c/private-rule.c | 22 ++++++- level_3/controller/c/private-thread.c | 67 +++++++++++++--------- .../settings/example/entries/asynchronous.entry | 11 ++++ .../example/rules/asynchronous/sleep_1.rule | 13 +++++ .../example/rules/asynchronous/sleep_10.rule | 12 ++++ .../example/rules/asynchronous/sleep_2.rule | 13 +++++ .../example/rules/asynchronous/sleep_3.rule | 13 +++++ .../example/rules/asynchronous/sleep_5.rule | 12 ++++ .../example/rules/asynchronous/sleep_8.rule | 12 ++++ 11 files changed, 158 insertions(+), 30 deletions(-) create mode 100644 level_3/controller/data/settings/example/rules/asynchronous/sleep_1.rule create mode 100644 level_3/controller/data/settings/example/rules/asynchronous/sleep_10.rule create mode 100644 level_3/controller/data/settings/example/rules/asynchronous/sleep_2.rule create mode 100644 level_3/controller/data/settings/example/rules/asynchronous/sleep_3.rule create mode 100644 level_3/controller/data/settings/example/rules/asynchronous/sleep_5.rule create mode 100644 level_3/controller/data/settings/example/rules/asynchronous/sleep_8.rule diff --git a/documents/threads.txt b/documents/threads.txt index edbae5b..fbb2f79 100644 --- a/documents/threads.txt +++ b/documents/threads.txt @@ -25,3 +25,10 @@ GLIBC Problems: There needs to be more investigation into the cause of this. Maybe there is some way to fix this during compile or link time without having to fix GLIBC or use a different libc for static linking. + +Valgrind Debugging: + The tool "helgrind" in valgrind allows for debugging threads (such as valgrind --tool=helgrrind controller). + + The way in which the "active" lock is used will result in out of order locks. + This causes "helgrind" to produce a lot of warnings about locks being out of order. + Therefore, it is stongly recommended to use the parameter "--track-lockorders=no". diff --git a/level_3/controller/c/private-controller.c b/level_3/controller/c/private-controller.c index e8da949..ca34fe7 100644 --- a/level_3/controller/c/private-controller.c +++ b/level_3/controller/c/private-controller.c @@ -1100,8 +1100,10 @@ extern "C" { } if (entry_action->code & controller_entry_rule_code_asynchronous) { - process_options |= controller_process_option_asynchronous; - rule_options |= controller_rule_option_asynchronous; + if (main.data->parameters[controller_parameter_validate].result != f_console_result_found) { + process_options |= controller_process_option_asynchronous; + rule_options |= controller_rule_option_asynchronous; + } } status = controller_rule_process_begin(process_options, alias_rule, controller_rule_action_type_start, rule_options, stack, main, *cache); diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index 99499d8..e959722 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -1639,6 +1639,8 @@ extern "C" { if ((process->options & controller_rule_option_simulate) && main.data->parameters[controller_parameter_validate].result == f_console_result_found) { controller_rule_validate(process->rule, controller_rule_action_type_start, process->options, main, &process->cache); + + return F_none; } f_array_length_t i = 0; @@ -1935,9 +1937,25 @@ extern "C" { controller_rule_error_print(main.data->error, process->cache.action, F_status_set_fine(status), "controller_rule_find", F_true, F_true, main.thread); } else { - main.setting->rules.array[id_rule].status = process->rule.status; + controller_rule_t *rule = &main.setting->rules.array[id_rule]; + + rule->status = process->rule.status; + + f_array_length_t j = 0; + + controller_rule_item_t *rule_item = 0; + controller_rule_action_t *rule_action = 0; - // @fixme the rule item action status needs to be copied over from the local rule to the old one but there is no way to map the two (the structure could have changeed). + // @todo implement a "version" counter and detect if the rule version is different before attempting update. + // copy all rule item action statuses from the rule process to the rule. + for (i = 0; i < rule->items.used; ++i) { + + rule_item = &rule->items.array[i]; + + for (j = 0; j < rule_item->actions.used; ++j) { + rule_item->actions.array[j].status = process->rule.items.array[i].actions.array[j].status; + } // for + } // for } f_thread_unlock(&main.thread->lock.rule); diff --git a/level_3/controller/c/private-thread.c b/level_3/controller/c/private-thread.c index f4dbb16..7856526 100644 --- a/level_3/controller/c/private-thread.c +++ b/level_3/controller/c/private-thread.c @@ -77,6 +77,11 @@ extern "C" { controller_cache_delete_simple(&process->cache); f_type_array_lengths_resize(0, &process->stack); + // deallocate any rules in the space that is declared to be unused. + if (i >= main->thread->processs.used) { + controller_rule_delete_simple(&process->rule); + } + f_thread_unlock(&process->active); } // for @@ -222,50 +227,60 @@ extern "C" { thread.id_rule = 0; status = thread.status; - } - if (status == F_child) { - controller_thread_delete_simple(&thread); + if (status == F_child) { + controller_thread_delete_simple(&thread); - return F_child; + return F_child; + } } } } + // @todo consider redesigning to spawn forked processes from main thread to allow proper deallocation via a timed mutex condition (only need to do this for scripts). + // only make the rule and control threads available once any/all pre-processing and are completed. if (F_status_is_error_not(status) && status != F_signal && status != F_child && thread.enabled) { - if (data->parameters[controller_parameter_validate].result == f_console_result_none && thread.id_rule) { + if (data->parameters[controller_parameter_validate].result == f_console_result_none) { - // wait for the entry thread to complete before starting the rule thread. - f_thread_join(thread.id_rule, 0); + if (thread.id_rule) { - if (thread.status == F_child) { - controller_thread_delete_simple(&thread); + // wait for the entry thread to complete before starting the rule thread. + f_thread_join(thread.id_rule, 0); - return F_child; - } + if (thread.status == F_child) { + controller_thread_delete_simple(&thread); - thread.id_rule = 0; + return F_child; + } + + thread.id_rule = 0; + } if (thread.enabled) { status = f_thread_create(0, &thread.id_rule, &controller_thread_rule, (void *) &main); - } - status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &main); + if (F_status_is_error(status)) { + thread.id_rule = 0; + } + else { + status = f_thread_create(0, &thread.id_control, &controller_thread_control, (void *) &main); + } - if (F_status_is_error(status)) { - thread.id_control = 0; - } - else { - status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &main); - } + if (F_status_is_error(status)) { + thread.id_control = 0; + } + else { + status = f_thread_create(0, &thread.id_cleanup, &controller_thread_cleanup, (void *) &main); + } - if (F_status_is_error(status)) { - thread.id_cleanup = 0; + if (F_status_is_error(status)) { + thread.id_cleanup = 0; - if (data->error.verbosity != f_console_verbosity_quiet) { - controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread); + if (data->error.verbosity != f_console_verbosity_quiet) { + controller_error_print(data->error, F_status_set_fine(status), "f_thread_create", F_true, &thread); + } } } } @@ -292,9 +307,9 @@ extern "C" { thread.id_signal = 0; } - } - controller_thread_process_cancel(&main); + controller_thread_process_cancel(&main); + } if (thread.id_signal) f_thread_cancel(thread.id_signal); if (thread.id_cleanup) f_thread_cancel(thread.id_cleanup); diff --git a/level_3/controller/data/settings/example/entries/asynchronous.entry b/level_3/controller/data/settings/example/entries/asynchronous.entry index 67f0d67..5a2f516 100644 --- a/level_3/controller/data/settings/example/entries/asynchronous.entry +++ b/level_3/controller/data/settings/example/entries/asynchronous.entry @@ -1,3 +1,14 @@ # fss-0005 main: + consider asynchronous sleep_3 asynchronous + consider asynchronous sleep_5 asynchronous + + rule asynchronous sleep_1 asynchronous + rule asynchronous sleep_2 asynchronous + rule asynchronous sleep_3 asynchronous + rule asynchronous sleep_5 asynchronous + rule asynchronous sleep_8 asynchronous + rule asynchronous sleep_10 asynchronous + + ready diff --git a/level_3/controller/data/settings/example/rules/asynchronous/sleep_1.rule b/level_3/controller/data/settings/example/rules/asynchronous/sleep_1.rule new file mode 100644 index 0000000..17671c1 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/asynchronous/sleep_1.rule @@ -0,0 +1,13 @@ +# fss-000d + +setting: + name "Sleep 1 Seconds." + nice 15 + limit nice 1 2 + need asynchronous sleep_3 + +script: + start sleep 1 + +script: + start echo "Sleep 1: $(date -u)" diff --git a/level_3/controller/data/settings/example/rules/asynchronous/sleep_10.rule b/level_3/controller/data/settings/example/rules/asynchronous/sleep_10.rule new file mode 100644 index 0000000..d4e89b0 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/asynchronous/sleep_10.rule @@ -0,0 +1,12 @@ +# fss-000d + +setting: + name "Sleep 10 Seconds." + nice 15 + limit nice 1 2 + +script: + start sleep 10 + +script: + start echo "Sleep 10: $(date -u)" diff --git a/level_3/controller/data/settings/example/rules/asynchronous/sleep_2.rule b/level_3/controller/data/settings/example/rules/asynchronous/sleep_2.rule new file mode 100644 index 0000000..a080fd1 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/asynchronous/sleep_2.rule @@ -0,0 +1,13 @@ +# fss-000d + +setting: + name "Sleep 2 Seconds." + nice 15 + limit nice 1 2 + need asynchronous sleep_5 + +script: + start sleep 2 + +script: + start echo "Sleep 2: $(date -u)" diff --git a/level_3/controller/data/settings/example/rules/asynchronous/sleep_3.rule b/level_3/controller/data/settings/example/rules/asynchronous/sleep_3.rule new file mode 100644 index 0000000..436fbbd --- /dev/null +++ b/level_3/controller/data/settings/example/rules/asynchronous/sleep_3.rule @@ -0,0 +1,13 @@ +# fss-000d + +setting: + name "Sleep 3 Seconds." + nice 15 + limit nice 1 2 + need asynchronous sleep_5 + +script: + start sleep 3 + +script: + start echo "Sleep 3: $(date -u)" diff --git a/level_3/controller/data/settings/example/rules/asynchronous/sleep_5.rule b/level_3/controller/data/settings/example/rules/asynchronous/sleep_5.rule new file mode 100644 index 0000000..e6ede53 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/asynchronous/sleep_5.rule @@ -0,0 +1,12 @@ +# fss-000d + +setting: + name "Sleep 5 Seconds." + nice 15 + limit nice 1 2 + +script: + start sleep 5 + +script: + start echo "Sleep 5: $(date -u)" diff --git a/level_3/controller/data/settings/example/rules/asynchronous/sleep_8.rule b/level_3/controller/data/settings/example/rules/asynchronous/sleep_8.rule new file mode 100644 index 0000000..1c5dbfc --- /dev/null +++ b/level_3/controller/data/settings/example/rules/asynchronous/sleep_8.rule @@ -0,0 +1,12 @@ +# fss-000d + +setting: + name "Sleep 8 Seconds." + nice 15 + limit nice 1 2 + +script: + start sleep 8 + +script: + start echo "Sleep 8: $(date -u)" -- 1.8.3.1