diff --git a/lib/eal/common/eal_private.h b/lib/eal/common/eal_private.h index bb315dab04..42def89a55 100644 --- a/lib/eal/common/eal_private.h +++ b/lib/eal/common/eal_private.h @@ -72,6 +72,9 @@ struct rte_config { */ struct rte_config *rte_eal_get_configuration(void); +void +eal_init_early(void); + /** * Initialize the memzone subsystem (private to eal). * diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h index 4d299f2b36..4efa50d6be 100644 --- a/lib/eal/include/rte_common.h +++ b/lib/eal/include/rte_common.h @@ -19,6 +19,8 @@ #include +#include + /* OS specific include */ #include @@ -262,101 +264,6 @@ typedef uint16_t unaligned_uint16_t; #define __rte_dealloc(dealloc, argno) #endif -#define RTE_PRIORITY_LOG 101 -#define RTE_PRIORITY_BUS 110 -#define RTE_PRIORITY_CLASS 120 -#define RTE_PRIORITY_LAST 65535 - -#define RTE_PRIO(prio) \ - RTE_PRIORITY_ ## prio - -/** - * Run function before main() with high priority. - * - * @param func - * Constructor function. - * @param prio - * Priority number must be above 100. - * Lowest number is the first to run. - */ -#ifndef RTE_INIT_PRIO /* Allow to override from EAL */ -#ifndef RTE_TOOLCHAIN_MSVC -#define RTE_INIT_PRIO(func, prio) \ -static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void) -#else -/* definition from the Microsoft CRT */ -typedef int(__cdecl *_PIFV)(void); - -#define CTOR_SECTION_LOG ".CRT$XIB" -#define CTOR_SECTION_BUS ".CRT$XIC" -#define CTOR_SECTION_CLASS ".CRT$XID" -#define CTOR_SECTION_LAST ".CRT$XIY" - -#define CTOR_PRIORITY_TO_SECTION(priority) CTOR_SECTION_ ## priority - -#define RTE_INIT_PRIO(name, priority) \ - static void name(void); \ - static int __cdecl name ## _thunk(void) { name(); return 0; } \ - __pragma(const_seg(CTOR_PRIORITY_TO_SECTION(priority))) \ - __declspec(allocate(CTOR_PRIORITY_TO_SECTION(priority))) \ - _PIFV name ## _pointer = &name ## _thunk; \ - __pragma(const_seg()) \ - static void name(void) -#endif -#endif - -/** - * Run function before main() with low priority. - * - * The constructor will be run after prioritized constructors. - * - * @param func - * Constructor function. - */ -#define RTE_INIT(func) \ - RTE_INIT_PRIO(func, LAST) - -/** - * Run after main() with low priority. - * - * @param func - * Destructor function name. - * @param prio - * Priority number must be above 100. - * Lowest number is the last to run. - */ -#ifndef RTE_FINI_PRIO /* Allow to override from EAL */ -#ifndef RTE_TOOLCHAIN_MSVC -#define RTE_FINI_PRIO(func, prio) \ -static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void) -#else -#define DTOR_SECTION_LOG "mydtor$B" -#define DTOR_SECTION_BUS "mydtor$C" -#define DTOR_SECTION_CLASS "mydtor$D" -#define DTOR_SECTION_LAST "mydtor$Y" - -#define DTOR_PRIORITY_TO_SECTION(priority) DTOR_SECTION_ ## priority - -#define RTE_FINI_PRIO(name, priority) \ - static void name(void); \ - __pragma(const_seg(DTOR_PRIORITY_TO_SECTION(priority))) \ - __declspec(allocate(DTOR_PRIORITY_TO_SECTION(priority))) void *name ## _pointer = &name; \ - __pragma(const_seg()) \ - static void name(void) -#endif -#endif - -/** - * Run after main() with high priority. - * - * The destructor will be run *before* prioritized destructors. - * - * @param func - * Destructor function name. - */ -#define RTE_FINI(func) \ - RTE_FINI_PRIO(func, LAST) - /** * Hint never returning function */ diff --git a/lib/eal/linux/eal.c b/lib/eal/linux/eal.c index a6220524a4..afcbba4397 100644 --- a/lib/eal/linux/eal.c +++ b/lib/eal/linux/eal.c @@ -927,6 +927,8 @@ rte_eal_init(int argc, char **argv) struct internal_config *internal_conf = eal_get_internal_configuration(); + eal_init_early(); + /* setup log as early as possible */ if (eal_parse_log_options(argc, argv) < 0) { rte_eal_init_alert("invalid log arguments."); diff --git a/lib/init/meson.build b/lib/init/meson.build new file mode 100644 index 0000000000..e503dd7294 --- /dev/null +++ b/lib/init/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024 Red Hat, Inc. + +includes += global_inc +sources = files('rte_init.c') +headers = files('rte_init.h') diff --git a/lib/init/rte_init.c b/lib/init/rte_init.c new file mode 100644 index 0000000000..eaee8b1221 --- /dev/null +++ b/lib/init/rte_init.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2024 Red Hat, Inc. + */ + +#include +#include +#include + +#include + +static bool init_called; + +RTE_TAILQ_HEAD(, rte_init) rte_init_list; +struct rte_init { + RTE_TAILQ_ENTRY(rte_init) next; + unsigned int priority; + const char *file; + int line; + void (*init)(void); +}; + +void +rte_init_register(const char *file, int line, void (*init)(void), unsigned int priority) +{ + struct rte_init *p; + struct rte_init *i; + + /* + * This code has been invoked after rte_eal_init() (common case is with drivers loaded + * as shared libraries). + */ + if (init_called) { + printf("Late init for %s:%d, priority %u\n", file, line, priority); + init(); + return; + } + + i = malloc(sizeof(*i)); + if (i == NULL) + return; + + i->priority = priority; + i->file = file; + i->line = line; + i->init = init; + + TAILQ_FOREACH(p, &rte_init_list, next) { + if (i->priority >= p->priority) + continue; + TAILQ_INSERT_BEFORE(p, i, next); + } + + TAILQ_INSERT_HEAD(&rte_init_list, i, next); +} + +void +eal_init_early(void) +{ + struct rte_init *i; + + init_called = true; + + TAILQ_FOREACH(i, &rte_init_list, next) { + printf("Init for %s:%d, priority %u\n", i->file, i->line, i->priority); + i->init(); + } +} diff --git a/lib/init/rte_init.h b/lib/init/rte_init.h new file mode 100644 index 0000000000..5a1911ea1f --- /dev/null +++ b/lib/init/rte_init.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2019 Intel Corporation + */ + +#ifndef RTE_INIT_H +#define RTE_INIT_H + +#include + +__rte_experimental +void +rte_init_register(const char *file, int line, void (*init)(void), unsigned int prio); + +__rte_internal +void +eal_init_early(void); + +#define RTE_PRIORITY_LOG 101 +#define RTE_PRIORITY_BUS 110 +#define RTE_PRIORITY_CLASS 120 +#define RTE_PRIORITY_LAST 65535 + +#define RTE_PRIO(prio) \ + RTE_PRIORITY_ ## prio + +/** + * Run function before main() with high priority. + * + * @param func + * Constructor function. + * @param prio + * Priority number must be above 100. + * Lowest number is the first to run. + */ +#ifndef RTE_INIT_PRIO /* Allow to override from EAL */ +#ifndef RTE_TOOLCHAIN_MSVC +#define RTE_INIT_PRIO(func, prio) \ +static void func(void); \ +static void __attribute__((constructor(RTE_PRIO(prio)), used)) init_ ## func(void) \ +{ \ + rte_init_register(__FILE__, __LINE__, func, RTE_PRIO(prio)); \ +} \ +static void func(void) +#else +/* definition from the Microsoft CRT */ +typedef int(__cdecl *_PIFV)(void); + +#define CTOR_SECTION_LOG ".CRT$XIB" +#define CTOR_SECTION_BUS ".CRT$XIC" +#define CTOR_SECTION_CLASS ".CRT$XID" +#define CTOR_SECTION_LAST ".CRT$XIY" + +#define CTOR_PRIORITY_TO_SECTION(priority) CTOR_SECTION_ ## priority + +#define RTE_INIT_PRIO(name, priority) \ + static void name(void); \ + static int __cdecl name ## _thunk(void) { name(); return 0; } \ + __pragma(const_seg(CTOR_PRIORITY_TO_SECTION(priority))) \ + __declspec(allocate(CTOR_PRIORITY_TO_SECTION(priority))) \ + _PIFV name ## _pointer = &name ## _thunk; \ + __pragma(const_seg()) \ + static void name(void) +#endif +#endif + +/** + * Run function before main() with low priority. + * + * The constructor will be run after prioritized constructors. + * + * @param func + * Constructor function. + */ +#define RTE_INIT(func) \ + RTE_INIT_PRIO(func, LAST) + +/** + * Run after main() with low priority. + * + * @param func + * Destructor function name. + * @param prio + * Priority number must be above 100. + * Lowest number is the last to run. + */ +#ifndef RTE_FINI_PRIO /* Allow to override from EAL */ +#ifndef RTE_TOOLCHAIN_MSVC +#define RTE_FINI_PRIO(func, prio) \ +static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void) +#else +#define DTOR_SECTION_LOG "mydtor$B" +#define DTOR_SECTION_BUS "mydtor$C" +#define DTOR_SECTION_CLASS "mydtor$D" +#define DTOR_SECTION_LAST "mydtor$Y" + +#define DTOR_PRIORITY_TO_SECTION(priority) DTOR_SECTION_ ## priority + +#define RTE_FINI_PRIO(name, priority) \ + static void name(void); \ + __pragma(const_seg(DTOR_PRIORITY_TO_SECTION(priority))) \ + __declspec(allocate(DTOR_PRIORITY_TO_SECTION(priority))) void *name ## _pointer = &name; \ + __pragma(const_seg()) \ + static void name(void) +#endif +#endif + +/** + * Run after main() with high priority. + * + * The destructor will be run *before* prioritized destructors. + * + * @param func + * Destructor function name. + */ +#define RTE_FINI(func) \ + RTE_FINI_PRIO(func, LAST) + +#endif /* RTE_INIT_H */ diff --git a/lib/init/version.map b/lib/init/version.map new file mode 100644 index 0000000000..06be9445d0 --- /dev/null +++ b/lib/init/version.map @@ -0,0 +1,13 @@ +EXPERIMENTAL { + global: + + rte_init_register; + + local: *; +}; + +INTERNAL { + global: + + eal_init_early; +}; diff --git a/lib/meson.build b/lib/meson.build index ce92cb5537..6a9390c272 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -9,6 +9,7 @@ # given as a dep, no need to mention ring. This is especially true for the # core libs which are widely reused, so their deps are kept to a minimum. libraries = [ + 'init', 'log', 'kvargs', # eal depends on kvargs 'argparse', @@ -74,6 +75,7 @@ always_enable = [ 'eal', 'ethdev', 'hash', + 'init', 'kvargs', 'log', 'mbuf', @@ -134,6 +136,10 @@ foreach l:libraries # external package/library requirements ext_deps = [] deps = [] + # init (that comes first in the libraries list) can't depend on itself + if dpdk_conf.has('RTE_LIB_INIT') + deps += ['init'] + endif # eal is standard dependency once built if dpdk_conf.has('RTE_LIB_EAL') deps += ['eal']