]> Kevux Git Server - fll/commitdiff
Progress: scheduler support in contol program.
authorKevin Day <thekevinday@gmail.com>
Sat, 26 Dec 2020 23:01:32 +0000 (17:01 -0600)
committerKevin Day <thekevinday@gmail.com>
Sat, 26 Dec 2020 23:01:32 +0000 (17:01 -0600)
The control (aka cgroups) will be implemented in an isolated commit as I suspect the required changes will be more extensive.

level_1/fl_execute/c/execute-common.h
level_2/fll_execute/c/execute.h
level_2/fll_execute/c/private-execute.c
level_3/controller/c/controller.h
level_3/controller/c/private-common.h
level_3/controller/c/private-rule.c
level_3/controller/data/settings/example/rules/command/multiple.rule
level_3/controller/data/settings/rules/service/logger.rule
level_3/controller/documents/rule.txt
level_3/controller/specifications/rule.txt

index e6be62a75b607bc3e1d9be0e5f05e5436dfc356f..455b5b7caf823200afd31d18128d0cea35c636e6 100644 (file)
@@ -54,22 +54,22 @@ extern "C" {
 /**
  * A structure representing a scheduler and its parameters for execution.
  *
- * policy:    the scheduler policy.
- * parameter: a pointer to the scheduler parameters;
+ * policy:   the scheduler policy.
+ * priority: the scheduler priority;
  */
 #ifndef _di_fl_execute_scheduler_t_
   typedef struct {
     int policy;
-    const struct sched_param *parameter;
+    int priority;
   } fl_execute_scheduler_t;
 
   #define fl_execute_scheduler_t_initialize { 0, 0 }
 
-  #define fl_macro_execute_scheduler_t_initialize(policy, parameter) { policy, parameter }
+  #define fl_macro_execute_scheduler_t_initialize(policy, priority) { policy, priority }
 
   #define fl_execute_scheduler_t_clear(scheduler) \
     scheduler.policy = 0; \
-    scheduler.parameter = 0;
+    scheduler.priority = 0;
 #endif // _di_fl_execute_scheduler_t_
 
 /**
index 2ba0dfbcee80d84710f42631501eedb72b4ad523..817a8598110e2323f18d99cd1d323bd89ce4dec2 100644 (file)
@@ -15,6 +15,7 @@
 
 // libc includes
 #include <memory.h>
+#include <sched.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
index b4241594e4799c435f039b35af0a469d80ced719..fdb45f30c3c07ccbbb2a18ada9c76e7d7ff03b90 100644 (file)
@@ -136,9 +136,12 @@ extern "C" {
     if (as.scheduler) {
       const int process_id = getpid();
 
+      struct sched_param parameter_schedule;
+      parameter_schedule.sched_priority = as.scheduler->priority;
+
       errno = 0;
 
-      if (sched_setscheduler(process_id, as.scheduler->policy, as.scheduler->parameter) == -1) {
+      if (sched_setscheduler(process_id, as.scheduler->policy, &parameter_schedule) == -1) {
         *result = -1;
 
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
index a59dafb5370dc4e65e441adf0d618d9e554de1a0..4c4c826381c1bab7c9ae7ca20d5d2dc80bad04e1 100644 (file)
 #ifndef _controller_h
 
 // libc includes
+#include <sched.h>
 #include <string.h>
 #include <sys/types.h>
+#include <linux/sched.h>
 #include <unistd.h>
 
 // fll-0 includes
index ad9aba96b62ea122532293199024752fc0d48e9e..58a5ddcd4db114939c4bd49e24178bbdae2d4603 100644 (file)
@@ -17,11 +17,13 @@ extern "C" {
   #define controller_string_actions       "actions"
   #define controller_string_asynchronous  "asynchronous"
   #define controller_string_bash          "bash"
+  #define controller_string_batch         "batch"
   #define controller_string_capability    "capability"
   #define controller_string_create        "create"
   #define controller_string_command       "command"
   #define controller_string_consider      "consider"
   #define controller_string_control       "control"
+  #define controller_string_deadline      "deadline"
   #define controller_string_default       "default"
   #define controller_string_define        "define"
   #define controller_string_entry         "entry"
@@ -29,9 +31,11 @@ extern "C" {
   #define controller_string_environment   "environment"
   #define controller_string_fail          "fail"
   #define controller_string_failsafe      "failsafe"
+  #define controller_string_fifo          "fifo"
   #define controller_string_group         "group"
   #define controller_string_groups        "groups"
   #define controller_string_how           "how"
+  #define controller_string_idle          "idle"
   #define controller_string_item          "item"
   #define controller_string_kill          "kill"
   #define controller_string_main          "main"
@@ -41,6 +45,7 @@ extern "C" {
   #define controller_string_nice          "nice"
   #define controller_string_no            "no"
   #define controller_string_optional      "optional"
+  #define controller_string_other         "other"
   #define controller_string_parameter     "parameter"
   #define controller_string_path          "path"
   #define controller_string_pid           "pid"
@@ -50,6 +55,7 @@ extern "C" {
   #define controller_string_require       "require"
   #define controller_string_required      "required"
   #define controller_string_restart       "restart"
+  #define controller_string_round_robin   "round_robin"
   #define controller_string_rule          "rule"
   #define controller_string_rules         "rules"
   #define controller_string_scheduler     "scheduler"
@@ -73,11 +79,13 @@ extern "C" {
   #define controller_string_actions_length       7
   #define controller_string_asynchronous_length  12
   #define controller_string_bash_length          4
+  #define controller_string_batch_length         5
   #define controller_string_capability_length    10
   #define controller_string_create_length        6
   #define controller_string_command_length       7
   #define controller_string_consider_length      8
   #define controller_string_control_length       7
+  #define controller_string_deadline_length      8
   #define controller_string_define_length        6
   #define controller_string_default_length       7
   #define controller_string_entry_length         5
@@ -85,8 +93,10 @@ extern "C" {
   #define controller_string_environment_length   11
   #define controller_string_fail_length          4
   #define controller_string_failsafe_length      8
+  #define controller_string_fifo_length          4
   #define controller_string_group_length         5
   #define controller_string_how_length           3
+  #define controller_string_idle_length          4
   #define controller_string_item_length          4
   #define controller_string_kill_length          4
   #define controller_string_main_length          4
@@ -96,6 +106,7 @@ extern "C" {
   #define controller_string_nice_length          4
   #define controller_string_no_length            2
   #define controller_string_optional_length      8
+  #define controller_string_other_length         5
   #define controller_string_parameter_length     9
   #define controller_string_path_length          4
   #define controller_string_pid_length           3
@@ -105,6 +116,7 @@ extern "C" {
   #define controller_string_require_length       7
   #define controller_string_required_length      8
   #define controller_string_restart_length       7
+  #define controller_string_round_robin_length   11
   #define controller_string_rule_length          4
   #define controller_string_rules_length         5
   #define controller_string_scheduler_length     9
@@ -272,9 +284,10 @@ extern "C" {
   #define controller_rule_option_wait         0x8
 
   // bitwise codes representing properties on controller_rule_t that have been found in the rule file.
-  #define controller_rule_has_group 0x1
-  #define controller_rule_has_nice  0x2
-  #define controller_rule_has_user  0x4
+  #define controller_rule_has_group     0x1
+  #define controller_rule_has_nice      0x2
+  #define controller_rule_has_scheduler 0x4
+  #define controller_rule_has_user      0x8
 
   typedef struct {
     f_status_t status;
@@ -295,7 +308,6 @@ extern "C" {
     f_string_dynamic_t name;
     f_string_dynamic_t control;
     f_string_dynamic_t path;
-    f_string_dynamic_t scheduler;
     f_string_dynamic_t script;
 
     f_string_maps_t define;
@@ -308,6 +320,7 @@ extern "C" {
 
     f_capability_t capability;
     f_int32s_t groups;
+    fl_execute_scheduler_t scheduler;
 
     controller_rule_items_t items;
   } controller_rule_t;
@@ -329,7 +342,6 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
-      f_string_dynamic_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_dynamics_t_initialize, \
@@ -338,6 +350,7 @@ extern "C" {
       f_string_dynamics_t_initialize, \
       f_capability_t_initialize, \
       f_int32s_t_initialize, \
+      fl_execute_scheduler_t_initialize, \
       controller_rule_items_initialize, \
     }
 
@@ -346,7 +359,6 @@ extern "C" {
     fl_string_dynamic_delete(&rule.name); \
     fl_string_dynamic_delete(&rule.control); \
     fl_string_dynamic_delete(&rule.path); \
-    fl_string_dynamic_delete(&rule.scheduler); \
     fl_string_dynamic_delete(&rule.script); \
     f_macro_string_maps_t_delete_simple(rule.define) \
     f_macro_string_maps_t_delete_simple(rule.parameter) \
index 83198caa0d8113fc5c7e7c2173468541ea29ade3..cb6723382256ba6ad6ef6e1a3bddc963d22f51c5 100644 (file)
@@ -480,8 +480,8 @@ extern "C" {
       as.capability = rule->capability;
     }
 
-    if (rule->scheduler.used) {
-      // @todo: as.scheduler =
+    if (rule->has & controller_rule_has_scheduler) {
+      as.scheduler = &rule->scheduler;
     }
 
     if (rule->control.used) {
@@ -1366,7 +1366,8 @@ extern "C" {
     rule->name.used = 0;
     rule->control.used = 0;
     rule->path.used = 0;
-    rule->scheduler.used = 0;
+    rule->scheduler.policy = 0;
+    rule->scheduler.priority = 0;
     rule->script.used = 0;
 
     rule->define.used = 0;
@@ -1826,7 +1827,7 @@ extern "C" {
         continue;
       }
 
-      if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_scheduler || type == controller_rule_setting_type_script) {
+      if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) {
         if (type == controller_rule_setting_type_control) {
           setting_value = &rule->control;
         }
@@ -1836,9 +1837,6 @@ extern "C" {
         else if (type == controller_rule_setting_type_path) {
           setting_value = &rule->path;
         }
-        else if (type == controller_rule_setting_type_scheduler) {
-          setting_value = &rule->scheduler;
-        }
         else if (type == controller_rule_setting_type_script) {
           setting_value = &rule->script;
         }
@@ -1950,10 +1948,124 @@ extern "C" {
             continue;
           }
         }
-        else if (type == controller_rule_setting_type_scheduler) {
-          // @todo
+
+        continue;
+      }
+
+
+      if (type == controller_rule_setting_type_scheduler) {
+
+        if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2 || rule->has & controller_rule_has_scheduler) {
+
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sRule setting requires either one or two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+          }
+
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+
+          continue;
         }
 
+        if (fl_string_dynamic_partial_compare_string(controller_string_batch, cache->buffer_item, controller_string_batch_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          rule->scheduler.policy = SCHED_BATCH;
+          rule->scheduler.priority = 0;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_deadline, cache->buffer_item, controller_string_deadline_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          rule->scheduler.policy = SCHED_DEADLINE;
+          rule->scheduler.priority = 49;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_fifo, cache->buffer_item, controller_string_fifo_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          rule->scheduler.policy = SCHED_FIFO;
+          rule->scheduler.priority = 49;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_idle, cache->buffer_item, controller_string_idle_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          rule->scheduler.policy = SCHED_IDLE;
+          rule->scheduler.priority = 0;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_other, cache->buffer_item, controller_string_other_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          rule->scheduler.policy = SCHED_OTHER;
+          rule->scheduler.priority = 0;
+        }
+        else if (fl_string_dynamic_partial_compare_string(controller_string_round_robin, cache->buffer_item, controller_string_round_robin_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+          rule->scheduler.policy = SCHED_RR;
+          rule->scheduler.priority = 49;
+        }
+        else {
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sRule setting has an unknown scheduler '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+            fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+            f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]);
+            fprintf(data.error.to.stream, "%s%s'.%s%c", data.error.notable.after->string, data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+          }
+
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+
+          continue;
+        }
+
+        if (cache->content_actions.array[i].used > 1) {
+          const bool zero_only = rule->scheduler.policy == SCHED_BATCH || rule->scheduler.policy == SCHED_IDLE || rule->scheduler.policy == SCHED_OTHER;
+
+          f_number_signed_t number = 0;
+
+          status = fl_conversion_string_to_number_signed(cache->buffer_item.string, &number, cache->content_actions.array[i].array[1]);
+
+          if (F_status_is_error(status) || (zero_only && number) || (!zero_only && (number < 1 || number > 99))) {
+            status = F_status_set_fine(status);
+
+            if ((zero_only && number) || (!zero_only && (number < 1 || number > 99)) || status == F_data_not || status == F_number || status == F_number_overflow) {
+
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid number '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[1]);
+
+                if (zero_only) {
+                  fprintf(data.error.to.stream, "%s%s', only ", data.error.notable.after->string, data.error.context.before->string);
+                  fprintf(data.error.to.stream, "%s%s0%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+                  fprintf(data.error.to.stream, "%s is", data.error.context.before->string);
+                }
+                else {
+                  fprintf(data.error.to.stream, "%s%s', only the whole numbers inclusively between ", data.error.notable.after->string, data.error.context.before->string);
+                  fprintf(data.error.to.stream, "%s%s1%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+                  fprintf(data.error.to.stream, "%s and ", data.error.context.before->string);
+                  fprintf(data.error.to.stream, "%s%s99%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+                  fprintf(data.error.to.stream, "%s are", data.error.context.before->string);
+                }
+
+                fprintf(data.error.to.stream, " allowed for the designated scheduler.%s%c", data.error.context.after->string, f_string_eol_s[0]);
+
+                controller_rule_error_print(data.error, *cache, F_false);
+              }
+
+              if (F_status_is_error_not(status_return)) {
+                status_return = F_status_set_error(F_valid_not);
+              }
+            }
+            else {
+              fll_error_print(data.error, status, "fl_conversion_string_to_number_signed", F_true);
+              status = F_status_set_error(status);
+            }
+
+            continue;
+          }
+
+          rule->scheduler.priority = number;
+        }
+
+        rule->has |= controller_rule_has_scheduler;
+
         continue;
       }
 
@@ -2050,8 +2162,7 @@ extern "C" {
                 fprintf(data.error.to.stream, "%s%sRule setting has an invalid number '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
                 fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
                 f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]);
-                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
-                fprintf(data.error.to.stream, "%s', only the whole numbers inclusively between ", data.error.context.before->string);
+                fprintf(data.error.to.stream, "%s%s', only the whole numbers inclusively between ", data.error.notable.after->string, data.error.context.before->string);
                 fprintf(data.error.to.stream, "%s%s-20%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
                 fprintf(data.error.to.stream, "%s and ", data.error.context.before->string);
                 fprintf(data.error.to.stream, "%s%s19%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
@@ -2514,7 +2625,35 @@ extern "C" {
 
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_control, data.context.set.important.after->string, rule->control.used ? rule->control.string : f_string_empty_s, f_string_eol_s[0]);
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_path, data.context.set.important.after->string, rule->path.used ? rule->path.string : f_string_empty_s, f_string_eol_s[0]);
-    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_scheduler, data.context.set.important.after->string, rule->scheduler.used ? rule->scheduler.string : f_string_empty_s, f_string_eol_s[0]);
+
+
+    fprintf(data.output.stream, "  %s%s%s", data.context.set.important.before->string, controller_string_scheduler, data.context.set.important.after->string);
+    if (rule->has & controller_rule_has_scheduler) {
+      f_string_t policy = "";
+
+      if (rule->scheduler.policy == SCHED_BATCH) {
+        policy = controller_string_batch;
+      }
+      else if (rule->scheduler.policy == SCHED_DEADLINE) {
+        policy = controller_string_deadline;
+      }
+      else if (rule->scheduler.policy == SCHED_FIFO) {
+        policy = controller_string_fifo;
+      }
+      else if (rule->scheduler.policy == SCHED_IDLE) {
+        policy = controller_string_idle;
+      }
+      else if (rule->scheduler.policy == SCHED_OTHER) {
+        policy = controller_string_other;
+      }
+      else if (rule->scheduler.policy == SCHED_RR) {
+        policy = controller_string_round_robin;
+      }
+
+      fprintf(data.output.stream, " %s %i", policy, rule->scheduler.priority);
+    }
+    fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_script, data.context.set.important.after->string, rule->script.used ? rule->script.string : f_string_empty_s, f_string_eol_s[0]);
 
     fprintf(data.output.stream, "  %s%s%s", data.context.set.important.before->string, controller_string_nice, data.context.set.important.after->string);
index b2a2bcb23e2062219887f4f880435f0064c5dd5d..da9ca3ff84cb7a2563546af2314b8f646ac107de 100644 (file)
@@ -4,6 +4,7 @@ setting:
   name "Multiple Commands: id, whoami, date, etc.."
   capability "all="
   nice 15
+  scheduler batch 0
   #user kevin
   #group list 8 root
 
index 4c650929f66c122e7b62d73cf54ae2d0be8e26c7..23abe8f77d685eeedaa17141a56bcbd55f58f2b1 100644 (file)
@@ -7,6 +7,7 @@ setting:
   name "System Logger"
   capability "all="
   nice 19
+  scheduler idle
 
 service:
   # @todo consider adding support for IKI to make "/var/run/logger/logger.pid" a variable.
index 9a1aa027fe451bd5371f2ad0ec1b939cdb0594ce..1fdf144b7d70cd5fa09a50bd9c6b49cde971961b 100644 (file)
@@ -20,7 +20,7 @@ Rule Documentation:
     "parameter": A statically defined IKI name and its associated value for use in this rule file.
     "path": A single Content used to set a custom PATH environment variable value.
     "script": An executable name of a script, such as "bash", to use for the "script" Rule Type (which likely defaults to "bash" if not specified).
-    "scheduler": A valid name of a scheduler to use.
+    "scheduler": A valid name of a scheduler to use followed by an optional priority number.
     "user": A single user name or ID to execute as.
     "want": A single rule desired to be executed (may exist and must succeed) before this rule starts.
     "wish": A single rule desired to be executed (may exist and is not required to succeed) before this rule starts.
@@ -42,6 +42,11 @@ Rule Documentation:
   A "parameter" variable and an "environment" variable are mutually exclusive but an environment variable, in theory, can have an IKI variable assigned to it inside of a "script".
   These IKI variables are only substituted within a Rule Item's Content (and not within a Rule Setting nor within a Rule Item's Object).
 
+  In the case of "scheduler", the valid range of the priority number is dependent on the scheduler.
+  For example, non-real-time schedulers (such as "idle") only support a value of 0 whereas real-time schedulers (such as "fifo") only support an inclusive range of 1 to 99.
+  Supported non-real-time schedulers are: "batch", "idle", and "other" (aka: normal/default).
+  Supported real-time schedulers are: "deadline", "fifo", "round_robin".
+
   The "command" Rule Type provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload".
   A "command" always operates in the foreground.
 
index a7ae7ae8c3022470cd64ed62bd8a4ddbd3c3fde7..5df9b62f69b49f971c08273b661aec8b64518a7f 100644 (file)
@@ -38,7 +38,7 @@ Rule Specification:
     "nice": One Content, must be a valid number for process "niceness" (Any whole number inclusively between -20 to 19).
     "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value.
     "path": One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin").
-    "scheduler": One Content representing a scheduler name.
+    "scheduler": One or Two Content representing a scheduler name and the optional numeric priority (Any whole number inclusively between 0 and 99).
     "script": One Content representing a valid program name or path (such as "bash" or "/bin/bash").
     "user": One Content representing a user name or user id.
     "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").