1 /* 2 * Copyright (C) 2020, Intel Corporation 3 * Copyright (C) 2023, Nordic Semiconductor ASA 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ 8 #define INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ 9 10 #include <zephyr/sys/__assert.h> 11 #include <zephyr/toolchain.h> 12 13 #ifdef __cplusplus 14 extern "C" { 15 #endif 16 17 /** 18 * @brief Iterable Sections APIs 19 * @defgroup iterable_section_apis Iterable Sections APIs 20 * @ingroup os_services 21 * @{ 22 */ 23 24 /** 25 * @brief Defines a new element for an iterable section for a generic type. 26 * 27 * @details 28 * Convenience helper combining __in_section() and Z_DECL_ALIGN(). 29 * The section name will be '.[SECNAME].static.[SECTION_POSTFIX]' 30 * 31 * In the linker script, create output sections for these using 32 * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM(). 33 * 34 * @note In order to store the element in ROM, a const specifier has to 35 * be added to the declaration: const TYPE_SECTION_ITERABLE(...); 36 * 37 * @param[in] type data type of variable 38 * @param[in] varname name of variable to place in section 39 * @param[in] secname type name of iterable section. 40 * @param[in] section_postfix postfix to use in section name 41 */ 42 #define TYPE_SECTION_ITERABLE(type, varname, secname, section_postfix) \ 43 Z_DECL_ALIGN(type) varname \ 44 __in_section(_##secname, static, _CONCAT(section_postfix, _)) __used __noasan 45 46 /** 47 * @brief iterable section start symbol for a generic type 48 * 49 * will return '_[OUT_TYPE]_list_start'. 50 * 51 * @param[in] secname type name of iterable section. For 'struct foobar' this 52 * would be TYPE_SECTION_START(foobar) 53 * 54 */ 55 #define TYPE_SECTION_START(secname) _CONCAT(_##secname, _list_start) 56 57 /** 58 * @brief iterable section end symbol for a generic type 59 * 60 * will return '_<SECNAME>_list_end'. 61 * 62 * @param[in] secname type name of iterable section. For 'struct foobar' this 63 * would be TYPE_SECTION_START(foobar) 64 */ 65 #define TYPE_SECTION_END(secname) _CONCAT(_##secname, _list_end) 66 67 /** 68 * @brief iterable section extern for start symbol for a generic type 69 * 70 * Helper macro to give extern for start of iterable section. The macro 71 * typically will be called TYPE_SECTION_START_EXTERN(struct foobar, foobar). 72 * This allows the macro to hand different types as well as cases where the 73 * type and section name may differ. 74 * 75 * @param[in] type data type of section 76 * @param[in] secname name of output section 77 */ 78 #define TYPE_SECTION_START_EXTERN(type, secname) \ 79 extern type TYPE_SECTION_START(secname)[] 80 81 /** 82 * @brief iterable section extern for end symbol for a generic type 83 * 84 * Helper macro to give extern for end of iterable section. The macro 85 * typically will be called TYPE_SECTION_END_EXTERN(struct foobar, foobar). 86 * This allows the macro to hand different types as well as cases where the 87 * type and section name may differ. 88 * 89 * @param[in] type data type of section 90 * @param[in] secname name of output section 91 */ 92 #define TYPE_SECTION_END_EXTERN(type, secname) \ 93 extern type TYPE_SECTION_END(secname)[] 94 95 /** 96 * @brief Iterate over a specified iterable section for a generic type 97 * 98 * @details 99 * Iterator for structure instances gathered by TYPE_SECTION_ITERABLE(). 100 * The linker must provide a _<SECNAME>_list_start symbol and a 101 * _<SECNAME>_list_end symbol to mark the start and the end of the 102 * list of struct objects to iterate over. This is normally done using 103 * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script. 104 */ 105 #define TYPE_SECTION_FOREACH(type, secname, iterator) \ 106 TYPE_SECTION_START_EXTERN(type, secname); \ 107 TYPE_SECTION_END_EXTERN(type, secname); \ 108 for (type * iterator = TYPE_SECTION_START(secname); ({ \ 109 __ASSERT(iterator <= TYPE_SECTION_END(secname),\ 110 "unexpected list end location"); \ 111 iterator < TYPE_SECTION_END(secname); \ 112 }); \ 113 iterator++) 114 115 /** 116 * @brief Get element from section for a generic type. 117 * 118 * @note There is no protection against reading beyond the section. 119 * 120 * @param[in] type type of element 121 * @param[in] secname name of output section 122 * @param[in] i Index. 123 * @param[out] dst Pointer to location where pointer to element is written. 124 */ 125 #define TYPE_SECTION_GET(type, secname, i, dst) do { \ 126 TYPE_SECTION_START_EXTERN(type, secname); \ 127 *(dst) = &TYPE_SECTION_START(secname)[i]; \ 128 } while (0) 129 130 /** 131 * @brief Count elements in a section for a generic type. 132 * 133 * @param[in] type type of element 134 * @param[in] secname name of output section 135 * @param[out] dst Pointer to location where result is written. 136 */ 137 #define TYPE_SECTION_COUNT(type, secname, dst) do { \ 138 TYPE_SECTION_START_EXTERN(type, secname); \ 139 TYPE_SECTION_END_EXTERN(type, secname); \ 140 *(dst) = ((uintptr_t)TYPE_SECTION_END(secname) - \ 141 (uintptr_t)TYPE_SECTION_START(secname)) / sizeof(type); \ 142 } while (0) 143 144 /** 145 * @brief iterable section start symbol for a struct type 146 * 147 * @param[in] struct_type data type of section 148 */ 149 #define STRUCT_SECTION_START(struct_type) \ 150 TYPE_SECTION_START(struct_type) 151 152 /** 153 * @brief iterable section extern for start symbol for a struct 154 * 155 * Helper macro to give extern for start of iterable section. 156 * 157 * @param[in] struct_type data type of section 158 */ 159 #define STRUCT_SECTION_START_EXTERN(struct_type) \ 160 TYPE_SECTION_START_EXTERN(struct struct_type, struct_type) 161 162 /** 163 * @brief iterable section end symbol for a struct type 164 * 165 * @param[in] struct_type data type of section 166 */ 167 #define STRUCT_SECTION_END(struct_type) \ 168 TYPE_SECTION_END(struct_type) 169 170 /** 171 * @brief iterable section extern for end symbol for a struct 172 * 173 * Helper macro to give extern for end of iterable section. 174 * 175 * @param[in] struct_type data type of section 176 */ 177 #define STRUCT_SECTION_END_EXTERN(struct_type) \ 178 TYPE_SECTION_END_EXTERN(struct struct_type, struct_type) 179 180 /** 181 * @brief Defines a new element of alternate data type for an iterable section. 182 * 183 * @details 184 * Special variant of STRUCT_SECTION_ITERABLE(), for placing alternate 185 * data types within the iterable section of a specific data type. The 186 * data type sizes and semantics must be equivalent! 187 */ 188 #define STRUCT_SECTION_ITERABLE_ALTERNATE(secname, struct_type, varname) \ 189 TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, varname) 190 191 /** 192 * @brief Defines an array of elements of alternate data type for an iterable 193 * section. 194 * 195 * @see STRUCT_SECTION_ITERABLE_ALTERNATE 196 */ 197 #define STRUCT_SECTION_ITERABLE_ARRAY_ALTERNATE(secname, struct_type, varname, \ 198 size) \ 199 TYPE_SECTION_ITERABLE(struct struct_type, varname[size], secname, \ 200 varname) 201 202 /** 203 * @brief Defines a new element for an iterable section. 204 * 205 * @details 206 * Convenience helper combining __in_section() and Z_DECL_ALIGN(). 207 * The section name is the struct type prepended with an underscore. 208 * The subsection is "static" and the subsubsection is the variable name. 209 * 210 * In the linker script, create output sections for these using 211 * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM(). 212 * 213 * @note In order to store the element in ROM, a const specifier has to 214 * be added to the declaration: const STRUCT_SECTION_ITERABLE(...); 215 */ 216 #define STRUCT_SECTION_ITERABLE(struct_type, varname) \ 217 STRUCT_SECTION_ITERABLE_ALTERNATE(struct_type, struct_type, varname) 218 219 /** 220 * @brief Defines an array of elements for an iterable section. 221 * 222 * @see STRUCT_SECTION_ITERABLE 223 */ 224 #define STRUCT_SECTION_ITERABLE_ARRAY(struct_type, varname, size) \ 225 STRUCT_SECTION_ITERABLE_ARRAY_ALTERNATE(struct_type, struct_type, \ 226 varname, size) 227 228 /** 229 * @brief Defines a new element for an iterable section with a custom name. 230 * 231 * The name can be used to customize how iterable section entries are sorted. 232 * @see STRUCT_SECTION_ITERABLE() 233 */ 234 #define STRUCT_SECTION_ITERABLE_NAMED(struct_type, name, varname) \ 235 TYPE_SECTION_ITERABLE(struct struct_type, varname, struct_type, name) 236 237 /** 238 * @brief Defines a new element for an iterable section with a custom name, 239 * placed in a custom section. 240 * 241 * The name can be used to customize how iterable section entries are sorted. 242 * @see STRUCT_SECTION_ITERABLE_NAMED() 243 */ 244 #define STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(struct_type, secname, name, varname) \ 245 TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, name) 246 247 /** 248 * @brief Iterate over a specified iterable section (alternate). 249 * 250 * @details 251 * Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE(). 252 * The linker must provide a _<SECNAME>_list_start symbol and a 253 * _<SECNAME>_list_end symbol to mark the start and the end of the 254 * list of struct objects to iterate over. This is normally done using 255 * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script. 256 */ 257 #define STRUCT_SECTION_FOREACH_ALTERNATE(secname, struct_type, iterator) \ 258 TYPE_SECTION_FOREACH(struct struct_type, secname, iterator) 259 260 /** 261 * @brief Iterate over a specified iterable section. 262 * 263 * @details 264 * Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE(). 265 * The linker must provide a _<struct_type>_list_start symbol and a 266 * _<struct_type>_list_end symbol to mark the start and the end of the 267 * list of struct objects to iterate over. This is normally done using 268 * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script. 269 */ 270 #define STRUCT_SECTION_FOREACH(struct_type, iterator) \ 271 STRUCT_SECTION_FOREACH_ALTERNATE(struct_type, struct_type, iterator) 272 273 /** 274 * @brief Get element from section. 275 * 276 * @note There is no protection against reading beyond the section. 277 * 278 * @param[in] struct_type Struct type. 279 * @param[in] i Index. 280 * @param[out] dst Pointer to location where pointer to element is written. 281 */ 282 #define STRUCT_SECTION_GET(struct_type, i, dst) \ 283 TYPE_SECTION_GET(struct struct_type, struct_type, i, dst) 284 285 /** 286 * @brief Count elements in a section. 287 * 288 * @param[in] struct_type Struct type 289 * @param[out] dst Pointer to location where result is written. 290 */ 291 #define STRUCT_SECTION_COUNT(struct_type, dst) \ 292 TYPE_SECTION_COUNT(struct struct_type, struct_type, dst); 293 294 /** 295 * @} 296 */ /* end of struct_section_apis */ 297 298 #ifdef __cplusplus 299 } 300 #endif 301 302 #endif /* INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ */ 303