Resource Management¶
There are various situations where it’s necessary to coordinate resource use at runtime among multiple clients. These include power rails, clocks, other peripherals, and binary device power management. The complexity of properly managing multiple consumers of a device in a multithreaded system, especially when transitions may be asynchronous, suggests that a shared implementation is desirable.
On-Off Services¶
An on-off service supports an arbitrary number of clients of a service which has a binary state. Example applications are power rails, clocks, and binary device power management.
The service has the following properties:
The stable states are off, on, and error. The service always begins in the off state. The service may also be in a transition to a given state.
The core operations are request (add a dependency) and release (remove a dependency). The service manages the state based on calls to functions that initiate these operations.
The service transitions from off to on when first client request is received.
The service transitions from on to off when last client release is received.
Each service configuration provides functions that implement the transition from off to on, from on to off, and optionally from an error state to off. Transitions that may put a calling thread to sleep must be flagged in the configuration to support safe invocation from non-thread context.
All operations are asynchronous, and are initiated by a function call that references a specific service and is given client notification data. The function call will succeed or fail. On success, the operation is guaranteed to be initiated, but whether the operation itself succeeds or fails is indicated through client notification. The initiation functions can be invoked from pre-kernel, thread, or ISR context. In contexts and states where the operation cannot be started the function will result in an error.
Requests to turn on may be queued while a transition to off is in progress: when the service has turned off successfully it will be immediately turned on again (where context allows) and waiting clients notified when the start completes.
Requests are reference counted, but not tracked. That means clients are responsible for recording whether their requests were accepted, and for initiating a release only if they have previously successfully completed a request. Improper use of the API can cause an active client to be shut out, and the service does not maintain a record of specific clients that have been granted a request.
Failures in executing a transition are recorded and inhibit further requests or releases until the service is reset. Pending requests are notified (and cancelled) when errors are discovered.
Transition operation completion notifications are provided through any of the following mechanisms:
Signal: A pointer to a
struct k_poll_signal
is provided, and the signal is raised when the transition completes. The operation completion code is stored as the signal value.Callback: a function pointer is provided by the client along with an opaque pointer, and on completion of the operation the function is invoked with the pointer and the operation completion code.
Spin-wait: the client is required to check for operation completion using the
onoff_client_fetch_result()
function.
Synchronous transition may be implemented by a caller based on its
context, for example by using k_poll()
to wait until the
completion is signalled.
-
group
resource_mgmt_apis
Defines
-
ONOFF_SERVICE_INITIALIZER
(_start, _stop, _reset, _flags)¶
Typedefs
-
typedef void (*
onoff_service_notify_fn
)(struct onoff_service *srv, int res)¶ Signature used to notify an on-off service that a transition has completed.
Functions of this type are passed to service-specific transition functions to be used to report the completion of the operation. The functions may be invoked from any context.
- Parameters
srv
: the service for which transition was requested.res
: the result of the transition. This shall be non-negative on success, or a negative error code. If an error is indicated the service shall enter an error state.
-
typedef void (*
onoff_service_transition_fn
)(struct onoff_service *srv, onoff_service_notify_fn notify)¶ Signature used by service implementations to effect a transition.
Service definitions use two function pointers of this type to be notified that a transition is required, and a third optional one to reset service state.
The start function will be called only from the off state.
The stop function will be called only from the on state.
The reset function may be called only when onoff_service_has_error() returns true.
- Parameters
srv
: the service for which transition was requested.notify
: the function to be invoked when the transition has completed. The callee shall capture this parameter to notify on completion of asynchronous transitions. If the transition is not asynchronous, notify shall be invoked before the transition function returns.
-
typedef void (*
onoff_client_callback
)(struct onoff_service *srv, struct onoff_client *cli, void *user_data, int res)¶ Signature used to notify an on-off service client of the completion of an operation.
These functions may be invoked from any context including pre-kernel, ISR, or cooperative or pre-emptible threads. Compatible functions must be isr-callable and non-suspendable.
- Parameters
srv
: the service for which the operation was initiated.cli
: the client structure passed to the function that initiated the operation.user_data
: user data provided when the client structure was initialized with onoff_client_init_callback().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.
Enums
-
enum
onoff_service_flags
¶ Flag fields used to specify on-off service behavior.
Values:
-
ONOFF_SERVICE_START_SLEEPS
= BIT(0)¶ Flag passed to onoff_service_init().
When provided this indicates the start transition function may cause the calling thread to wait. This blocks attempts to initiate a transition from a non-thread context.
-
ONOFF_SERVICE_STOP_SLEEPS
= BIT(1)¶ Flag passed to onoff_service_init().
As with ONOFF_SERVICE_START_SLEEPS but describing the stop transition function.
-
ONOFF_SERVICE_RESET_SLEEPS
= BIT(2)¶ Flag passed to onoff_service_init().
As with ONOFF_SERVICE_START_SLEEPS but describing the reset transition function.
-
ONOFF_SERVICE_HAS_ERROR
= BIT(3)¶
-
ONOFF_SERVICE_INTERNAL_BASE
= BIT(4)¶
-
Functions
-
int
onoff_service_init
(struct onoff_service *srv, onoff_service_transition_fn start, onoff_service_transition_fn stop, onoff_service_transition_fn reset, u32_t flags)¶ Initialize an on-off service to off state.
This function must be invoked exactly once per service instance, by the infrastructure that provides the service, and before any other on-off service API is invoked on the service.
This function should never be invoked by clients of an on-off service.
- Parameters
srv
: the service definition object to be initialized.start
: the function used to (initiate a) transition from off to on. This must not be null. Include ONOFF_SERVICE_START_SLEEPS as appropriate in flags.stop
: the function used to (initiate a) transition from on to off. This must not be null. Include ONOFF_SERVICE_STOP_SLEEPS as appropriate in flags.reset
: the function used to clear errors and force the service to an off state. Pass null if the service cannot or need not be reset. (Services where a transition operation can complete with an error notification should support the reset operation.) Include ONOFF_SERVICE_RESET_SLEEPS as appropriate in flags.flags
: any or all of the flags mentioned above, e.g. ONOFF_SERVICE_START_SLEEPS. Use of other flags produces an error.
- Return Value
0
: on success-EINVAL
: if start, stop, or flags are invalid
-
static int
onoff_client_fetch_result
(const struct onoff_client *op, int *result)¶ Check for and read the result of an asynchronous operation.
- Parameters
op
: pointer to the object used to specify asynchronous function behavior and store completion information.result
: pointer to storage for the result of the operation. The result is stored only if the operation has completed.
- Return Value
0
: if the operation has completed.-EAGAIN
: if the operation has not completed.
-
static void
onoff_client_init_spinwait
(struct onoff_client *cli)¶ Initialize an on-off client to be used for a spin-wait operation notification.
Clients that use this initialization receive no asynchronous notification, and instead must periodically check for completion using onoff_client_fetch_result().
On completion of the operation the client object must be reinitialized before it can be re-used.
- Parameters
cli
: pointer to the client state object.
-
static void
onoff_client_init_signal
(struct onoff_client *cli, struct k_poll_signal *sigp)¶ Initialize an on-off client to be used for a signal operation notification.
Clients that use this initialization will be notified of the completion of operations submitted through onoff_request() and onoff_release() 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
CONFIG_POLL
is selected.- Parameters
cli
: pointer to the client state object.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 void
onoff_client_init_callback
(struct onoff_client *cli, onoff_client_callback handler, void *user_data)¶ Initialize an on-off client to be used for a callback operation notification.
Clients that use this initialization will be notified of the completion of operations submitted through on-off service API through the provided callback. Note that callbacks may be invoked from various contexts depending on the specific service; see onoff_client_callback.
On completion of the operation the client object must be reinitialized before it can be re-used.
- Parameters
cli
: pointer to the client state object.handler
: a function pointer to use for notification.user_data
: an opaque pointer passed to the handler to provide additional context.
-
int
onoff_request
(struct onoff_service *srv, struct onoff_client *cli)¶ Request a reservation to use an on-off service.
The return value indicates the success or failure of an attempt to initiate an operation to request the resource be made available. If initiation of the operation succeeds the result of the request operation is provided through the configured client notification method, possibly before this call returns.
Note that the call to this function may succeed in a case where the actual request fails. Always check the operation completion result.
As a specific example: A call to this function may succeed at a point while the service is still transitioning to off due to a previous call to onoff_release(). When the transition completes the service would normally start a transition to on. However, if the transition to off completed in a non-thread context, and the transition to on can sleep, the transition cannot be started and the request will fail with
-EWOULDBLOCK
.- Parameters
srv
: the service that will be used.cli
: a non-null pointer to client state providing instructions on synchronous expectations and how to notify the client when the request completes. Behavior is undefined if client passes a pointer object associated with an incomplete service operation.
- Return Value
Non-negative
: on successful (initiation of) request-EIO
: if service has recorded an an error-EINVAL
: if the parameters are invalid-EAGAIN
: if the reference count would overflow-EWOULDBLOCK
: if the function was invoked from non-thread context and successful initiation could result in an attempt to make the calling thread sleep.
-
int
onoff_release
(struct onoff_service *srv, struct onoff_client *cli)¶ Release a reserved use of an on-off service.
The return value indicates the success or failure of an attempt to initiate an operation to release the resource. If initiation of the operation succeeds the result of the release operation itself is provided through the configured client notification method, possibly before this call returns.
Note that the call to this function may succeed in a case where the actual release fails. Always check the operation completion result.
- Parameters
srv
: the service that will be used.cli
: a non-null pointer to client state providing instructions on how to notify the client when release completes. Behavior is undefined if cli references an object associated with an incomplete service operation.
- Return Value
Non-negative
: on successful (initiation of) release-EINVAL
: if the parameters are invalid-EIO
: if service has recorded an an error-EWOULDBLOCK
: if a non-blocking request was made and could not be satisfied without potentially blocking.-EALREADY
: if the service is already off or transitioning to off-EBUSY
: if the service is transitioning to on
-
static bool
onoff_service_has_error
(const struct onoff_service *srv)¶ Test whether an on-off service has recorded an error.
This function can be used to determine whether the service has recorded an error. Errors may be cleared by invoking onoff_service_reset().
- Return
true if and only if the service has an uncleared error.
-
int
onoff_service_reset
(struct onoff_service *srv, struct onoff_client *cli)¶ Clear errors on an on-off service and reset it to its off state.
A service can only be reset when it is in an error state as indicated by onoff_service_has_error().
The return value indicates the success or failure of an attempt to initiate an operation to reset the resource. If initiation of the operation succeeds the result of the reset operation itself is provided through the configured client notification method, possibly before this call returns. Multiple clients may request a reset; all are notified when it is complete.
Note that the call to this function may succeed in a case where the actual reset fails. Always check the operation completion result.
This function is blocking if the reset transition is blocking, unless client notification specifies no-wait.
- Note
Due to the conditions on state transition all incomplete asynchronous operations will have been informed of the error when it occurred. There need be no concern about dangling requests left after a reset completes.
- Parameters
srv
: the service to be reset.cli
: pointer to client state, including instructions on how to notify the client when reset completes. Behavior is undefined if cli references an object associated with an incomplete service operation.
- Return Value
0
: on success-ENOTSUP
: if reset is not supported-EINVAL
: if the parameters are invalid, or if the service-EALREADY
: if the service does not have a recorded error
-
int
onoff_cancel
(struct onoff_service *srv, struct onoff_client *cli)¶ Attempt to cancel an in-progress client operation.
It may be that a client has initiated an operation but needs to shut down before the operation has completed. For example, when a request was made and the need is no longer present.
There is limited support for cancelling an in-progress operation:
If a start or reset is in progress, all but one clients requesting the start can cancel their request.
If a stop is in progress, all clients requesting a restart can cancel their request;
A client requesting a release cannot cancel the release.
Be aware that any transition that was initiated on behalf of the client will continue to progress to completion. The restricted support for cancellation ensures that for any in-progress transition there will always be at least one client that will be notified when the operation completes.
If the cancellation fails the service retains control of the client object, and the client must wait for operation completion.
- Parameters
srv
: the service for which an operation is to be cancelled.cli
: a pointer to the same client state that was provided when the operation to be cancelled was issued. If the cancellation is successful the client will be notified of operation completion with a result of-ECANCELED
.
- Return Value
0
: if the cancellation was completed before the client could be notified. The client will be notified through cli with an operation completion of-ECANCELED
.-EINVAL
: if the parameters are invalid.-EWOULDBLOCK
: if cancellation was rejected because the client is the only waiter for an in-progress transition. The service retains control of the client structure.-EALREADY
: if cli was not a record of an uncompleted notification at the time the cancellation was processed. This likely indicates that the operation and client notification had already completed.
-
struct
onoff_service
¶ - #include <onoff.h>
State associated with an on-off service.
No fields in this structure are intended for use by service providers or clients. The state is to be initialized once, using onoff_service_init(), when the service provider is initialized. In case of error it may be reset through the onoff_service_reset() API.
-
struct
onoff_client
¶ - #include <onoff.h>
State associated with a client of an on-off service.
Objects of this type are allocated by a client, which must use an initialization function (e.g. onoff_client_init_signal()) to configure them.
Control of the object content transfers to the service provider when a pointer to the object is passed to any on-off service function. 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;
if the call to the service API succeeds for a no-wait operation;
when operation completion is posted (signalled or callback invoked).
After control has reverted to the client the state object must be reinitialized for the next operation.
The content of this structure is not public API: all configuration and inspection should be done with functions like onoff_client_init_callback() and onoff_client_fetch_result().
-