123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- /*
- * 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 uninititalized
- * 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_ */
|