From 4bdee23501739236bee34d9c5dae90fef2bde057 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 3 Mar 2022 10:32:22 +0100 Subject: [PATCH] xen/sched: generate code for calling scheduler callbacks In order to avoid calls via function pointers don't use per scheduler call vectors, but generate the respective call stubs dynamically based on the defined schedulers. Use a definition file for defining the templates of the callbacks and the configured schedulers. The stubs will be using if () and switch () statements to call into the correct scheduler using the scheduler id. The default scheduler is likely to be used in most cases, so it is called using an if ( likely() ) construct. In case only a single scheduler is configured the stub will be just a wrapper for that scheduler. The callbacks inside the single schedulers need to have standard names in the form "sched_callback" with "sched" being the scheduler name (e.g. "credit2"), and "callback" being the specific function (e.g. "init"), resulting in a function name like "credit2_init". Signed-off-by: Juergen Gross --- .gitignore | 1 + xen/common/sched/Makefile | 12 +++ xen/common/sched/gen-sched-defs.awk | 152 ++++++++++++++++++++++++++++ xen/common/sched/private.h | 2 + xen/common/sched/sched-defs.c | 62 ++++++++++++ 5 files changed, 229 insertions(+) create mode 100644 xen/common/sched/gen-sched-defs.awk create mode 100644 xen/common/sched/sched-defs.c diff --git a/.gitignore b/.gitignore index d425be4bd9..d976cbf794 100644 --- a/.gitignore +++ b/.gitignore @@ -316,6 +316,7 @@ xen/arch/*/efi/runtime.c xen/arch/*/include/asm/asm-offsets.h xen/common/config_data.S xen/common/config.gz +xen/common/sched/sched-defs.h xen/include/headers*.chk xen/include/compat/* xen/include/config/ diff --git a/xen/common/sched/Makefile b/xen/common/sched/Makefile index 3537f2a68d..f7ba8b184c 100644 --- a/xen/common/sched/Makefile +++ b/xen/common/sched/Makefile @@ -5,3 +5,15 @@ obj-$(CONFIG_SCHED_CREDIT2) += credit2.o obj-$(CONFIG_SCHED_RTDS) += rt.o obj-$(CONFIG_SCHED_NULL) += null.o obj-y += core.o + +quiet_cmd_gendefs = GEN $@ +cmd_gendefs = awk -f $(src)/gen-sched-defs.awk <$< >$@ + +$(addprefix $(obj)/,$(obj-y)): $(obj)/sched-defs.h + +$(obj)/sched-defs.h: $(obj)/sched-defs.i $(src)/gen-sched-defs.awk FORCE + $(call if_changed,gendefs) + +targets += sched-defs.h + +clean-files := sched-defs.h sched-defs.i diff --git a/xen/common/sched/gen-sched-defs.awk b/xen/common/sched/gen-sched-defs.awk new file mode 100644 index 0000000000..b445271db0 --- /dev/null +++ b/xen/common/sched/gen-sched-defs.awk @@ -0,0 +1,152 @@ +# awk script to generate scheduler calling stubs without using function vectors + +BEGIN { + printf("/* Generated file, do not edit! */\n\n"); + s = 0; + n = 0; + ret[0] = 0; +} + +# Issue error to stderr +function do_err(msg) { + print "Error: "msg": "$0 >"/dev/stderr"; + exit 1; +} + +function parse_def(id, ret) { + sub("^ *", "", id); # Remove leading white space + sub(" +", " ", id); # Replace multiple spaces with single ones + sub(" *$", "", id); # Remove trailing white space + ret[1] = index(id, "*"); # Is it a pointer type? + sub("[*]", "", id); # Remove "*" + if (index(id, " ") == 0) + do_err("Identifier with no type or no name"); + ret[0] = id; + sub(" [^ ]+$", "", ret[0]); # Remove identifier name + ret[2] = id; + sub("^([^ ]+ )+", "", ret[2]); # Remove type +} + +function print_id(t, p, n, x) { + printf("%s ", t); + if (p > 0) + printf("*"); + if (x != "") + printf("%s_", x); + printf("%s", n); +} + +function print_call(s, f, p) { + printf(" return %s_%s(", s, fn_name[f]); + if (n_args[f] > 0) { + for (p = 1; p <= n_args[f]; p++) { + if (p > 1) + printf(", "); + printf("%s", arg[f, p]); + } + } + printf(");\n"); +} + +# Skip preprocessing artefacts +$1 == "extern" { + next; +} +/^#/ { + next; +} + +# Drop empty lines +NF == 0 { + next; +} + +# Handle "scheduler:" line +$1 == "scheduler:" { + if (NF < 2) + do_err("\"scheduler:\" requires one parameter"); + scheds[$2] = 1; + s++; + next; +} + +# Handle "default:" line +$1 == "default:" { + if (NF < 2) + do_err("\"default:\" requires one parameter"); + if (substr($2, 1, 1) != "\"" || substr($2, length($2)) != "\"") + do_err("\"default:\" parameter must be enclosed in \""); + sched_def = substr($2, 2, length($2) - 2); + next; +} + +# Handle prototype line +{ + bro = index($0, "("); + brc = index($0, ")"); + if (bro < 2 || brc < bro) + do_err("No valid prototype line"); + n++; + fun = substr($0, 1, bro - 1); + parse_def(fun, ret); + fn_type[n] = ret[0]; fn_ptr[n] = ret[1]; fn_name[n] = ret[2]; + args = substr($0, bro + 1, brc - bro - 1); + n_args[n] = split(args, a, ","); + if (n_args[n] == 1 && a[1] == "void") { + n_args[n] = 0; + next; + } + for (i = 1; i <= n_args[n]; i++) { + parse_def(a[i], ret); + typ[n, i] = ret[0]; ptr[n, i] = ret[1]; arg[n, i] = ret[2]; + } +} + +# Generate the output +END { + for (i in scheds) { + for (f = 1; f <= n; f++) { + print_id(fn_type[f], fn_ptr[f], fn_name[f], i); + printf("("); + if (n_args[f] == 0) { + printf("void);\n"); + continue; + } + for (p = 1; p <= n_args[f]; p++) { + if (p > 1) + printf(", "); + print_id(typ[f, p], ptr[f, p], arg[f, p], ""); + } + printf(");\n"); + } + printf("\n"); + } + + for (f = 1; f <= n; f++) { + printf("static inline "); + print_id(fn_type[f], fn_ptr[f], fn_name[f], "sched"); + printf("(unsigned int id"); + if (n_args[f] > 0) { + for (p = 1; p <= n_args[f]; p++) { + printf(", "); + print_id(typ[f, p], ptr[f, p], arg[f, p], ""); + } + } + printf(")\n"); + printf("{\n"); + printf(" if ( likely(id == XEN_SCHEDULER_%s) )\n", toupper(sched_def)); + print_call(sched_def, f); + printf(" switch ( id )\n"); + printf(" {\n"); + for (i in scheds) { + if (i == sched_def) + continue; + printf(" case XEN_SCHEDULER_%s:\n", toupper(i)); + print_call(i, f); + } + printf(" default:\n"); + printf(" BUG();\n"); + printf(" }\n"); + printf("}\n\n"); + } +} diff --git a/xen/common/sched/private.h b/xen/common/sched/private.h index a870320146..1669e82f6b 100644 --- a/xen/common/sched/private.h +++ b/xen/common/sched/private.h @@ -608,4 +608,6 @@ void cpupool_put(struct cpupool *pool); int cpupool_add_domain(struct domain *d, unsigned int poolid); void cpupool_rm_domain(struct domain *d); +#include "sched-defs.h" + #endif /* __XEN_SCHED_IF_H__ */ diff --git a/xen/common/sched/sched-defs.c b/xen/common/sched/sched-defs.c new file mode 100644 index 0000000000..82096a65d4 --- /dev/null +++ b/xen/common/sched/sched-defs.c @@ -0,0 +1,62 @@ +/* + * Scheduler callbacks + * + * Syntax for definitions: + * scheduler: + * Adds the scheduler "name" to the possible schedulers + * default: "" + * Specifies the default scheduler + * All other non-empty lines being no preprocessor commands or comments are + * treated as callback prototypes. The function name is used to create the + * stub call-function "sched_()" with the scheduler id to be passed as + * first parameter, followed by the other prototype's parameters. The called + * functions are named "_()", with the prototypes of those + * being in the generated file, too. + */ + +#ifdef CONFIG_SCHED_CREDIT +scheduler: credit +#endif +#ifdef CONFIG_SCHED_CREDIT2 +scheduler: credit2 +#endif +#ifdef CONFIG_SCHED_RTDS +scheduler: rtds +#endif +#ifdef CONFIG_SCHED_ARINC653 +scheduler: arinc653 +#endif +#ifdef CONFIG_SCHED_NULL +scheduler: null +#endif +scheduler: idle +default: CONFIG_SCHED_DEFAULT + +int global_init(void); +int init(struct scheduler *s); +void *deinit(struct scheduler *s); +void *free_udata(const struct scheduler *s, void *data); +void *alloc_udata(const struct scheduler *s, struct sched_unit *unit, void *dom_data); +void free_pdata(const struct scheduler *s, void *data, int cpu); +void *alloc_pdata(const struct scheduler *s, int cpu); +void deinit_pdata(const struct scheduler *s, void *data, int cpu); +/* Returns ERR_PTR(-err) for error, NULL for 'nothing needed'. */ +void *alloc_domdata(const struct scheduler *s, struct domain *d); +/* Idempotent. */ +void free_domdata(const struct scheduler *s, void *data); +spinlock_t *switch_sched(struct scheduler *s, unsigned int cpu, void *pdata, void *vdata); +/* Activate / deactivate units in a cpu pool */ +void insert_unit(const struct scheduler *s, struct sched_unit *unit); +void remove_unit(const struct scheduler *s, struct sched_unit *unit); +void sleep(const struct scheduler *s, struct sched_unit *unit); +void wake(const struct scheduler *s, struct sched_unit *unit); +void yield(const struct scheduler *s, struct sched_unit *unit); +void context_saved(const struct scheduler *s, struct sched_unit *unit); +void do_schedule(const struct scheduler *s, struct sched_unit *prev, s_time_t now, bool tasklet_work_scheduled); +struct sched_resource *pick_resource(const struct scheduler *s, const struct sched_unit *unit); +void migrate(const struct scheduler *s, struct sched_unit *unit, unsigned int cpu); +int adjust(const struct scheduler *s, struct domain *d, struct xen_domctl_scheduler_op *op); +void adjust_affinity(const struct scheduler *s, struct sched_unit *unit, const struct cpumask *hard, const struct cpumask *soft); +int adjust_global(const struct scheduler *s, struct xen_sysctl_scheduler_op *op); +void dump_settings(const struct scheduler *s); +void dump_cpu_state(const struct scheduler *s, int cpu); -- 2.34.1