Branch data Line data Source code
1 : : /* 2 : : * Copyright (c) 2019 Peter Bigot Consulting, LLC 3 : : * Copyright (c) 2020 Nordic Semiconductor ASA 4 : : * 5 : : * SPDX-License-Identifier: Apache-2.0 6 : : */ 7 : : 8 : : #ifndef ZEPHYR_INCLUDE_SYS_NOTIFY_H_ 9 : : #define ZEPHYR_INCLUDE_SYS_NOTIFY_H_ 10 : : 11 : : #include <kernel.h> 12 : : #include <zephyr/types.h> 13 : : 14 : : #ifdef __cplusplus 15 : : extern "C" { 16 : : #endif 17 : : 18 : : struct sys_notify; 19 : : 20 : : /* 21 : : * Flag value that overwrites the method field when the operation has 22 : : * completed. 23 : : */ 24 : : #define SYS_NOTIFY_METHOD_COMPLETED 0 25 : : 26 : : /* 27 : : * Indicates that no notification will be provided. 28 : : * 29 : : * Callers must check for completions using 30 : : * sys_notify_fetch_result(). 31 : : * 32 : : * See sys_notify_init_spinwait(). 33 : : */ 34 : : #define SYS_NOTIFY_METHOD_SPINWAIT 1 35 : : 36 : : /* 37 : : * Select notification through @ref k_poll signal 38 : : * 39 : : * See sys_notify_init_signal(). 40 : : */ 41 : : #define SYS_NOTIFY_METHOD_SIGNAL 2 42 : : 43 : : /* 44 : : * Select notification through a user-provided callback. 45 : : * 46 : : * See sys_notify_init_callback(). 47 : : */ 48 : : #define SYS_NOTIFY_METHOD_CALLBACK 3 49 : : 50 : : #define SYS_NOTIFY_METHOD_MASK 0x03U 51 : : #define SYS_NOTIFY_METHOD_POS 0 52 : : 53 : : /** 54 : : * @brief Identify the region of sys_notify flags available for 55 : : * containing services. 56 : : * 57 : : * Bits of the flags field of the sys_notify structure at and above 58 : : * this position may be used by extensions to the sys_notify 59 : : * structure. 60 : : * 61 : : * These bits are intended for use by containing service 62 : : * implementations to record client-specific information. The bits 63 : : * are cleared by sys_notify_validate(). Use of these does not 64 : : * imply that the flags field becomes public API. 65 : : */ 66 : : #define SYS_NOTIFY_EXTENSION_POS 2 67 : : 68 : : /* 69 : : * Mask isolating the bits of sys_notify::flags that are available 70 : : * for extension. 71 : : */ 72 : : #define SYS_NOTIFY_EXTENSION_MASK (~BIT_MASK(SYS_NOTIFY_EXTENSION_POS)) 73 : : 74 : : /** 75 : : * @defgroup sys_notify_apis Asynchronous Notification APIs 76 : : * @ingroup kernel_apis 77 : : * @{ 78 : : */ 79 : : 80 : : /** 81 : : * @brief Generic signature used to notify of result completion by 82 : : * callback. 83 : : * 84 : : * Functions with this role may be invoked from any context including 85 : : * pre-kernel, ISR, or cooperative or pre-emptible threads. 86 : : * Compatible functions must be isr-ok and not sleep. 87 : : * 88 : : * Parameters that should generally be passed to such functions include: 89 : : * 90 : : * * a pointer to a specific client request structure, i.e. the one 91 : : * that contains the sys_notify structure. 92 : : * * the result of the operation, either as passed to 93 : : * sys_notify_finalize() or extracted afterwards using 94 : : * sys_notify_fetch_result(). Expected values are 95 : : * service-specific, but the value shall be non-negative if the 96 : : * operation succeeded, and negative if the operation failed. 97 : : */ 98 : : typedef void (*sys_notify_generic_callback)(); 99 : : 100 : : /** 101 : : * @brief State associated with notification for an asynchronous 102 : : * operation. 103 : : * 104 : : * Objects of this type are allocated by a client, which must use an 105 : : * initialization function (e.g. sys_notify_init_signal()) to 106 : : * configure them. Generally the structure is a member of a 107 : : * service-specific client structure, such as onoff_client. 108 : : * 109 : : * Control of the containing object transfers to the service provider 110 : : * when a pointer to the object is passed to a service function that 111 : : * is documented to take control of the object, such as 112 : : * onoff_service_request(). While the service provider controls the 113 : : * object the client must not change any object fields. Control 114 : : * reverts to the client: 115 : : * * if the call to the service API returns an error; 116 : : * * when operation completion is posted. This may occur before the 117 : : * call to the service API returns. 118 : : * 119 : : * Operation completion is technically posted when the flags field is 120 : : * updated so that sys_notify_fetch_result() returns success. This 121 : : * will happen before the signal is posted or callback is invoked. 122 : : * Note that although the manager will no longer reference the 123 : : * sys_notify object past this point, the containing object may have 124 : : * state that will be referenced within the callback. Where callbacks 125 : : * are used control of the containing object does not revert to the 126 : : * client until the callback has been invoked. (Re-use within the 127 : : * callback is explicitly permitted.) 128 : : * 129 : : * After control has reverted to the client the notify object must be 130 : : * reinitialized for the next operation. 131 : : * 132 : : * The content of this structure is not public API to clients: all 133 : : * configuration and inspection should be done with functions like 134 : : * sys_notify_init_callback() and sys_notify_fetch_result(). 135 : : * However, services that use this structure may access certain 136 : : * fields directly. 137 : : */ 138 : : struct sys_notify { 139 : : union method { 140 : : /* Pointer to signal used to notify client. 141 : : * 142 : : * The signal value corresponds to the res parameter 143 : : * of sys_notify_callback. 144 : : */ 145 : : struct k_poll_signal *signal; 146 : : 147 : : /* Generic callback function for callback notification. */ 148 : : sys_notify_generic_callback callback; 149 : : } method; 150 : : 151 : : /* 152 : : * Flags recording information about the operation. 153 : : * 154 : : * Bits below SYS_NOTIFY_EXTENSION_POS are initialized by 155 : : * async notify API init functions like 156 : : * sys_notify_init_callback(), and must not by modified by 157 : : * extensions or client code. 158 : : * 159 : : * Bits at and above SYS_NOTIFY_EXTENSION_POS are available 160 : : * for use by service extensions while the containing object 161 : : * is managed by the service. They are not for client use, 162 : : * are zeroed by the async notify API init functions, and will 163 : : * be zeroed by sys_notify_finalize(). 164 : : */ 165 : : uint32_t volatile flags; 166 : : 167 : : /* 168 : : * The result of the operation. 169 : : * 170 : : * This is the value that was (or would be) passed to the 171 : : * async infrastructure. This field is the sole record of 172 : : * success or failure for spin-wait synchronous operations. 173 : : */ 174 : : int volatile result; 175 : : }; 176 : : 177 : : /** @internal */ 178 : 2 : static inline uint32_t sys_notify_get_method(const struct sys_notify *notify) 179 : : { 180 : 2 : uint32_t method = notify->flags >> SYS_NOTIFY_METHOD_POS; 181 : : 182 : 2 : return method & SYS_NOTIFY_METHOD_MASK; 183 : : } 184 : : 185 : : /** 186 : : * @brief Validate and initialize the notify structure. 187 : : * 188 : : * This should be invoked at the start of any service-specific 189 : : * configuration validation. It ensures that the basic asynchronous 190 : : * notification configuration is consistent, and clears the result. 191 : : * 192 : : * Note that this function does not validate extension bits (zeroed by 193 : : * async notify API init functions like sys_notify_init_callback()). 194 : : * It may fail to recognize that an uninitialized structure has been 195 : : * passed because only method bits of flags are tested against method 196 : : * settings. To reduce the chance of accepting an uninitialized 197 : : * operation service validation of structures that contain an 198 : : * sys_notify instance should confirm that the extension bits are 199 : : * set or cleared as expected. 200 : : * 201 : : * @retval 0 on successful validation and reinitialization 202 : : * @retval -EINVAL if the configuration is not valid. 203 : : */ 204 : : int sys_notify_validate(struct sys_notify *notify); 205 : : 206 : : /** 207 : : * @brief Record and signal the operation completion. 208 : : * 209 : : * @param notify pointer to the notification state structure. 210 : : * 211 : : * @param res the result of the operation. Expected values are 212 : : * service-specific, but the value shall be non-negative if the 213 : : * operation succeeded, and negative if the operation failed. 214 : : * 215 : : * @return If the notification is to be done by callback this returns 216 : : * the generic version of the function to be invoked. The caller must 217 : : * immediately invoke that function with whatever arguments are 218 : : * expected by the callback. If notification is by spin-wait or 219 : : * signal, the notification has been completed by the point this 220 : : * function returns, and a null pointer is returned. 221 : : */ 222 : : sys_notify_generic_callback sys_notify_finalize(struct sys_notify *notify, 223 : : int res); 224 : : 225 : : /** 226 : : * @brief Check for and read the result of an asynchronous operation. 227 : : * 228 : : * @param notify pointer to the object used to specify asynchronous 229 : : * function behavior and store completion information. 230 : : * 231 : : * @param result pointer to storage for the result of the operation. 232 : : * The result is stored only if the operation has completed. 233 : : * 234 : : * @retval 0 if the operation has completed. 235 : : * @retval -EAGAIN if the operation has not completed. 236 : : */ 237 : : static inline int sys_notify_fetch_result(const struct sys_notify *notify, 238 : : int *result) 239 : : { 240 : : __ASSERT_NO_MSG(notify != NULL); 241 : : __ASSERT_NO_MSG(result != NULL); 242 : : int rv = -EAGAIN; 243 : : 244 : : if (sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_COMPLETED) { 245 : : rv = 0; 246 : : *result = notify->result; 247 : : } 248 : : 249 : : return rv; 250 : : } 251 : : 252 : : /** 253 : : * @brief Initialize a notify object for spin-wait notification. 254 : : * 255 : : * Clients that use this initialization receive no asynchronous 256 : : * notification, and instead must periodically check for completion 257 : : * using sys_notify_fetch_result(). 258 : : * 259 : : * On completion of the operation the client object must be 260 : : * reinitialized before it can be re-used. 261 : : * 262 : : * @param notify pointer to the notification configuration object. 263 : : */ 264 : 1 : static inline void sys_notify_init_spinwait(struct sys_notify *notify) 265 : : { 266 [ - + ]: 1 : __ASSERT_NO_MSG(notify != NULL); 267 : : 268 : 1 : *notify = (struct sys_notify){ 269 : : .flags = SYS_NOTIFY_METHOD_SPINWAIT, 270 : : }; 271 : 1 : } 272 : : 273 : : /** 274 : : * @brief Initialize a notify object for (k_poll) signal notification. 275 : : * 276 : : * Clients that use this initialization will be notified of the 277 : : * completion of operations through the provided signal. 278 : : * 279 : : * On completion of the operation the client object must be 280 : : * reinitialized before it can be re-used. 281 : : * 282 : : * @note 283 : : * This capability is available only when @kconfig{CONFIG_POLL} is 284 : : * selected. 285 : : * 286 : : * @param notify pointer to the notification configuration object. 287 : : * 288 : : * @param sigp pointer to the signal to use for notification. The 289 : : * value must not be null. The signal must be reset before the client 290 : : * object is passed to the on-off service API. 291 : : */ 292 : : static inline void sys_notify_init_signal(struct sys_notify *notify, 293 : : struct k_poll_signal *sigp) 294 : : { 295 : : __ASSERT_NO_MSG(notify != NULL); 296 : : __ASSERT_NO_MSG(sigp != NULL); 297 : : 298 : : *notify = (struct sys_notify){ 299 : : .method = { 300 : : .signal = sigp, 301 : : }, 302 : : .flags = SYS_NOTIFY_METHOD_SIGNAL, 303 : : }; 304 : : } 305 : : 306 : : /** 307 : : * @brief Initialize a notify object for callback notification. 308 : : * 309 : : * Clients that use this initialization will be notified of the 310 : : * completion of operations through the provided callback. Note that 311 : : * callbacks may be invoked from various contexts depending on the 312 : : * specific service; see @ref sys_notify_generic_callback. 313 : : * 314 : : * On completion of the operation the client object must be 315 : : * reinitialized before it can be re-used. 316 : : * 317 : : * @param notify pointer to the notification configuration object. 318 : : * 319 : : * @param handler a function pointer to use for notification. 320 : : */ 321 : : static inline void sys_notify_init_callback(struct sys_notify *notify, 322 : : sys_notify_generic_callback handler) 323 : : { 324 : : __ASSERT_NO_MSG(notify != NULL); 325 : : __ASSERT_NO_MSG(handler != NULL); 326 : : 327 : : *notify = (struct sys_notify){ 328 : : .method = { 329 : : .callback = handler, 330 : : }, 331 : : .flags = SYS_NOTIFY_METHOD_CALLBACK, 332 : : }; 333 : : } 334 : : 335 : : /** 336 : : * @brief Detect whether a particular notification uses a callback. 337 : : * 338 : : * The generic handler does not capture the signature expected by the 339 : : * callback, and the translation to a service-specific callback must 340 : : * be provided by the service. This check allows abstracted services 341 : : * to reject callback notification requests when the service doesn't 342 : : * provide a translation function. 343 : : * 344 : : * @return true if and only if a callback is to be used for notification. 345 : : */ 346 : : static inline bool sys_notify_uses_callback(const struct sys_notify *notify) 347 : : { 348 : : __ASSERT_NO_MSG(notify != NULL); 349 : : 350 : : return sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_CALLBACK; 351 : : } 352 : : 353 : : /** @} */ 354 : : 355 : : #ifdef __cplusplus 356 : : } 357 : : #endif 358 : : 359 : : #endif /* ZEPHYR_INCLUDE_SYS_NOTIFY_H_ */