-
Notifications
You must be signed in to change notification settings - Fork 7.4k
init: Make entry init-function less and introduce service objects #90014
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tbursztyka
wants to merge
4
commits into
zephyrproject-rtos:main
Choose a base branch
from
tbursztyka:init_fn_out
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+154
−42
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
b1ab527
init: Make entry init-function less and introduce service objects
tbursztyka 0c2aa72
scripts: Removing init function pointer from check_init_priorities.py
tbursztyka b06e83b
tests: misc: Fixing expected output on check_init_priorities test
tbursztyka f0e862f
cmake: Add service section to commo-rom linker generator
tbursztyka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <zephyr/sys/iterable_sections.h> | ||
|
||
#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_ */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This per-item test seems needless. You're sorting them in the linker already as a "sub-section" of an existing contiguous level. No need to check every item, just walk the prefix that is "devices" and the suffix which is "services", no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am afraid I don't see what you are seeing. Service and device presence in init entries is shuffled, so one after another an init entry might point to a service or a device. What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be possible to do what Andy is suggesting, but I think it would require initializing devices either before or after services. Given that some services likely do depend on devices being initialized and some do not depend on devices being initialized, it might also require multiple passes through the service area to look only for certain priorities before, and then only certain priorities after.
The way it's done in this PR is probably the lesser evil of the two but it does add a few extra instructions to be executed before every init routine. So there is maybe a small price to pay here in terms of speed and the trade-off is to gain some amount of space back.
So @tbursztyka - this PR is kind of a space-optimization, unless I'm misunderstanding.
If you quantize the space savings, it is is the size of 1
void *
per device, is that right?So on 32-bit system with 16 devices, we would be 64 bytes in
.rodata
and gaining maybe 32 bytes in.text
?Of course the growth in
.text
is O(1) whereas the savings in.rodata
is O(n), in terms of number of devices, so in the end, the space savings should be worth it.Is the space savings worth it at the expense of additional time needed for init?
Maybe I'm looking into it too much 😅
What do you think @peter-mitsis ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.text size depends on the architecture, so on x86 it's a mere 12bytes added, on arm cortex_m0 it's 20bytes.
I don't think timing is going to be badly impacted by such check. (it's on if statement added, and a new indirection for services). We are probably talking about µs of difference in overall.
It's a small gain, one could argue it's negligible but there are numerous place where rom/ram size is loosely taken into account (it always surprises me that ppl developing for embedded systems are sometimes not aligning structures for instance, nor using bits instead of bytes whenever it makes sense to pack things up etc...). So such places here + there + also there etc... we end up consuming quite much data that could be useful for something else. Take #90009 for instance and add it to this current one. Continuing your example it's already 128 bytes gained on devices only. Little by little, it starts to make a difference.
Now from a design point of view, I believe my proposal makes more sense as well. init_entry is only about sorting out objects, which objects then provide the means to be initialized etc...
On further changes, in the future, we could even generalize the init operation, thus removing altogether the if statement I added to discriminate object type. (that would mean however that service init fn would take a const void * parameter as well etc...)