From 3ebe4d989cf2fdac8601e3dc0d3dd592e013c4ba Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 18 Feb 2022 14:51:49 +0100 Subject: [PATCH] MEDIUM: initcall: move STG_REGISTER earlier The STG_REGISTER init level is used to register known keywords and protocol stacks. It must be called earlier because some of the init code already relies on it to be known. For example, "haproxy -vv" for now is constrained to start very late only because of this. This patch moves it between STG_LOCK and STG_ALLOC, which is fine as it's used for static registration. --- doc/internals/api/initcalls.txt | 13 +++++++++---- include/haproxy/initcall.h | 4 ++-- src/haproxy.c | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/doc/internals/api/initcalls.txt b/doc/internals/api/initcalls.txt index b52c4ab37..4829f500a 100644 --- a/doc/internals/api/initcalls.txt +++ b/doc/internals/api/initcalls.txt @@ -213,19 +213,24 @@ and in this execution order: - STG_PREPARE : used to preset variables, pre-initialize lookup tables and pre-initialize list heads - STG_LOCK : used to pre-initialize locks + - STG_REGISTER : used to register static lists such as keywords - STG_ALLOC : used to allocate the required structures - STG_POOL : used to create pools - - STG_REGISTER : used to register static lists such as keywords - STG_INIT : used to initialize subsystems Each stage is guaranteed that previous stages have successfully completed. This -means that an INITCALL placed at stage STG_REGISTER is guaranteed that all -pools were already created and will be usable. Conversely, an INITCALL placed -at stage STG_PREPARE must not rely on any field that requires preliminary +means that an INITCALL placed at stage STG_INIT is guaranteed that all pools +were already created and will be usable. Conversely, an INITCALL placed at +stage STG_REGISTER must not rely on any field that requires preliminary allocation nor initialization. A callback cannot rely on other callbacks of the same stage, as the execution order within a stage is undefined and essentially depends on the linking order. +The STG_REGISTER level is made for run-time linking of the various modules that +compose the executable. Keywords, protocols and various other elements that are +local known to each compilation unit can will be appended into common lists at +boot time. This is why this call is placed just before STG_ALLOC. + Example: register a very early call to init_log() with no argument, and another call to cli_register_kw(&cli_kws) much later: diff --git a/include/haproxy/initcall.h b/include/haproxy/initcall.h index 50dedb7c8..1ffbabf57 100644 --- a/include/haproxy/initcall.h +++ b/include/haproxy/initcall.h @@ -63,9 +63,9 @@ enum init_stage { STG_PREPARE = 0, // preset variables, tables, list heads STG_LOCK, // pre-initialize locks + STG_REGISTER, // register static lists (keywords etc) STG_ALLOC, // allocate required structures STG_POOL, // create pools - STG_REGISTER, // register static lists (keywords etc) STG_INIT, // subsystems normal initialization STG_SIZE // size of the stages array, must be last }; @@ -200,9 +200,9 @@ __attribute__((constructor)) static void __initcb_##linenum() \ /* Declare all initcall sections here */ DECLARE_INIT_SECTION(STG_PREPARE); DECLARE_INIT_SECTION(STG_LOCK); +DECLARE_INIT_SECTION(STG_REGISTER); DECLARE_INIT_SECTION(STG_ALLOC); DECLARE_INIT_SECTION(STG_POOL); -DECLARE_INIT_SECTION(STG_REGISTER); DECLARE_INIT_SECTION(STG_INIT); // for use in the main haproxy.c file diff --git a/src/haproxy.c b/src/haproxy.c index f2e417b26..263e699b7 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -2906,9 +2906,9 @@ int main(int argc, char **argv) /* process all initcalls in order of potential dependency */ RUN_INITCALLS(STG_PREPARE); RUN_INITCALLS(STG_LOCK); + RUN_INITCALLS(STG_REGISTER); RUN_INITCALLS(STG_ALLOC); RUN_INITCALLS(STG_POOL); - RUN_INITCALLS(STG_REGISTER); RUN_INITCALLS(STG_INIT); init(argc, argv);