haproxy/include/common/initcall.h

269 lines
11 KiB
C
Raw Normal View History

MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/*
* include/common/initcall.h
*
* Initcall management.
*
* Copyright (C) 2018 Willy Tarreau - w@1wt.eu
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _COMMON_INIT_H
#define _COMMON_INIT_H
/* List of known init stages. If others are added, please declare their
* section at the end of the file below.
*/
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
/* The principle of the initcalls is to create optional sections in the target
* program which are made of arrays of structures containing a function pointer
* and 3 argument pointers. Then at boot time, these sections are scanned in a
* well defined order to call in turn each of these functions with their
* arguments. This allows to declare register callbacks in C files without
* having to export lots of things nor to cross-reference functions. There are
* several initialization stages defined so that certain guarantees are offered
* (for example list heads might or might not be initialized, pools might or
* might not have been created yet).
*
* On some very old platforms there is no convenient way to retrieve the start
* or stop pointer for these sections so there is no reliable way to enumerate
* the callbacks. When this is the case, as detected when USE_OBSOLETE_LINKER
* is set, instead of using sections we exclusively use constructors whose name
* is based on the current line number in the file to guarantee uniqueness.
* When called, these constructors then add their callback to their respective
* list. It works as well but slightly inflates the executable's size since
* code has to be emitted just to register each of these callbacks.
*/
/*
* Please keep those names short enough, they are used to generate section
* names, Mac OS X accepts section names up to 16 characters, and we prefix
* them with i_, so stage name can't be more than 14 characters.
*/
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
enum init_stage {
STG_PREPARE = 0, // preset variables, tables, list heads
STG_LOCK, // pre-initialize locks
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
};
/* This is the descriptor for an initcall */
struct initcall {
void (*const fct)(void *arg1, void *arg2, void *arg3);
void *arg1;
void *arg2;
void *arg3;
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#if defined(USE_OBSOLETE_LINKER)
void *next;
#endif
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
};
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#if !defined(USE_OBSOLETE_LINKER)
#ifdef __APPLE__
#define HA_SECTION(s) __section__("__DATA, i_" # s)
#else
#define HA_SECTION(s) __section__("init_" # s)
#endif
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* Declare a static variable in the init section dedicated to stage <stg>,
* with an element referencing function <function> and arguments <a1..a3>.
* <linenum> is needed to deduplicate entries created from a same file. The
* trick with (stg<STG_SIZE) consists in verifying that stg if a valid enum
* value from the initcall set, and to emit a warning or error if it is not.
* The function's type is cast so that it is technically possible to call a
* function taking other argument types, provided they are all the same size
* as a pointer (args are cast to (void*)). Do not use this macro directly,
* use INITCALL{0..3}() instead.
*/
#define __GLOBL1(sym) __asm__(".globl " #sym)
#define __GLOBL(sym) __GLOBL1(sym)
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
#define __DECLARE_INITCALL(stg, linenum, function, a1, a2, a3) \
__GLOBL(__start_init_##stg ); \
__GLOBL(__stop_init_##stg ); \
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
static const struct initcall *__initcb_##linenum \
__attribute__((__used__,HA_SECTION(stg))) = \
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
(stg < STG_SIZE) ? &(const struct initcall) { \
.fct = (void (*)(void *,void *,void *))function, \
.arg1 = (void *)(a1), \
.arg2 = (void *)(a2), \
.arg3 = (void *)(a3), \
} : NULL
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#else // USE_OBSOLETE_LINKER
/* Declare a static constructor function to register a static descriptor for
* stage <stg>, with an element referencing function <function> and arguments
* <a1..a3>. <linenum> is needed to deduplicate entries created from a same
* file. The trick with (stg<STG_SIZE) consists in verifying that stg if a
* valid enum value from the initcall set, and to emit a warning or error if
* it is not.
* The function's type is cast so that it is technically possible to call a
* function taking other argument types, provided they are all the same size
* as a pointer (args are cast to (void*)). Do not use this macro directly,
* use INITCALL{0..3}() instead.
*/
#define __DECLARE_INITCALL(stg, linenum, function, a1, a2, a3) \
__attribute__((constructor)) static void __initcb_##linenum() \
{ \
static struct initcall entry = { \
.fct = (void (*)(void *,void *,void *))function, \
.arg1 = (void *)(a1), \
.arg2 = (void *)(a2), \
.arg3 = (void *)(a3), \
}; \
if (stg < STG_SIZE) { \
entry.next = __initstg[stg]; \
__initstg[stg] = &entry; \
}; \
}
#endif // USE_OBSOLETE_LINKER
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* This is used to resolve <linenum> to an integer before calling
* __DECLARE_INITCALL(). Do not use this macro directly, use INITCALL{0..3}()
* instead.
*/
#define _DECLARE_INITCALL(...) \
__DECLARE_INITCALL(__VA_ARGS__)
/* This requires that function <function> is called with pointer argument
* <argument> during init stage <stage> which must be one of init_stage.
*/
#define INITCALL0(stage, function) \
_DECLARE_INITCALL(stage, __LINE__, function, 0, 0, 0)
/* This requires that function <function> is called with pointer argument
* <argument> during init stage <stage> which must be one of init_stage.
*/
#define INITCALL1(stage, function, arg1) \
_DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0)
/* This requires that function <function> is called with pointer arguments
* <arg1..2> during init stage <stage> which must be one of init_stage.
*/
#define INITCALL2(stage, function, arg1, arg2) \
_DECLARE_INITCALL(stage, __LINE__, function, arg1, arg2, 0)
/* This requires that function <function> is called with pointer arguments
* <arg1..3> during init stage <stage> which must be one of init_stage.
*/
#define INITCALL3(stage, function, arg1, arg2, arg3) \
_DECLARE_INITCALL(stage, __LINE__, function, arg1, arg2, arg3)
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#if !defined(USE_OBSOLETE_LINKER)
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* Iterate pointer p (of type initcall**) over all registered calls at
* stage <stg>.
*/
#define FOREACH_INITCALL(p,stg) \
for ((p) = &(__start_init_##stg); (p) < &(__stop_init_##stg); (p)++)
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#else // USE_OBSOLETE_LINKER
#define FOREACH_INITCALL(p,stg) \
for ((p) = __initstg[stg]; (p); (p) = (p)->next)
#endif // USE_OBSOLETE_LINKER
#if !defined(USE_OBSOLETE_LINKER)
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* Declare a section for stage <stg>. The start and stop pointers are set by
* the linker itself, which is why they're declared extern here. The weak
* attribute is used so that we declare them ourselves if the section is
* empty. The corresponding sections must contain exclusively pointers to
* make sure each location may safely be visited by incrementing a pointer.
*/
#ifdef __APPLE__
#define DECLARE_INIT_SECTION(stg) \
extern __attribute__((__weak__)) const struct initcall *__start_init_##stg __asm("section$start$__DATA$i_" # stg); \
extern __attribute__((__weak__)) const struct initcall *__stop_init_##stg __asm("section$end$__DATA$i_" # stg)
#else
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
#define DECLARE_INIT_SECTION(stg) \
extern __attribute__((__weak__)) const struct initcall *__start_init_##stg; \
extern __attribute__((__weak__)) const struct initcall *__stop_init_##stg
#endif
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* Declare all initcall sections here */
DECLARE_INIT_SECTION(STG_PREPARE);
DECLARE_INIT_SECTION(STG_LOCK);
DECLARE_INIT_SECTION(STG_ALLOC);
DECLARE_INIT_SECTION(STG_POOL);
DECLARE_INIT_SECTION(STG_REGISTER);
DECLARE_INIT_SECTION(STG_INIT);
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
// for use in the main haproxy.c file
#define DECLARE_INIT_STAGES asm("")
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* not needed anymore */
#undef DECLARE_INIT_SECTION
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#else // USE_OBSOLETE_LINKER
extern struct initcall *__initstg[STG_SIZE];
// for use in the main haproxy.c file
#define DECLARE_INIT_STAGES struct initcall *__initstg[STG_SIZE]
#endif // USE_OBSOLETE_LINKER
#if !defined(USE_OBSOLETE_LINKER)
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
/* Run the initcalls for stage <stg>. The test on <stg> is only there to
* ensure it is a valid initcall stage.
*/
#define RUN_INITCALLS(stg) \
do { \
const struct initcall **ptr; \
if (stg >= STG_SIZE) \
break; \
FOREACH_INITCALL(ptr, stg) \
(*ptr)->fct((*ptr)->arg1, (*ptr)->arg2, (*ptr)->arg3); \
} while (0)
BUILD: re-implement an initcall variant without using executable sections The current initcall implementation relies on dedicated sections (one section per init stage) to store the initcall descriptors. Then upon startup, these sections are scanned from beginning to end and all items found there are called in sequence. On platforms like AIX or Cygwin it seems difficult to figure the beginning and end of sections as the linker doesn't seem to provide the corresponding symbols. In order to replace this, this patch simply implements an array of single linked (one per init stage) which are fed using constructors for each register call. These constructors are declared static, with a name depending on their line number in the file, in order to avoid name clashes. The final effect is the same, except that the method is slightly more expensive in that it explicitly produces code to register these initcalls : $ size haproxy.sections haproxy.constructor text data bss dec hex filename 4060312 249176 1457652 5767140 57ffe4 haproxy.sections 4062862 260408 1457652 5780922 5835ba haproxy.constructor This mechanism is enabled as an alternative to the default one when build option USE_OBSOLETE_LINKER is set. This option is currently enabled by default only on AIX and Cygwin, and may be attempted for any target which fails to build complaining about missing symbols __start_init_* and/or __stop_init_*. Once confirmed as a reliable fix, this will likely have to be backported to 1.9 where AIX and Cygwin do not build anymore.
2019-03-29 20:30:17 +00:00
#else // USE_OBSOLETE_LINKER
/* Run the initcalls for stage <stg>. The test on <stg> is only there to
* ensure it is a valid initcall stage.
*/
#define RUN_INITCALLS(stg) \
do { \
const struct initcall *ptr; \
if (stg >= STG_SIZE) \
break; \
FOREACH_INITCALL(ptr, stg) \
(ptr)->fct((ptr)->arg1, (ptr)->arg2, (ptr)->arg3); \
} while (0)
#endif // USE_OBSOLETE_LINKER
MINOR: initcall: introduce a way to register init functions to call at boot We currently have to deal with multiple initialization stages in a way that can be confusing, because certain parts rely on others having been properly initialized. Most calls consist in adding lists to existing lists, whose heads are initialized in the declaration so this is easy. But some calls create new pools and require pools to be properly initialized. Pools currently are thread-local and as such cannot be pre-initialized, requiring run-time checks. All this could be simplified by using multiple boot stages and allowing functions to be registered at various stages. One approach might be to use gcc's constructor priorities, but this requires gcc >= 4.3 which eliminates a wide spectrum of working compilers, and some versions of certain compilers (like clang 3.0) are known for silently ignore these priorities. Instead we can use our own init function registration mechanism. A first attempt was made using register_function() calls in all constructors but this made the code more painful. This patch's approach is different. It creates sections containing arrays of pointers to "initcall" descriptors. An initcall contains a pointer to a function and an argument. Each section corresponds to a specific initialization stage. Each module creates such descriptors for various calls it requires. The main() function starts by scanning each of these sections in turn to process these initcalls. This will make it possible to remove many constructors from various modules, by simply placing initcalls for the requested functions next to the keyword lists that need to be called. A first attempt was made by placing the initcalls directly into the sections instead of creating an array of pointers, but it becomes sensitive to the array's alignment which depends on the compiler and the linker, so it seems too fragile. For now we support 6 init stages : - STG_PREPARE : preset variables, tables and list heads - STG_LOCK : initialize spinlocks and rwlocks - STG_ALLOC : allocate the required structures - STG_POOL : create pools - STG_REGISTER : register static lists (keywords etc) - STG_INIT : subsystems normal initialization These ones are declared directly in the files where they are needed using one of the INITCALL* macros, passing 0 to 3 pointers as arguments. The API should possibly be extended to support a return value to give a status to the caller, and to support a unified API, possibly a bit more flexibility in the arguments. In this case it might make sense to support a set of macros to register functions having a different API and to pass the function type in the initcall itself. Special thanks to Olivier for showing how to scan sections as this is not something particularly well documented and exactly what I've been missing to achieve this.
2018-11-25 17:36:15 +00:00
#endif /* _COMMON_INIT_H */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*/