| /* |
| * Copyright (c) 2019 Peter Bigot Consulting, LLC |
| * Copyright (c) 2020 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_SYS_NOTIFY_H_ |
| #define ZEPHYR_INCLUDE_SYS_NOTIFY_H_ |
| |
| #include <kernel.h> |
| #include <zephyr/types.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| struct sys_notify; |
| |
| /* |
| * Flag value that overwrites the method field when the operation has |
| * completed. |
| */ |
| #define SYS_NOTIFY_METHOD_COMPLETED 0 |
| |
| /* |
| * Indicates that no notification will be provided. |
| * |
| * Callers must check for completions using |
| * sys_notify_fetch_result(). |
| * |
| * See sys_notify_init_spinwait(). |
| */ |
| #define SYS_NOTIFY_METHOD_SPINWAIT 1 |
| |
| /* |
| * Select notification through @ref k_poll signal |
| * |
| * See sys_notify_init_signal(). |
| */ |
| #define SYS_NOTIFY_METHOD_SIGNAL 2 |
| |
| /* |
| * Select notification through a user-provided callback. |
| * |
| * See sys_notify_init_callback(). |
| */ |
| #define SYS_NOTIFY_METHOD_CALLBACK 3 |
| |
| #define SYS_NOTIFY_METHOD_MASK 0x03U |
| #define SYS_NOTIFY_METHOD_POS 0 |
| |
| /** |
| * @brief Identify the region of sys_notify flags available for |
| * containing services. |
| * |
| * Bits of the flags field of the sys_notify structure at and above |
| * this position may be used by extensions to the sys_notify |
| * structure. |
| * |
| * These bits are intended for use by containing service |
| * implementations to record client-specific information. The bits |
| * are cleared by sys_notify_validate(). Use of these does not |
| * imply that the flags field becomes public API. |
| */ |
| #define SYS_NOTIFY_EXTENSION_POS 2 |
| |
| /* |
| * Mask isolating the bits of sys_notify::flags that are available |
| * for extension. |
| */ |
| #define SYS_NOTIFY_EXTENSION_MASK (~BIT_MASK(SYS_NOTIFY_EXTENSION_POS)) |
| |
| /** |
| * @defgroup sys_notify_apis Asynchronous Notification APIs |
| * @ingroup kernel_apis |
| * @{ |
| */ |
| |
| /** |
| * @brief Generic signature used to notify of result completion by |
| * callback. |
| * |
| * Functions with this role may be invoked from any context including |
| * pre-kernel, ISR, or cooperative or pre-emptible threads. |
| * Compatible functions must be isr-ok and not sleep. |
| * |
| * Parameters that should generally be passed to such functions include: |
| * |
| * * a pointer to a specific client request structure, i.e. the one |
| * that contains the sys_notify structure. |
| * * the result of the operation, either as passed to |
| * sys_notify_finalize() or extracted afterwards using |
| * sys_notify_fetch_result(). Expected values are |
| * service-specific, but the value shall be non-negative if the |
| * operation succeeded, and negative if the operation failed. |
| */ |
| typedef void (*sys_notify_generic_callback)(); |
| |
| /** |
| * @brief State associated with notification for an asynchronous |
| * operation. |
| * |
| * Objects of this type are allocated by a client, which must use an |
| * initialization function (e.g. sys_notify_init_signal()) to |
| * configure them. Generally the structure is a member of a |
| * service-specific client structure, such as onoff_client. |
| * |
| * Control of the containing object transfers to the service provider |
| * when a pointer to the object is passed to a service function that |
| * is documented to take control of the object, such as |
| * onoff_service_request(). While the service provider controls the |
| * object the client must not change any object fields. Control |
| * reverts to the client: |
| * * if the call to the service API returns an error; |
| * * when operation completion is posted. This may occur before the |
| * call to the service API returns. |
| * |
| * Operation completion is technically posted when the flags field is |
| * updated so that sys_notify_fetch_result() returns success. This |
| * will happen before the signal is posted or callback is invoked. |
| * Note that although the manager will no longer reference the |
| * sys_notify object past this point, the containing object may have |
| * state that will be referenced within the callback. Where callbacks |
| * are used control of the containing object does not revert to the |
| * client until the callback has been invoked. (Re-use within the |
| * callback is explicitly permitted.) |
| * |
| * After control has reverted to the client the notify object must be |
| * reinitialized for the next operation. |
| * |
| * The content of this structure is not public API to clients: all |
| * configuration and inspection should be done with functions like |
| * sys_notify_init_callback() and sys_notify_fetch_result(). |
| * However, services that use this structure may access certain |
| * fields directly. |
| */ |
| struct sys_notify { |
| union method { |
| /* Pointer to signal used to notify client. |
| * |
| * The signal value corresponds to the res parameter |
| * of sys_notify_callback. |
| */ |
| struct k_poll_signal *signal; |
| |
| /* Generic callback function for callback notification. */ |
| sys_notify_generic_callback callback; |
| } method; |
| |
| /* |
| * Flags recording information about the operation. |
| * |
| * Bits below SYS_NOTIFY_EXTENSION_POS are initialized by |
| * async notify API init functions like |
| * sys_notify_init_callback(), and must not by modified by |
| * extensions or client code. |
| * |
| * Bits at and above SYS_NOTIFY_EXTENSION_POS are available |
| * for use by service extensions while the containing object |
| * is managed by the service. They are not for client use, |
| * are zeroed by the async notify API init functions, and will |
| * be zeroed by sys_notify_finalize(). |
| */ |
| uint32_t volatile flags; |
| |
| /* |
| * The result of the operation. |
| * |
| * This is the value that was (or would be) passed to the |
| * async infrastructure. This field is the sole record of |
| * success or failure for spin-wait synchronous operations. |
| */ |
| int volatile result; |
| }; |
| |
| /** @internal */ |
| static inline uint32_t sys_notify_get_method(const struct sys_notify *notify) |
| { |
| uint32_t method = notify->flags >> SYS_NOTIFY_METHOD_POS; |
| |
| return method & SYS_NOTIFY_METHOD_MASK; |
| } |
| |
| /** |
| * @brief Validate and initialize the notify structure. |
| * |
| * This should be invoked at the start of any service-specific |
| * configuration validation. It ensures that the basic asynchronous |
| * notification configuration is consistent, and clears the result. |
| * |
| * Note that this function does not validate extension bits (zeroed by |
| * async notify API init functions like sys_notify_init_callback()). |
| * It may fail to recognize that an uninitialized structure has been |
| * passed because only method bits of flags are tested against method |
| * settings. To reduce the chance of accepting an uninitialized |
| * operation service validation of structures that contain an |
| * sys_notify instance should confirm that the extension bits are |
| * set or cleared as expected. |
| * |
| * @retval 0 on successful validation and reinitialization |
| * @retval -EINVAL if the configuration is not valid. |
| */ |
| int sys_notify_validate(struct sys_notify *notify); |
| |
| /** |
| * @brief Record and signal the operation completion. |
| * |
| * @param notify pointer to the notification state structure. |
| * |
| * @param res the result of the operation. Expected values are |
| * service-specific, but the value shall be non-negative if the |
| * operation succeeded, and negative if the operation failed. |
| * |
| * @return If the notification is to be done by callback this returns |
| * the generic version of the function to be invoked. The caller must |
| * immediately invoke that function with whatever arguments are |
| * expected by the callback. If notification is by spin-wait or |
| * signal, the notification has been completed by the point this |
| * function returns, and a null pointer is returned. |
| */ |
| sys_notify_generic_callback sys_notify_finalize(struct sys_notify *notify, |
| int res); |
| |
| /** |
| * @brief Check for and read the result of an asynchronous operation. |
| * |
| * @param notify pointer to the object used to specify asynchronous |
| * function behavior and store completion information. |
| * |
| * @param result pointer to storage for the result of the operation. |
| * The result is stored only if the operation has completed. |
| * |
| * @retval 0 if the operation has completed. |
| * @retval -EAGAIN if the operation has not completed. |
| */ |
| static inline int sys_notify_fetch_result(const struct sys_notify *notify, |
| int *result) |
| { |
| __ASSERT_NO_MSG(notify != NULL); |
| __ASSERT_NO_MSG(result != NULL); |
| int rv = -EAGAIN; |
| |
| if (sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_COMPLETED) { |
| rv = 0; |
| *result = notify->result; |
| } |
| |
| return rv; |
| } |
| |
| /** |
| * @brief Initialize a notify object for spin-wait notification. |
| * |
| * Clients that use this initialization receive no asynchronous |
| * notification, and instead must periodically check for completion |
| * using sys_notify_fetch_result(). |
| * |
| * On completion of the operation the client object must be |
| * reinitialized before it can be re-used. |
| * |
| * @param notify pointer to the notification configuration object. |
| */ |
| static inline void sys_notify_init_spinwait(struct sys_notify *notify) |
| { |
| __ASSERT_NO_MSG(notify != NULL); |
| |
| *notify = (struct sys_notify){ |
| .flags = SYS_NOTIFY_METHOD_SPINWAIT, |
| }; |
| } |
| |
| /** |
| * @brief Initialize a notify object for (k_poll) signal notification. |
| * |
| * Clients that use this initialization will be notified of the |
| * completion of operations through the provided signal. |
| * |
| * On completion of the operation the client object must be |
| * reinitialized before it can be re-used. |
| * |
| * @note |
| * This capability is available only when @kconfig{CONFIG_POLL} is |
| * selected. |
| * |
| * @param notify pointer to the notification configuration object. |
| * |
| * @param sigp pointer to the signal to use for notification. The |
| * value must not be null. The signal must be reset before the client |
| * object is passed to the on-off service API. |
| */ |
| static inline void sys_notify_init_signal(struct sys_notify *notify, |
| struct k_poll_signal *sigp) |
| { |
| __ASSERT_NO_MSG(notify != NULL); |
| __ASSERT_NO_MSG(sigp != NULL); |
| |
| *notify = (struct sys_notify){ |
| .method = { |
| .signal = sigp, |
| }, |
| .flags = SYS_NOTIFY_METHOD_SIGNAL, |
| }; |
| } |
| |
| /** |
| * @brief Initialize a notify object for callback notification. |
| * |
| * Clients that use this initialization will be notified of the |
| * completion of operations through the provided callback. Note that |
| * callbacks may be invoked from various contexts depending on the |
| * specific service; see @ref sys_notify_generic_callback. |
| * |
| * On completion of the operation the client object must be |
| * reinitialized before it can be re-used. |
| * |
| * @param notify pointer to the notification configuration object. |
| * |
| * @param handler a function pointer to use for notification. |
| */ |
| static inline void sys_notify_init_callback(struct sys_notify *notify, |
| sys_notify_generic_callback handler) |
| { |
| __ASSERT_NO_MSG(notify != NULL); |
| __ASSERT_NO_MSG(handler != NULL); |
| |
| *notify = (struct sys_notify){ |
| .method = { |
| .callback = handler, |
| }, |
| .flags = SYS_NOTIFY_METHOD_CALLBACK, |
| }; |
| } |
| |
| /** |
| * @brief Detect whether a particular notification uses a callback. |
| * |
| * The generic handler does not capture the signature expected by the |
| * callback, and the translation to a service-specific callback must |
| * be provided by the service. This check allows abstracted services |
| * to reject callback notification requests when the service doesn't |
| * provide a translation function. |
| * |
| * @return true if and only if a callback is to be used for notification. |
| */ |
| static inline bool sys_notify_uses_callback(const struct sys_notify *notify) |
| { |
| __ASSERT_NO_MSG(notify != NULL); |
| |
| return sys_notify_get_method(notify) == SYS_NOTIFY_METHOD_CALLBACK; |
| } |
| |
| /** @} */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_SYS_NOTIFY_H_ */ |