From 175da6bdb0da7c6b626c4e2d62520764998ebc07 Mon Sep 17 00:00:00 2001 From: Tomasz Bursztyka Date: Wed, 14 May 2025 15:59:08 +0200 Subject: [PATCH] init: Make entry init-function less and introduce service objects Since the addition of deinit operation in device, init and deinit have been within each device, rendering their init entry's init function useless. In order to save ROM space, let's remove the init function from init entry altogether, and introduce a new object called "service" which owns an init function to go along with SYS_INIT/SYS_INIT_NAMED. Signed-off-by: Tomasz Bursztyka --- include/zephyr/device.h | 1 - include/zephyr/init.h | 22 +++-- .../common-rom/common-rom-kernel-devices.ld | 2 + include/zephyr/service.h | 92 +++++++++++++++++++ kernel/init.c | 26 +++++- subsys/net/lib/sockets/sockets_service.c | 2 +- 6 files changed, 130 insertions(+), 15 deletions(-) create mode 100644 include/zephyr/service.h diff --git a/include/zephyr/device.h b/include/zephyr/device.h index 07fea3c2d1f..152b1257af6 100644 --- a/include/zephyr/device.h +++ b/include/zephyr/device.h @@ -1263,7 +1263,6 @@ device_get_dt_nodelabels(const struct device *dev) static const Z_DECL_ALIGN(struct init_entry) __used __noasan Z_INIT_ENTRY_SECTION( \ level, prio, Z_DEVICE_INIT_SUB_PRIO(node_id)) \ Z_INIT_ENTRY_NAME(DEVICE_NAME_GET(dev_id)) = { \ - .init_fn = NULL, \ .dev = (const struct device *)&DEVICE_NAME_GET(dev_id), \ } diff --git a/include/zephyr/init.h b/include/zephyr/init.h index d7f254c3c51..75c9d29092a 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -13,6 +13,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -65,15 +67,14 @@ struct device; */ struct init_entry { /** - * If the init function belongs to a SYS_INIT, this field stored the - * initialization function, otherwise it is set to NULL. - */ - int (*init_fn)(void); - /** - * If the init entry belongs to a device, this fields stores a - * reference to it, otherwise it is set to NULL. + * An init entry can be about a device or a service, _init_object + * will be used to differentiate depending on relative sections. */ - const struct device *dev; + union { + const void *_init_object; + const struct device *dev; + const struct service *srv; + }; }; /** @cond INTERNAL_HIDDEN */ @@ -164,9 +165,12 @@ struct init_entry { * @see SYS_INIT() */ #define SYS_INIT_NAMED(name, init_fn_, level, prio) \ + Z_SERVICE_DEFINE(name, init_fn_, level, prio); \ static const Z_DECL_ALIGN(struct init_entry) \ Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ - Z_INIT_ENTRY_NAME(name) = {.init_fn = (init_fn_), .dev = NULL} \ + Z_INIT_ENTRY_NAME(name) = { \ + .srv = (const struct service *)&Z_SERVICE_NAME_GET(name) \ + } /** @} */ diff --git a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld index 656a4b075d9..2bb7d2c509c 100644 --- a/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld +++ b/include/zephyr/linker/common-rom/common-rom-kernel-devices.ld @@ -22,6 +22,8 @@ ITERABLE_SECTION_ROM_NUMERIC(device, Z_LINK_ITERABLE_SUBALIGN) + ITERABLE_SECTION_ROM_NUMERIC(service, Z_LINK_ITERABLE_SUBALIGN) + #if defined(CONFIG_GEN_SW_ISR_TABLE) && defined(CONFIG_SHARED_INTERRUPTS) /* since z_shared_isr() is not referenced anywhere when * zephyr_pre0.elf is built, the linker will end up dropping it. diff --git a/include/zephyr/service.h b/include/zephyr/service.h new file mode 100644 index 00000000000..cbeaeecefcf --- /dev/null +++ b/include/zephyr/service.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 Tomasz Bursztyka. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SERVICE_H_ +#define ZEPHYR_INCLUDE_SERVICE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup service System service + * @ingroup os_services + * + * A system service is a one-shot initialized software component, instantiated + * via SYS_INIT() or SYS_INIT_NAMED(). It does not provide any public API. + * + * @{ + */ + +/** + * @brief Structure to store service instance + * + * This will be defined through SYS_INIT/SYS_INIT_NAMED + */ +struct service { + /** + * Initialization function + */ + int (*init)(void); +}; + +/** @cond INTERNAL_HIDDEN */ + +/** + * @brief Expands to the name of a global service object + * + * @param name Service name. + * + * @return The full name of the service object defined by the service + * definition macro. + */ +#define Z_SERVICE_NAME_GET(name) _CONCAT(__service_, name) + +/** + * @brief Initializer for @ref service + * + * @param init_fn Initialization function (mandatory). + */ +#define Z_SERVICE_INIT(init_fn) \ + { \ + .init = (init_fn) \ + } + +/** + * @brief Service section name (used for sorting purposes). + * + * @param level Initialization level. + * @param prio Initialization priority. + */ +#define Z_SERVICE_SECTION_NAME(level, prio) \ + _CONCAT(INIT_LEVEL_ORD(level), _##prio) + +/** + * @brief Define a @ref service + * + * @param name Service name. + * @param init_fn Initialization function. + * @param level Initialization level. + * @param prio Initialization priority. + */ +#define Z_SERVICE_DEFINE(name, init_fn, level, prio) \ + static const \ + STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE( \ + service, service, \ + Z_SERVICE_SECTION_NAME(level, prio), \ + Z_SERVICE_NAME_GET(name)) = Z_SERVICE_INIT(init_fn) + +/** @endcond */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SERVICE_H_ */ diff --git a/kernel/init.c b/kernel/init.c index dd9f3d7258f..2ab9804c7cf 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -136,6 +136,9 @@ enum init_level { extern const struct init_entry __init_SMP_start[]; #endif /* CONFIG_SMP */ +TYPE_SECTION_START_EXTERN(struct service, service); +TYPE_SECTION_END_EXTERN(struct service, service); + /* * storage space for the interrupt stack * @@ -337,6 +340,12 @@ static int do_device_init(const struct device *dev) return rc; } +static inline bool is_entry_about_service(const void *obj) +{ + return (obj >= (void *)_service_list_start && + obj < (void *)_service_list_end); +} + /** * @brief Execute all the init entry initialization functions at a given level * @@ -365,17 +374,26 @@ static void z_sys_init_run_level(enum init_level level) const struct init_entry *entry; for (entry = levels[level]; entry < levels[level+1]; entry++) { - const struct device *dev = entry->dev; int result = 0; + if (unlikely(entry->_init_object == NULL)) { + continue; + } + sys_trace_sys_init_enter(entry, level); - if (dev != NULL) { + + if (is_entry_about_service(entry->_init_object)) { + const struct service *srv = entry->srv; + + result = srv->init(); + } else { + const struct device *dev = entry->dev; + if ((dev->flags & DEVICE_FLAG_INIT_DEFERRED) == 0U) { result = do_device_init(dev); } - } else { - result = entry->init_fn(); } + sys_trace_sys_init_exit(entry, level, result); } } diff --git a/subsys/net/lib/sockets/sockets_service.c b/subsys/net/lib/sockets/sockets_service.c index aac226f64f7..cb9fc306745 100644 --- a/subsys/net/lib/sockets/sockets_service.c +++ b/subsys/net/lib/sockets/sockets_service.c @@ -28,7 +28,7 @@ static K_CONDVAR_DEFINE(wait_start); STRUCT_SECTION_START_EXTERN(net_socket_service_desc); STRUCT_SECTION_END_EXTERN(net_socket_service_desc); -static struct service { +static struct service_context { struct zsock_pollfd events[CONFIG_ZVFS_POLL_MAX]; int count; } ctx;