sys: onoff: generalize and shorten API

The original API was misnamed, as the intent was to provide a manager
that decoupled state management from the service that needed to be
turned on or off.  Update all the names, shortening them where
appropriate removing unncessary internal components like _service.

Also remove some API that misled developers into believing that onoff
managers are normally expected to be exposed directly to consumers.
While this is a use case, in most situations there are service or
client-specific actions that need to be coupled to transition events.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2020-03-03 08:20:04 -06:00 committed by Carles Cufí
commit 8bd676ed38
4 changed files with 344 additions and 328 deletions

View file

@ -10,21 +10,24 @@ complexity of properly managing multiple consumers of a device in a
multithreaded system, especially when transitions may be asynchronous, multithreaded system, especially when transitions may be asynchronous,
suggests that a shared implementation is desirable. suggests that a shared implementation is desirable.
Zephyr provides managers for several coordination policies. These
managers are embedded into services that use them for specific
functions.
.. contents:: .. contents::
:local: :local:
:depth: 2 :depth: 2
.. _resource_mgmt_onoff: .. _resource_mgmt_onoff:
On-Off Services On-Off Manager
*************** **************
An on-off service supports an arbitrary number of clients of a service An on-off manager supports an arbitrary number of clients of a service
which has a binary state. Example applications are power rails, clocks, which has a binary state. Example applications are power rails, clocks,
and binary device power management. and binary device power management.
The service has the following properties: The manager has the following properties:
* The stable states are off, on, and error. The service always begins * 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 in the off state. The service may also be in a transition to a given
@ -39,8 +42,8 @@ The service has the following properties:
* Each service configuration provides functions that implement the * Each service configuration provides functions that implement the
transition from off to on, from on to off, and optionally from an 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 error state to off. Transitions that may put a calling thread to
sleep must be flagged in the configuration to support safe invocation sleep must be flagged in the configuration to support detecting unsafe
from non-thread context. invocation from non-thread context.
* All operations are asynchronous, and are initiated by a function call * All operations are asynchronous, and are initiated by a function call
that references a specific service and is given client notification that references a specific service and is given client notification
data. The function call will succeed or fail. On success, the data. The function call will succeed or fail. On success, the
@ -58,15 +61,15 @@ Requests are reference counted, but not tracked. That means clients are
responsible for recording whether their requests were accepted, and for responsible for recording whether their requests were accepted, and for
initiating a release only if they have previously successfully completed initiating a release only if they have previously successfully completed
a request. Improper use of the API can cause an active client to be 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 shut out, and the manager does not maintain a record of specific clients
that have been granted a request. that have been granted a request.
Failures in executing a transition are recorded and inhibit further Failures in executing a transition are recorded and inhibit further
requests or releases until the service is reset. Pending requests are requests or releases until the manager is reset. Pending requests are
notified (and cancelled) when errors are discovered. notified (and cancelled) when errors are discovered.
Transition operation completion notifications are provided through any Transition operation completion notifications are provided through the
of the following mechanisms: standard :ref:`async_notification`, supporting these methods:
* Signal: A pointer to a :c:type:`struct k_poll_signal` is provided, and * Signal: A pointer to a :c:type:`struct k_poll_signal` is provided, and
the signal is raised when the transition completes. The operation the signal is raised when the transition completes. The operation
@ -81,5 +84,5 @@ Synchronous transition may be implemented by a caller based on its
context, for example by using :cpp:func:`k_poll()` to wait until the context, for example by using :cpp:func:`k_poll()` to wait until the
completion is signalled. completion is signalled.
.. doxygengroup:: resource_mgmt_apis .. doxygengroup:: resource_mgmt_onoff_apis
:project: Zephyr :project: Zephyr

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2019 Peter Bigot Consulting, LLC
* Copyright (c) 2020 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -16,7 +17,7 @@ extern "C" {
#endif #endif
/** /**
* @defgroup resource_mgmt_apis Resource Management APIs * @defgroup resource_mgmt_onoff_apis On-Off Service APIs
* @ingroup kernel_apis * @ingroup kernel_apis
* @{ * @{
*/ */
@ -24,58 +25,64 @@ extern "C" {
/** /**
* @brief Flag fields used to specify on-off service behavior. * @brief Flag fields used to specify on-off service behavior.
*/ */
enum onoff_service_flags { enum onoff_manager_flags {
/** /**
* @brief Flag used in struct onoff_service_transitions. * @brief Flag used in struct onoff_manager_transitions.
* *
* When provided this indicates the start transition function * When provided this indicates the start transition function
* may cause the calling thread to wait. This blocks attempts * may cause the calling thread to wait. This blocks attempts
* to initiate a transition from a non-thread context. * to initiate a transition from a non-thread context.
*/ */
ONOFF_SERVICE_START_SLEEPS = BIT(0), ONOFF_START_SLEEPS = BIT(0),
/** /**
* @brief Flag used in struct onoff_service_transitions. * @brief Flag used in struct onoff_manager_transitions.
* *
* As with @ref ONOFF_SERVICE_START_SLEEPS but describing the * As with @ref ONOFF_START_SLEEPS but describing the stop
* stop transition function. * transition function.
*/ */
ONOFF_SERVICE_STOP_SLEEPS = BIT(1), ONOFF_STOP_SLEEPS = BIT(1),
/** /**
* @brief Flag used in struct onoff_service_transitions. * @brief Flag used in struct onoff_manager_transitions.
* *
* As with @ref ONOFF_SERVICE_START_SLEEPS but describing the * As with @ref ONOFF_START_SLEEPS but describing the reset
* reset transition function. * transition function.
*/ */
ONOFF_SERVICE_RESET_SLEEPS = BIT(2), ONOFF_RESET_SLEEPS = BIT(2),
/* Internal use. */ /* Internal use. */
ONOFF_SERVICE_HAS_ERROR = BIT(3), ONOFF_HAS_ERROR = BIT(3),
/* This and higher bits reserved for internal use. */ /* This and higher bits reserved for internal use. */
ONOFF_SERVICE_INTERNAL_BASE = BIT(4), ONOFF_INTERNAL_BASE = BIT(4),
}; };
#define ONOFF_SERVICE_START_SLEEPS __DEPRECATED_MACRO ONOFF_START_SLEEPS
#define ONOFF_SERVICE_STOP_SLEEPS __DEPRECATED_MACRO ONOFF_STOP_SLEEPS
#define ONOFF_SERVICE_RESET_SLEEPS __DEPRECATED_MACRO ONOFF_RESET_SLEEPS
#define ONOFF_SERVICE_HAS_ERROR __DEPRECATED_MACRO ONOFF_HAS_ERROR
#define ONOFF_SERVICE_INTERNAL_BASE __DEPRECATED_MACRO ONOFF_INTERNAL_BASE
/* Forward declaration */ /* Forward declaration */
struct onoff_service; struct onoff_manager;
/** /**
* @brief Signature used to notify an on-off service that a transition * @brief Signature used to notify an on-off manager that a transition
* has completed. * has completed.
* *
* Functions of this type are passed to service-specific transition * Functions of this type are passed to service-specific transition
* functions to be used to report the completion of the operation. * functions to be used to report the completion of the operation.
* The functions may be invoked from any context. * The functions may be invoked from any context.
* *
* @param srv the service for which transition was requested. * @param mgr the manager for which transition was requested.
* *
* @param res the result of the transition. This shall be * @param res the result of the transition. This shall be
* non-negative on success, or a negative error code. If an error is * non-negative on success, or a negative error code. If an error is
* indicated the service shall enter an error state. * indicated the service shall enter an error state.
*/ */
typedef void (*onoff_service_notify_fn)(struct onoff_service *srv, typedef void (*onoff_notify_fn)(struct onoff_manager *mgr,
int res); int res);
/** /**
* @brief Signature used by service implementations to effect a * @brief Signature used by service implementations to effect a
@ -89,10 +96,10 @@ typedef void (*onoff_service_notify_fn)(struct onoff_service *srv,
* *
* The stop function will be called only from the on state. * The stop function will be called only from the on state.
* *
* The reset function may be called only when * The reset function may be called only when onoff_has_error()
* onoff_service_has_error() returns true. * returns true.
* *
* @param srv the service for which transition was requested. * @param mgr the manager for which transition was requested.
* *
* @param notify the function to be invoked when the transition has * @param notify the function to be invoked when the transition has
* completed. The callee shall capture this parameter to notify on * completed. The callee shall capture this parameter to notify on
@ -100,41 +107,40 @@ typedef void (*onoff_service_notify_fn)(struct onoff_service *srv,
* asynchronous, notify shall be invoked before the transition * asynchronous, notify shall be invoked before the transition
* function returns. * function returns.
*/ */
typedef void (*onoff_service_transition_fn)(struct onoff_service *srv, typedef void (*onoff_transition_fn)(struct onoff_manager *mgr,
onoff_service_notify_fn notify); onoff_notify_fn notify);
/** @brief On-off service transition functions. */ /** @brief On-off service transition functions. */
struct onoff_service_transitions { struct onoff_transitions {
/* Function to invoke to transition the service to on. */ /* Function to invoke to transition the service to on. */
onoff_service_transition_fn start; onoff_transition_fn start;
/* Function to invoke to transition the service to off. */ /* Function to invoke to transition the service to off. */
onoff_service_transition_fn stop; onoff_transition_fn stop;
/* Function to force the service state to reset, where supported. */ /* Function to force the service state to reset, where supported. */
onoff_service_transition_fn reset; onoff_transition_fn reset;
/* Flags identifying transition function capabilities. */ /* Flags identifying transition function capabilities. */
u8_t flags; u8_t flags;
}; };
/** /**
* @brief State associated with an on-off service. * @brief State associated with an on-off manager.
* *
* No fields in this structure are intended for use by service * No fields in this structure are intended for use by service
* providers or clients. The state is to be initialized once, using * providers or clients. The state is to be initialized once, using
* onoff_service_init(), when the service provider is initialized. * onoff_manager_init(), when the service provider is initialized. In
* In case of error it may be reset through the * case of error it may be reset through the onoff_reset() API.
* onoff_service_reset() API.
*/ */
struct onoff_service { struct onoff_manager {
/* List of clients waiting for completion of reset or /* List of clients waiting for completion of reset or
* transition to on. * transition to on.
*/ */
sys_slist_t clients; sys_slist_t clients;
/* Transition functions. */ /* Transition functions. */
const struct onoff_service_transitions *transitions; const struct onoff_transitions *transitions;
/* Mutex protection for flags, clients, releaser, and refs. */ /* Mutex protection for flags, clients, releaser, and refs. */
struct k_spinlock lock; struct k_spinlock lock;
@ -149,7 +155,7 @@ struct onoff_service {
u16_t refs; u16_t refs;
}; };
/** @brief Initializer of transitions structure. /** @brief Initializer for a onoff_transitions object.
* *
* @param _start a function used to transition from off to on state. * @param _start a function used to transition from off to on state.
* *
@ -158,21 +164,30 @@ struct onoff_service {
* @param _reset a function used to clear errors and force the service to an off * @param _reset a function used to clear errors and force the service to an off
* state. Can be null. * state. Can be null.
* *
* @param _flags any or all of the flags from enum onoff_service_flags. * @param _flags any or all of the flags from enum onoff_manager_flags.
*/ */
#define ONOFF_SERVICE_TRANSITIONS_INITIALIZER(_start, _stop, _reset, _flags) { \ #define ONOFF_TRANSITIONS_INITIALIZER(_start, _stop, _reset, _flags) { \
.start = _start, \ .start = _start, \
.stop = _stop, \ .stop = _stop, \
.reset = _reset, \ .reset = _reset, \
.flags = _flags, \ .flags = _flags, \
} }
#define ONOFF_SERVICE_TRANSITIONS_INITIALIZER(_start, _stop, _reset, _flags) \
__DEPRECATED_MACRO \
ONOFF_TRANSISTIONS_INITIALIZER(_start, _stop, _reset, _flags)
/** @internal */ /** @internal */
#define ONOFF_SERVICE_INITIALIZER(_transitions) { \ #define ONOFF_MANAGER_INITIALIZER(_transitions) { \
.transitions = _transitions, \ .transitions = _transitions, \
.flags = (_transitions)->flags, \ .flags = (_transitions)->flags, \
} }
#define ONOFF_SERVICE_INITIALIZER(_transitions) \
__DEPRECATED_MACRO \
ONOFF_MANAGER_INITIALIZER(_transitions)
/** /**
* @brief Initialize an on-off service to off state. * @brief Initialize an on-off service to off state.
* *
@ -182,7 +197,7 @@ struct onoff_service {
* *
* This function should never be invoked by clients of an on-off service. * This function should never be invoked by clients of an on-off service.
* *
* @param srv the service definition object to be initialized. * @param mgr the manager definition object to be initialized.
* *
* @param transitions A structure with transition functions. Structure must be * @param transitions A structure with transition functions. Structure must be
* persistent as it is used by the service. * persistent as it is used by the service.
@ -190,8 +205,8 @@ struct onoff_service {
* @retval 0 on success * @retval 0 on success
* @retval -EINVAL if start, stop, or flags are invalid * @retval -EINVAL if start, stop, or flags are invalid
*/ */
int onoff_service_init(struct onoff_service *srv, int onoff_manager_init(struct onoff_manager *mgr,
const struct onoff_service_transitions *transitions); const struct onoff_transitions *transitions);
/* Forward declaration */ /* Forward declaration */
struct onoff_client; struct onoff_client;
@ -204,7 +219,7 @@ struct onoff_client;
* pre-kernel, ISR, or cooperative or pre-emptible threads. * pre-kernel, ISR, or cooperative or pre-emptible threads.
* Compatible functions must be isr-callable and non-suspendable. * Compatible functions must be isr-callable and non-suspendable.
* *
* @param srv the service for which the operation was initiated. * @param mgr the manager for which the operation was initiated.
* *
* @param cli the client structure passed to the function that * @param cli the client structure passed to the function that
* initiated the operation. * initiated the operation.
@ -216,7 +231,7 @@ struct onoff_client;
* service-specific, but the value shall be non-negative if the * service-specific, but the value shall be non-negative if the
* operation succeeded, and negative if the operation failed. * operation succeeded, and negative if the operation failed.
*/ */
typedef void (*onoff_client_callback)(struct onoff_service *srv, typedef void (*onoff_client_callback)(struct onoff_manager *mgr,
struct onoff_client *cli, struct onoff_client *cli,
void *user_data, void *user_data,
int res); int res);
@ -232,11 +247,7 @@ typedef void (*onoff_client_callback)(struct onoff_service *srv,
* when a pointer to the object is passed to any on-off service * when a pointer to the object is passed to any on-off service
* function. While the service provider controls the object the * function. While the service provider controls the object the
* client must not change any object fields. Control reverts to the * client must not change any object fields. Control reverts to the
* client: * client concurrent with release of the owned sys_notify structure.
* * 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 * After control has reverted to the client the state object must be
* reinitialized for the next operation. * reinitialized for the next operation.
@ -383,7 +394,7 @@ static inline void onoff_client_init_callback(struct onoff_client *cli,
* transition to on can sleep, the transition cannot be started and * transition to on can sleep, the transition cannot be started and
* the request will fail with `-EWOULDBLOCK`. * the request will fail with `-EWOULDBLOCK`.
* *
* @param srv the service that will be used. * @param mgr the manager that will be used.
* *
* @param cli a non-null pointer to client state providing * @param cli a non-null pointer to client state providing
* instructions on synchronous expectations and how to notify the * instructions on synchronous expectations and how to notify the
@ -399,7 +410,7 @@ static inline void onoff_client_init_callback(struct onoff_client *cli,
* context and successful initiation could result in an attempt to * context and successful initiation could result in an attempt to
* make the calling thread sleep. * make the calling thread sleep.
*/ */
int onoff_request(struct onoff_service *srv, int onoff_request(struct onoff_manager *mgr,
struct onoff_client *cli); struct onoff_client *cli);
/** /**
@ -415,7 +426,7 @@ int onoff_request(struct onoff_service *srv,
* actual release fails. Always check the operation completion * actual release fails. Always check the operation completion
* result. * result.
* *
* @param srv the service that will be used. * @param mgr the manager that will be used.
* *
* @param cli a non-null pointer to client state providing * @param cli a non-null pointer to client state providing
* instructions on how to notify the client when release completes. * instructions on how to notify the client when release completes.
@ -431,7 +442,7 @@ int onoff_request(struct onoff_service *srv,
* to off * to off
* @retval -EBUSY if the service is transitioning to on * @retval -EBUSY if the service is transitioning to on
*/ */
int onoff_release(struct onoff_service *srv, int onoff_release(struct onoff_manager *mgr,
struct onoff_client *cli); struct onoff_client *cli);
/** /**
@ -439,13 +450,17 @@ int onoff_release(struct onoff_service *srv,
* *
* This function can be used to determine whether the service has * This function can be used to determine whether the service has
* recorded an error. Errors may be cleared by invoking * recorded an error. Errors may be cleared by invoking
* onoff_service_reset(). * onoff_reset().
*
* This is an unlocked convenience function suitable for use only when
* it is known that no other process might invoke an operation that
* transitions the service between an error and non-error state.
* *
* @return true if and only if the service has an uncleared error. * @return true if and only if the service has an uncleared error.
*/ */
static inline bool onoff_service_has_error(const struct onoff_service *srv) static inline bool onoff_has_error(const struct onoff_manager *mgr)
{ {
return (srv->flags & ONOFF_SERVICE_HAS_ERROR) != 0; return (mgr->flags & ONOFF_HAS_ERROR) != 0;
} }
/** /**
@ -453,7 +468,7 @@ static inline bool onoff_service_has_error(const struct onoff_service *srv)
* state. * state.
* *
* A service can only be reset when it is in an error state as * A service can only be reset when it is in an error state as
* indicated by onoff_service_has_error(). * indicated by onoff_has_error().
* *
* The return value indicates the success or failure of an attempt to * The return value indicates the success or failure of an attempt to
* initiate an operation to reset the resource. If initiation of the * initiate an operation to reset the resource. If initiation of the
@ -465,15 +480,12 @@ static inline bool onoff_service_has_error(const struct onoff_service *srv)
* Note that the call to this function may succeed in a case where the * Note that the call to this function may succeed in a case where the
* actual reset fails. Always check the operation completion result. * 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 * @note Due to the conditions on state transition all incomplete
* asynchronous operations will have been informed of the error when * asynchronous operations will have been informed of the error when
* it occurred. There need be no concern about dangling requests left * it occurred. There need be no concern about dangling requests left
* after a reset completes. * after a reset completes.
* *
* @param srv the service to be reset. * @param mgr the manager to be reset.
* *
* @param cli pointer to client state, including instructions on how * @param cli pointer to client state, including instructions on how
* to notify the client when reset completes. Behavior is undefined * to notify the client when reset completes. Behavior is undefined
@ -481,12 +493,12 @@ static inline bool onoff_service_has_error(const struct onoff_service *srv)
* operation. * operation.
* *
* @retval 0 on success * @retval 0 on success
* @retval -ENOTSUP if reset is not supported * @retval -ENOTSUP if reset is not supported by the service.
* @retval -EINVAL if the parameters are invalid, or if the service * @retval -EINVAL if the parameters are invalid.
* @retval -EALREADY if the service does not have a recorded error * @retval -EALREADY if the service does not have a recorded error.
*/ */
int onoff_service_reset(struct onoff_service *srv, int onoff_reset(struct onoff_manager *mgr,
struct onoff_client *cli); struct onoff_client *cli);
/** /**
* @brief Attempt to cancel an in-progress client operation. * @brief Attempt to cancel an in-progress client operation.
@ -511,7 +523,7 @@ int onoff_service_reset(struct onoff_service *srv,
* If the cancellation fails the service retains control of the client * If the cancellation fails the service retains control of the client
* object, and the client must wait for operation completion. * object, and the client must wait for operation completion.
* *
* @param srv the service for which an operation is to be cancelled. * @param mgr the manager for which an operation is to be cancelled.
* *
* @param cli a pointer to the same client state that was provided * @param cli a pointer to the same client state that was provided
* when the operation to be cancelled was issued. If the cancellation * when the operation to be cancelled was issued. If the cancellation
@ -530,7 +542,7 @@ int onoff_service_reset(struct onoff_service *srv,
* likely indicates that the operation and client notification had * likely indicates that the operation and client notification had
* already completed. * already completed.
*/ */
int onoff_cancel(struct onoff_service *srv, int onoff_cancel(struct onoff_manager *mgr,
struct onoff_client *cli); struct onoff_client *cli);
/** @} */ /** @} */

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2019 Peter Bigot Consulting, LLC
* Copyright (c) 2020 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -7,33 +8,32 @@
#include <kernel.h> #include <kernel.h>
#include <sys/onoff.h> #include <sys/onoff.h>
#define SERVICE_CONFIG_FLAGS \
#define SERVICE_CONFIG_FLAGS \ (ONOFF_START_SLEEPS \
(ONOFF_SERVICE_START_SLEEPS \ | ONOFF_STOP_SLEEPS \
| ONOFF_SERVICE_STOP_SLEEPS \ | ONOFF_RESET_SLEEPS)
| ONOFF_SERVICE_RESET_SLEEPS)
#define SERVICE_REFS_MAX UINT16_MAX #define SERVICE_REFS_MAX UINT16_MAX
#define SERVICE_STATE_OFF 0 #define ST_OFF 0
#define SERVICE_STATE_ON ONOFF_SERVICE_INTERNAL_BASE #define ST_ON ONOFF_INTERNAL_BASE
#define SERVICE_STATE_TRANSITION (ONOFF_SERVICE_INTERNAL_BASE << 1) #define ST_TRANSITION (ONOFF_INTERNAL_BASE << 1)
#define SERVICE_STATE_TO_ON (SERVICE_STATE_TRANSITION | SERVICE_STATE_ON) #define ST_TO_ON (ST_TRANSITION | ST_ON)
#define SERVICE_STATE_TO_OFF (SERVICE_STATE_TRANSITION | SERVICE_STATE_OFF) #define ST_TO_OFF (ST_TRANSITION | ST_OFF)
#define SERVICE_STATE_MASK (SERVICE_STATE_ON | SERVICE_STATE_TRANSITION) #define ST_MASK (ST_ON | ST_TRANSITION)
static void set_service_state(struct onoff_service *srv, static void set_service_state(struct onoff_manager *mgr,
u32_t state) u32_t state)
{ {
srv->flags &= ~SERVICE_STATE_MASK; mgr->flags &= ~ST_MASK;
srv->flags |= (state & SERVICE_STATE_MASK); mgr->flags |= (state & ST_MASK);
} }
static int validate_args(const struct onoff_service *srv, static int validate_args(const struct onoff_manager *mgr,
struct onoff_client *cli) struct onoff_client *cli)
{ {
if ((srv == NULL) || (cli == NULL)) { if ((mgr == NULL) || (cli == NULL)) {
return -EINVAL; return -EINVAL;
} }
@ -47,8 +47,8 @@ static int validate_args(const struct onoff_service *srv,
return rv; return rv;
} }
int onoff_service_init(struct onoff_service *srv, int onoff_manager_init(struct onoff_manager *mgr,
const struct onoff_service_transitions *transitions) const struct onoff_transitions *transitions)
{ {
if (transitions->flags & ~SERVICE_CONFIG_FLAGS) { if (transitions->flags & ~SERVICE_CONFIG_FLAGS) {
return -EINVAL; return -EINVAL;
@ -58,24 +58,25 @@ int onoff_service_init(struct onoff_service *srv,
return -EINVAL; return -EINVAL;
} }
*srv = (struct onoff_service)ONOFF_SERVICE_INITIALIZER(transitions); *mgr = (struct onoff_manager)ONOFF_MANAGER_INITIALIZER(transitions);
return 0; return 0;
} }
static void notify_one(struct onoff_service *srv, static void notify_one(struct onoff_manager *mgr,
struct onoff_client *cli, struct onoff_client *cli,
int res) int res)
{ {
void *ud = cli->user_data;
onoff_client_callback cb = onoff_client_callback cb =
(onoff_client_callback)sys_notify_finalize(&cli->notify, res); (onoff_client_callback)sys_notify_finalize(&cli->notify, res);
if (cb) { if (cb) {
cb(srv, cli, cli->user_data, res); cb(mgr, cli, ud, res);
} }
} }
static void notify_all(struct onoff_service *srv, static void notify_all(struct onoff_manager *mgr,
sys_slist_t *list, sys_slist_t *list,
int res) int res)
{ {
@ -86,18 +87,18 @@ static void notify_all(struct onoff_service *srv,
struct onoff_client, struct onoff_client,
node); node);
notify_one(srv, cli, res); notify_one(mgr, cli, res);
} }
} }
static void onoff_start_notify(struct onoff_service *srv, static void onoff_start_notify(struct onoff_manager *mgr,
int res) int res)
{ {
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
sys_slist_t clients = srv->clients; sys_slist_t clients = mgr->clients;
/* Can't have a queued releaser during start */ /* Can't have a queued releaser during start */
__ASSERT_NO_MSG(srv->releaser == NULL); __ASSERT_NO_MSG(mgr->releaser == NULL);
/* If the start failed log an error and leave the rest of the /* If the start failed log an error and leave the rest of the
* state in place for diagnostics. * state in place for diagnostics.
@ -110,13 +111,13 @@ static void onoff_start_notify(struct onoff_service *srv,
* clients of operation completion. * clients of operation completion.
*/ */
if (res < 0) { if (res < 0) {
srv->flags &= ~SERVICE_STATE_TRANSITION; mgr->flags &= ~ST_TRANSITION;
srv->flags |= ONOFF_SERVICE_HAS_ERROR; mgr->flags |= ONOFF_HAS_ERROR;
} else { } else {
sys_snode_t *node; sys_snode_t *node;
unsigned int refs = 0U; unsigned int refs = 0U;
set_service_state(srv, SERVICE_STATE_ON); set_service_state(mgr, ST_ON);
SYS_SLIST_FOR_EACH_NODE(&clients, node) { SYS_SLIST_FOR_EACH_NODE(&clients, node) {
refs += 1U; refs += 1U;
@ -125,78 +126,78 @@ static void onoff_start_notify(struct onoff_service *srv,
/* Update the reference count, or fail if the count /* Update the reference count, or fail if the count
* would overflow. * would overflow.
*/ */
if (srv->refs > (SERVICE_REFS_MAX - refs)) { if (mgr->refs > (SERVICE_REFS_MAX - refs)) {
srv->flags |= ONOFF_SERVICE_HAS_ERROR; mgr->flags |= ONOFF_HAS_ERROR;
} else { } else {
srv->refs += refs; mgr->refs += refs;
} }
__ASSERT_NO_MSG(srv->refs > 0U); __ASSERT_NO_MSG(mgr->refs > 0U);
} }
sys_slist_init(&srv->clients); sys_slist_init(&mgr->clients);
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
notify_all(srv, &clients, res); notify_all(mgr, &clients, res);
} }
int onoff_request(struct onoff_service *srv, int onoff_request(struct onoff_manager *mgr,
struct onoff_client *cli) struct onoff_client *cli)
{ {
bool add_client = false; /* add client to pending list */ bool add_client = false; /* add client to pending list */
bool start = false; /* invoke start transition */ bool start = false; /* invoke start transition */
bool notify = false; /* do client notification */ bool notify = false; /* do client notification */
int rv = validate_args(srv, cli); int rv = validate_args(mgr, cli);
if (rv < 0) { if (rv < 0) {
return rv; return rv;
} }
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
if ((srv->flags & ONOFF_SERVICE_HAS_ERROR) != 0) { if ((mgr->flags & ONOFF_HAS_ERROR) != 0) {
rv = -EIO; rv = -EIO;
goto out; goto out;
} }
/* Reject if this would overflow the reference count. */ /* Reject if this would overflow the reference count. */
if (srv->refs == SERVICE_REFS_MAX) { if (mgr->refs == SERVICE_REFS_MAX) {
rv = -EAGAIN; rv = -EAGAIN;
goto out; goto out;
} }
u32_t state = srv->flags & SERVICE_STATE_MASK; u32_t state = mgr->flags & ST_MASK;
switch (state) { switch (state) {
case SERVICE_STATE_TO_OFF: case ST_TO_OFF:
/* Queue to start after release */ /* Queue to start after release */
__ASSERT_NO_MSG(srv->releaser != NULL); __ASSERT_NO_MSG(mgr->releaser != NULL);
add_client = true; add_client = true;
rv = 3; rv = 3;
break; break;
case SERVICE_STATE_OFF: case ST_OFF:
/* Reject if in a non-thread context and start could /* Reject if in a non-thread context and start could
* wait. * wait.
*/ */
if ((k_is_in_isr() || k_is_pre_kernel()) if ((k_is_in_isr() || k_is_pre_kernel())
&& ((srv->flags & ONOFF_SERVICE_START_SLEEPS) != 0U)) { && ((mgr->flags & ONOFF_START_SLEEPS) != 0U)) {
rv = -EWOULDBLOCK; rv = -EWOULDBLOCK;
break; break;
} }
/* Start with first request while off */ /* Start with first request while off */
__ASSERT_NO_MSG(srv->refs == 0); __ASSERT_NO_MSG(mgr->refs == 0);
set_service_state(srv, SERVICE_STATE_TO_ON); set_service_state(mgr, ST_TO_ON);
start = true; start = true;
add_client = true; add_client = true;
rv = 2; rv = 2;
break; break;
case SERVICE_STATE_TO_ON: case ST_TO_ON:
/* Already starting, just queue it */ /* Already starting, just queue it */
add_client = true; add_client = true;
rv = 1; rv = 1;
break; break;
case SERVICE_STATE_ON: case ST_ON:
/* Just increment the reference count */ /* Just increment the reference count */
notify = true; notify = true;
break; break;
@ -207,32 +208,32 @@ int onoff_request(struct onoff_service *srv,
out: out:
if (add_client) { if (add_client) {
sys_slist_append(&srv->clients, &cli->node); sys_slist_append(&mgr->clients, &cli->node);
} else if (notify) { } else if (notify) {
srv->refs += 1; mgr->refs += 1;
} }
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
if (start) { if (start) {
__ASSERT_NO_MSG(srv->transitions->start != NULL); __ASSERT_NO_MSG(mgr->transitions->start != NULL);
srv->transitions->start(srv, onoff_start_notify); mgr->transitions->start(mgr, onoff_start_notify);
} else if (notify) { } else if (notify) {
notify_one(srv, cli, 0); notify_one(mgr, cli, 0);
} }
return rv; return rv;
} }
static void onoff_stop_notify(struct onoff_service *srv, static void onoff_stop_notify(struct onoff_manager *mgr,
int res) int res)
{ {
bool notify_clients = false; bool notify_clients = false;
int client_res = res; int client_res = res;
bool start = false; bool start = false;
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
sys_slist_t clients = srv->clients; sys_slist_t clients = mgr->clients;
struct onoff_client *releaser = srv->releaser; struct onoff_client *releaser = mgr->releaser;
/* If the stop operation failed log an error and leave the /* If the stop operation failed log an error and leave the
* rest of the state in place. * rest of the state in place.
@ -244,72 +245,72 @@ static void onoff_stop_notify(struct onoff_service *srv,
* waiting clients of operation completion. * waiting clients of operation completion.
*/ */
if (res < 0) { if (res < 0) {
srv->flags &= ~SERVICE_STATE_TRANSITION; mgr->flags &= ~ST_TRANSITION;
srv->flags |= ONOFF_SERVICE_HAS_ERROR; mgr->flags |= ONOFF_HAS_ERROR;
notify_clients = true; notify_clients = true;
} else if (sys_slist_is_empty(&clients)) { } else if (sys_slist_is_empty(&clients)) {
set_service_state(srv, SERVICE_STATE_OFF); set_service_state(mgr, ST_OFF);
} else if ((k_is_in_isr() || k_is_pre_kernel()) } else if ((k_is_in_isr() || k_is_pre_kernel())
&& ((srv->flags & ONOFF_SERVICE_START_SLEEPS) != 0U)) { && ((mgr->flags & ONOFF_START_SLEEPS) != 0U)) {
set_service_state(srv, SERVICE_STATE_OFF); set_service_state(mgr, ST_OFF);
notify_clients = true; notify_clients = true;
client_res = -EWOULDBLOCK; client_res = -EWOULDBLOCK;
} else { } else {
set_service_state(srv, SERVICE_STATE_TO_ON); set_service_state(mgr, ST_TO_ON);
start = true; start = true;
} }
__ASSERT_NO_MSG(releaser); __ASSERT_NO_MSG(releaser);
srv->refs -= 1U; mgr->refs -= 1U;
srv->releaser = NULL; mgr->releaser = NULL;
__ASSERT_NO_MSG(srv->refs == 0); __ASSERT_NO_MSG(mgr->refs == 0);
/* Remove the clients if there was an error or a delayed start /* Remove the clients if there was an error or a delayed start
* couldn't be initiated, because we're resolving their * couldn't be initiated, because we're resolving their
* operation with an error. * operation with an error.
*/ */
if (notify_clients) { if (notify_clients) {
sys_slist_init(&srv->clients); sys_slist_init(&mgr->clients);
} }
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
/* Notify the releaser. If there was an error, notify any /* Notify the releaser. If there was an error, notify any
* pending requests; otherwise if there are pending requests * pending requests; otherwise if there are pending requests
* start the transition to ON. * start the transition to ON.
*/ */
notify_one(srv, releaser, res); notify_one(mgr, releaser, res);
if (notify_clients) { if (notify_clients) {
notify_all(srv, &clients, client_res); notify_all(mgr, &clients, client_res);
} else if (start) { } else if (start) {
srv->transitions->start(srv, onoff_start_notify); mgr->transitions->start(mgr, onoff_start_notify);
} }
} }
int onoff_release(struct onoff_service *srv, int onoff_release(struct onoff_manager *mgr,
struct onoff_client *cli) struct onoff_client *cli)
{ {
bool stop = false; /* invoke stop transition */ bool stop = false; /* invoke stop transition */
bool notify = false; /* do client notification */ bool notify = false; /* do client notification */
int rv = validate_args(srv, cli); int rv = validate_args(mgr, cli);
if (rv < 0) { if (rv < 0) {
return rv; return rv;
} }
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
if ((srv->flags & ONOFF_SERVICE_HAS_ERROR) != 0) { if ((mgr->flags & ONOFF_HAS_ERROR) != 0) {
rv = -EIO; rv = -EIO;
goto out; goto out;
} }
u32_t state = srv->flags & SERVICE_STATE_MASK; u32_t state = mgr->flags & ST_MASK;
switch (state) { switch (state) {
case SERVICE_STATE_ON: case ST_ON:
/* Stay on if release leaves a client. */ /* Stay on if release leaves a client. */
if (srv->refs > 1U) { if (mgr->refs > 1U) {
notify = true; notify = true;
rv = 1; rv = 1;
break; break;
@ -319,23 +320,23 @@ int onoff_release(struct onoff_service *srv,
* wait * wait
*/ */
if ((k_is_in_isr() || k_is_pre_kernel()) if ((k_is_in_isr() || k_is_pre_kernel())
&& ((srv->flags & ONOFF_SERVICE_STOP_SLEEPS) != 0)) { && ((mgr->flags & ONOFF_STOP_SLEEPS) != 0)) {
rv = -EWOULDBLOCK; rv = -EWOULDBLOCK;
break; break;
} }
stop = true; stop = true;
set_service_state(srv, SERVICE_STATE_TO_OFF); set_service_state(mgr, ST_TO_OFF);
srv->releaser = cli; mgr->releaser = cli;
rv = 2; rv = 2;
break; break;
case SERVICE_STATE_TO_ON: case ST_TO_ON:
rv = -EBUSY; rv = -EBUSY;
break; break;
case SERVICE_STATE_OFF: case ST_OFF:
case SERVICE_STATE_TO_OFF: case ST_TO_OFF:
rv = -EALREADY; rv = -EALREADY;
break; break;
default: default:
@ -344,57 +345,57 @@ int onoff_release(struct onoff_service *srv,
out: out:
if (notify) { if (notify) {
srv->refs -= 1U; mgr->refs -= 1U;
} }
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
if (stop) { if (stop) {
__ASSERT_NO_MSG(srv->transitions->stop != NULL); __ASSERT_NO_MSG(mgr->transitions->stop != NULL);
srv->transitions->stop(srv, onoff_stop_notify); mgr->transitions->stop(mgr, onoff_stop_notify);
} else if (notify) { } else if (notify) {
notify_one(srv, cli, 0); notify_one(mgr, cli, 0);
} }
return rv; return rv;
} }
static void onoff_reset_notify(struct onoff_service *srv, static void onoff_reset_notify(struct onoff_manager *mgr,
int res) int res)
{ {
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
sys_slist_t clients = srv->clients; sys_slist_t clients = mgr->clients;
/* If the reset failed clear the transition flag but otherwise /* If the reset failed clear the transition flag but otherwise
* leave the state unchanged. * leave the state unchanged.
* *
* If it was successful clear the reference count and all * If it was successful clear the reference count and all
* flags except capability flags (sets to SERVICE_STATE_OFF). * flags except capability flags (sets to ST_OFF).
*/ */
if (res < 0) { if (res < 0) {
srv->flags &= ~SERVICE_STATE_TRANSITION; mgr->flags &= ~ST_TRANSITION;
} else { } else {
__ASSERT_NO_MSG(srv->refs == 0U); __ASSERT_NO_MSG(mgr->refs == 0U);
srv->refs = 0U; mgr->refs = 0U;
srv->flags &= SERVICE_CONFIG_FLAGS; mgr->flags &= SERVICE_CONFIG_FLAGS;
} }
sys_slist_init(&srv->clients); sys_slist_init(&mgr->clients);
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
notify_all(srv, &clients, res); notify_all(mgr, &clients, res);
} }
int onoff_service_reset(struct onoff_service *srv, int onoff_reset(struct onoff_manager *mgr,
struct onoff_client *cli) struct onoff_client *cli)
{ {
if (srv->transitions->reset == NULL) { if (mgr->transitions->reset == NULL) {
return -ENOTSUP; return -ENOTSUP;
} }
bool reset = false; bool reset = false;
int rv = validate_args(srv, cli); int rv = validate_args(mgr, cli);
if (rv < 0) { if (rv < 0) {
return rv; return rv;
@ -402,70 +403,70 @@ int onoff_service_reset(struct onoff_service *srv,
/* Reject if in a non-thread context and reset could wait. */ /* Reject if in a non-thread context and reset could wait. */
if ((k_is_in_isr() || k_is_pre_kernel()) if ((k_is_in_isr() || k_is_pre_kernel())
&& ((srv->flags & ONOFF_SERVICE_RESET_SLEEPS) != 0U)) { && ((mgr->flags & ONOFF_RESET_SLEEPS) != 0U)) {
return -EWOULDBLOCK; return -EWOULDBLOCK;
} }
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
if ((srv->flags & ONOFF_SERVICE_HAS_ERROR) == 0) { if ((mgr->flags & ONOFF_HAS_ERROR) == 0) {
rv = -EALREADY; rv = -EALREADY;
goto out; goto out;
} }
if ((srv->flags & SERVICE_STATE_TRANSITION) == 0) { if ((mgr->flags & ST_TRANSITION) == 0) {
reset = true; reset = true;
srv->flags |= SERVICE_STATE_TRANSITION; mgr->flags |= ST_TRANSITION;
} }
out: out:
if (rv >= 0) { if (rv >= 0) {
sys_slist_append(&srv->clients, &cli->node); sys_slist_append(&mgr->clients, &cli->node);
} }
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
if (reset) { if (reset) {
srv->transitions->reset(srv, onoff_reset_notify); mgr->transitions->reset(mgr, onoff_reset_notify);
} }
return rv; return rv;
} }
int onoff_cancel(struct onoff_service *srv, int onoff_cancel(struct onoff_manager *mgr,
struct onoff_client *cli) struct onoff_client *cli)
{ {
int rv = validate_args(srv, cli); int rv = validate_args(mgr, cli);
if (rv < 0) { if (rv < 0) {
return rv; return rv;
} }
rv = -EALREADY; rv = -EALREADY;
k_spinlock_key_t key = k_spin_lock(&srv->lock); k_spinlock_key_t key = k_spin_lock(&mgr->lock);
u32_t state = srv->flags & SERVICE_STATE_MASK; u32_t state = mgr->flags & ST_MASK;
/* Can't remove the last client waiting for the in-progress /* Can't remove the last client waiting for the in-progress
* transition, as there would be nobody to receive the * transition, as there would be nobody to receive the
* completion notification, which might indicate a service * completion notification, which might indicate a service
* error. * error.
*/ */
if (sys_slist_find_and_remove(&srv->clients, &cli->node)) { if (sys_slist_find_and_remove(&mgr->clients, &cli->node)) {
rv = 0; rv = 0;
if (sys_slist_is_empty(&srv->clients) if (sys_slist_is_empty(&mgr->clients)
&& (state != SERVICE_STATE_TO_OFF)) { && (state != ST_TO_OFF)) {
rv = -EWOULDBLOCK; rv = -EWOULDBLOCK;
sys_slist_append(&srv->clients, &cli->node); sys_slist_append(&mgr->clients, &cli->node);
} }
} else if (srv->releaser == cli) { } else if (mgr->releaser == cli) {
/* must be waiting for TO_OFF to complete */ /* must be waiting for TO_OFF to complete */
rv = -EWOULDBLOCK; rv = -EWOULDBLOCK;
} }
k_spin_unlock(&srv->lock, key); k_spin_unlock(&mgr->lock, key);
if (rv == 0) { if (rv == 0) {
notify_one(srv, cli, -ECANCELED); notify_one(mgr, cli, -ECANCELED);
} }
return rv; return rv;

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2019 Peter Bigot Consulting, LLC * Copyright (c) 2019 Peter Bigot Consulting, LLC
* Copyright (c) 2020 Nordic Semiconductor ASA
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -11,7 +12,7 @@ static struct onoff_client spinwait_cli;
static int callback_res; static int callback_res;
static void *callback_ud; static void *callback_ud;
static void callback(struct onoff_service *srv, static void callback(struct onoff_manager *srv,
struct onoff_client *cli, struct onoff_client *cli,
void *ud, void *ud,
int res) int res)
@ -52,8 +53,8 @@ struct transit_state {
const char *tag; const char *tag;
bool async; bool async;
int retval; int retval;
onoff_service_notify_fn notify; onoff_notify_fn notify;
struct onoff_service *srv; struct onoff_manager *srv;
}; };
static void reset_transit_state(struct transit_state *tsp) static void reset_transit_state(struct transit_state *tsp)
@ -64,8 +65,8 @@ static void reset_transit_state(struct transit_state *tsp)
tsp->srv = NULL; tsp->srv = NULL;
} }
static void run_transit(struct onoff_service *srv, static void run_transit(struct onoff_manager *srv,
onoff_service_notify_fn notify, onoff_notify_fn notify,
struct transit_state *tsp) struct transit_state *tsp)
{ {
if (tsp->async) { if (tsp->async) {
@ -99,7 +100,7 @@ static void isr_notify(struct k_timer *timer)
} }
struct isr_call_state { struct isr_call_state {
struct onoff_service *srv; struct onoff_manager *srv;
struct onoff_client *cli; struct onoff_client *cli;
int result; int result;
}; };
@ -124,15 +125,15 @@ static void isr_reset(struct k_timer *timer)
{ {
struct isr_call_state *rsp = k_timer_user_data_get(timer); struct isr_call_state *rsp = k_timer_user_data_get(timer);
rsp->result = onoff_service_reset(rsp->srv, rsp->cli); rsp->result = onoff_reset(rsp->srv, rsp->cli);
k_sem_give(&isr_sync); k_sem_give(&isr_sync);
} }
static struct transit_state start_state = { static struct transit_state start_state = {
.tag = "start", .tag = "start",
}; };
static void start(struct onoff_service *srv, static void start(struct onoff_manager *srv,
onoff_service_notify_fn notify) onoff_notify_fn notify)
{ {
run_transit(srv, notify, &start_state); run_transit(srv, notify, &start_state);
} }
@ -140,8 +141,8 @@ static void start(struct onoff_service *srv,
static struct transit_state stop_state = { static struct transit_state stop_state = {
.tag = "stop", .tag = "stop",
}; };
static void stop(struct onoff_service *srv, static void stop(struct onoff_manager *srv,
onoff_service_notify_fn notify) onoff_notify_fn notify)
{ {
run_transit(srv, notify, &stop_state); run_transit(srv, notify, &stop_state);
} }
@ -149,8 +150,8 @@ static void stop(struct onoff_service *srv,
static struct transit_state reset_state = { static struct transit_state reset_state = {
.tag = "reset", .tag = "reset",
}; };
static void reset(struct onoff_service *srv, static void reset(struct onoff_manager *srv,
onoff_service_notify_fn notify) onoff_notify_fn notify)
{ {
run_transit(srv, notify, &reset_state); run_transit(srv, notify, &reset_state);
} }
@ -166,39 +167,39 @@ static void clear_transit(void)
static void test_service_init_validation(void) static void test_service_init_validation(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
const struct onoff_service_transitions null_transitions = const struct onoff_transitions null_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(NULL, NULL, NULL, 0); ONOFF_TRANSITIONS_INITIALIZER(NULL, NULL, NULL, 0);
const struct onoff_service_transitions start_transitions = const struct onoff_transitions start_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, NULL, NULL, 0); ONOFF_TRANSITIONS_INITIALIZER(start, NULL, NULL, 0);
const struct onoff_service_transitions stop_transitions = const struct onoff_transitions stop_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(NULL, stop, NULL, 0); ONOFF_TRANSITIONS_INITIALIZER(NULL, stop, NULL, 0);
struct onoff_service_transitions start_stop_transitions = struct onoff_transitions start_stop_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0); ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL, 0);
const struct onoff_service_transitions all_transitions = const struct onoff_transitions all_transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset,
ONOFF_SERVICE_START_SLEEPS); ONOFF_START_SLEEPS);
clear_transit(); clear_transit();
rc = onoff_service_init(NULL, &null_transitions); rc = onoff_manager_init(NULL, &null_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null srv %d", rc); "init null srv %d", rc);
rc = onoff_service_init(&srv, &null_transitions); rc = onoff_manager_init(&srv, &null_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null transit %d", rc); "init null transit %d", rc);
rc = onoff_service_init(&srv, &start_transitions); rc = onoff_manager_init(&srv, &start_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null stop %d", rc); "init null stop %d", rc);
rc = onoff_service_init(&srv, &stop_transitions); rc = onoff_manager_init(&srv, &stop_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init null start %d", rc); "init null start %d", rc);
start_stop_transitions.flags |= ONOFF_SERVICE_INTERNAL_BASE; start_stop_transitions.flags |= ONOFF_INTERNAL_BASE;
rc = onoff_service_init(&srv, &start_stop_transitions); rc = onoff_manager_init(&srv, &start_stop_transitions);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"init bad flags %d", rc); "init bad flags %d", rc);
@ -206,7 +207,7 @@ static void test_service_init_validation(void)
zassert_false(sys_slist_is_empty(&srv.clients), zassert_false(sys_slist_is_empty(&srv.clients),
"slist empty"); "slist empty");
rc = onoff_service_init(&srv, &all_transitions); rc = onoff_manager_init(&srv, &all_transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"init good %d", rc); "init good %d", rc);
zassert_equal(srv.transitions->start, start, zassert_equal(srv.transitions->start, start,
@ -215,7 +216,7 @@ static void test_service_init_validation(void)
"init stop mismatch"); "init stop mismatch");
zassert_equal(srv.transitions->reset, reset, zassert_equal(srv.transitions->reset, reset,
"init reset mismatch"); "init reset mismatch");
zassert_equal(srv.flags, ONOFF_SERVICE_START_SLEEPS, zassert_equal(srv.flags, ONOFF_START_SLEEPS,
"init flags mismatch"); "init flags mismatch");
zassert_equal(srv.refs, 0, zassert_equal(srv.refs, 0,
"init refs mismatch"); "init refs mismatch");
@ -262,11 +263,11 @@ static void test_client_init_validation(void)
static void test_validate_args(void) static void test_validate_args(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0); ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL, 0);
clear_transit(); clear_transit();
@ -274,7 +275,7 @@ static void test_validate_args(void)
* release, and reset; test it through the request API. * release, and reset; test it through the request API.
*/ */
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -340,30 +341,30 @@ static void test_validate_args(void)
static void test_reset(void) static void test_reset(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
unsigned int signalled = 0; unsigned int signalled = 0;
int result = 0; int result = 0;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, 0); ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL, 0);
struct onoff_service_transitions transitions_with_reset = struct onoff_transitions transitions_with_reset =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0); ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset, 0);
clear_transit(); clear_transit();
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
rc = onoff_service_reset(&srv, &cli); rc = onoff_reset(&srv, &cli);
zassert_equal(rc, -ENOTSUP, zassert_equal(rc, -ENOTSUP,
"reset: %d", rc); "reset: %d", rc);
rc = onoff_service_init(&srv, &transitions_with_reset); rc = onoff_manager_init(&srv, &transitions_with_reset);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
rc = onoff_service_reset(&srv, NULL); rc = onoff_reset(&srv, NULL);
zassert_equal(rc, -EINVAL, zassert_equal(rc, -EINVAL,
"rst no cli"); "rst no cli");
@ -375,11 +376,11 @@ static void test_reset(void)
"reset req refs: %u", srv.refs); "reset req refs: %u", srv.refs);
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
reset_state.retval = 57; reset_state.retval = 57;
init_notify_sig(&cli, &sig); init_notify_sig(&cli, &sig);
rc = onoff_service_reset(&srv, &cli); rc = onoff_reset(&srv, &cli);
zassert_equal(rc, -EALREADY, zassert_equal(rc, -EALREADY,
"reset: %d", rc); "reset: %d", rc);
@ -390,7 +391,7 @@ static void test_reset(void)
"rel trigger: %d", rc); "rel trigger: %d", rc);
zassert_equal(srv.refs, 0U, zassert_equal(srv.refs, 0U,
"reset req refs: %u", srv.refs); "reset req refs: %u", srv.refs);
zassert_true(onoff_service_has_error(&srv), zassert_true(onoff_has_error(&srv),
"has error"); "has error");
zassert_equal(cli_result(&cli), stop_state.retval, zassert_equal(cli_result(&cli), stop_state.retval,
"cli result"); "cli result");
@ -405,24 +406,24 @@ static void test_reset(void)
reset_state.retval = -59; reset_state.retval = -59;
init_notify_sig(&cli, &sig); init_notify_sig(&cli, &sig);
rc = onoff_service_reset(&srv, &cli); rc = onoff_reset(&srv, &cli);
zassert_equal(rc, 0U, zassert_equal(rc, 0U,
"reset: %d", rc); "reset: %d", rc);
zassert_equal(cli_result(&cli), reset_state.retval, zassert_equal(cli_result(&cli), reset_state.retval,
"reset result"); "reset result");
zassert_equal(srv.refs, 0U, zassert_equal(srv.refs, 0U,
"reset req refs: %u", srv.refs); "reset req refs: %u", srv.refs);
zassert_true(onoff_service_has_error(&srv), zassert_true(onoff_has_error(&srv),
"has error"); "has error");
reset_state.retval = 62; reset_state.retval = 62;
init_notify_sig(&cli, &sig); init_notify_sig(&cli, &sig);
rc = onoff_service_reset(&srv, &cli); rc = onoff_reset(&srv, &cli);
zassert_equal(rc, 0U, zassert_equal(rc, 0U,
"reset: %d", rc); "reset: %d", rc);
zassert_equal(cli_result(&cli), reset_state.retval, zassert_equal(cli_result(&cli), reset_state.retval,
"reset result"); "reset result");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
signalled = 0; signalled = 0;
@ -435,19 +436,19 @@ static void test_reset(void)
zassert_equal(srv.refs, 0U, zassert_equal(srv.refs, 0U,
"reset req refs: %u", srv.refs); "reset req refs: %u", srv.refs);
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
transitions_with_reset.flags |= ONOFF_SERVICE_RESET_SLEEPS; transitions_with_reset.flags |= ONOFF_RESET_SLEEPS;
rc = onoff_service_init(&srv, &transitions_with_reset); rc = onoff_manager_init(&srv, &transitions_with_reset);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
start_state.retval = -23; start_state.retval = -23;
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
init_spinwait(&spinwait_cli); init_spinwait(&spinwait_cli);
rc = onoff_request(&srv, &spinwait_cli); rc = onoff_request(&srv, &spinwait_cli);
zassert_true(onoff_service_has_error(&srv), zassert_true(onoff_has_error(&srv),
"has error"); "has error");
struct isr_call_state isr_state = { struct isr_call_state isr_state = {
@ -474,13 +475,13 @@ static void test_reset(void)
static void test_request(void) static void test_request(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct onoff_service_transitions transitions = struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0); ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset, 0);
clear_transit(); clear_transit();
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -495,7 +496,7 @@ static void test_request(void)
/* Can't reset when no error present. */ /* Can't reset when no error present. */
init_spinwait(&spinwait_cli); init_spinwait(&spinwait_cli);
rc = onoff_service_reset(&srv, &spinwait_cli); rc = onoff_reset(&srv, &spinwait_cli);
zassert_equal(rc, -EALREADY, zassert_equal(rc, -EALREADY,
"reset spin client"); "reset spin client");
@ -517,7 +518,7 @@ static void test_request(void)
"error release"); "error release");
zassert_equal(cli_result(&spinwait_cli), stop_state.retval, zassert_equal(cli_result(&spinwait_cli), stop_state.retval,
"error retval"); "error retval");
zassert_true(onoff_service_has_error(&srv), zassert_true(onoff_has_error(&srv),
"has error"); "has error");
/* Can't request when error present. */ /* Can't request when error present. */
@ -537,10 +538,10 @@ static void test_request(void)
/* Clear the error */ /* Clear the error */
init_notify_sig(&cli, &sig); init_notify_sig(&cli, &sig);
rc = onoff_service_reset(&srv, &cli); rc = onoff_reset(&srv, &cli);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"reset"); "reset");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
/* Error on start */ /* Error on start */
@ -551,20 +552,20 @@ static void test_request(void)
"req with error"); "req with error");
zassert_equal(cli_result(&spinwait_cli), start_state.retval, zassert_equal(cli_result(&spinwait_cli), start_state.retval,
"req with error"); "req with error");
zassert_true(onoff_service_has_error(&srv), zassert_true(onoff_has_error(&srv),
"has error"); "has error");
/* Clear the error */ /* Clear the error */
init_spinwait(&spinwait_cli); init_spinwait(&spinwait_cli);
rc = onoff_service_reset(&srv, &spinwait_cli); rc = onoff_reset(&srv, &spinwait_cli);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"reset"); "reset");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
/* Diagnose a no-wait delayed start */ /* Diagnose a no-wait delayed start */
transitions.flags |= ONOFF_SERVICE_START_SLEEPS; transitions.flags |= ONOFF_START_SLEEPS;
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
start_state.async = true; start_state.async = true;
@ -594,13 +595,13 @@ static void test_request(void)
static void test_sync(void) static void test_sync(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, 0); ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset, 0);
clear_transit(); clear_transit();
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -642,14 +643,15 @@ static void test_sync(void)
static void test_async(void) static void test_async(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct k_poll_signal sig[2]; struct k_poll_signal sig[2];
struct onoff_client cli[2]; struct onoff_client cli[2];
unsigned int signalled = 0; unsigned int signalled = 0;
int result = 0; int result = 0;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, reset, ONOFF_TRANSITIONS_INITIALIZER(start, stop, reset,
ONOFF_SERVICE_START_SLEEPS | ONOFF_SERVICE_STOP_SLEEPS); ONOFF_START_SLEEPS
| ONOFF_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
@ -657,7 +659,7 @@ static void test_async(void)
stop_state.async = true; stop_state.async = true;
stop_state.retval = 17; stop_state.retval = 17;
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -837,19 +839,19 @@ static void test_async(void)
static void test_half_sync(void) static void test_half_sync(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_STOP_SLEEPS); ONOFF_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.retval = 23; start_state.retval = 23;
stop_state.async = true; stop_state.async = true;
stop_state.retval = 17; stop_state.retval = 17;
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -895,12 +897,13 @@ static void test_half_sync(void)
static void test_cancel_request_waits(void) static void test_cancel_request_waits(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_START_SLEEPS | ONOFF_SERVICE_STOP_SLEEPS); ONOFF_START_SLEEPS
| ONOFF_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
@ -908,7 +911,7 @@ static void test_cancel_request_waits(void)
stop_state.async = true; stop_state.async = true;
stop_state.retval = 31; stop_state.retval = 31;
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -936,7 +939,7 @@ static void test_cancel_request_waits(void)
"cancel failed: %d", rc); "cancel failed: %d", rc);
zassert_equal(cli_result(&cli), -ECANCELED, zassert_equal(cli_result(&cli), -ECANCELED,
"cancel notified"); "cancel notified");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
/* Not allowed to cancel the last pending start. /* Not allowed to cancel the last pending start.
@ -944,7 +947,7 @@ static void test_cancel_request_waits(void)
rc = onoff_cancel(&srv, &spinwait_cli); rc = onoff_cancel(&srv, &spinwait_cli);
zassert_equal(rc, -EWOULDBLOCK, zassert_equal(rc, -EWOULDBLOCK,
"last cancel", rc); "last cancel", rc);
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
zassert_equal(cli_result(&spinwait_cli), -EAGAIN, zassert_equal(cli_result(&spinwait_cli), -EAGAIN,
"last request"); "last request");
@ -952,7 +955,7 @@ static void test_cancel_request_waits(void)
notify(&start_state); notify(&start_state);
zassert_equal(cli_result(&spinwait_cli), start_state.retval, zassert_equal(cli_result(&spinwait_cli), start_state.retval,
"last request"); "last request");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
@ -976,7 +979,7 @@ static void test_cancel_request_waits(void)
"restart cancel"); "restart cancel");
zassert_equal(cli_result(&spinwait_cli), -ECANCELED, zassert_equal(cli_result(&spinwait_cli), -ECANCELED,
"restart cancel"); "restart cancel");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
zassert_equal(cli_result(&cli), -EAGAIN, zassert_equal(cli_result(&cli), -EAGAIN,
@ -985,26 +988,26 @@ static void test_cancel_request_waits(void)
notify(&stop_state); notify(&stop_state);
zassert_equal(cli_result(&cli), stop_state.retval, zassert_equal(cli_result(&cli), stop_state.retval,
"released"); "released");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
} }
static void test_cancel_request_ok(void) static void test_cancel_request_ok(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
struct k_poll_signal sig; struct k_poll_signal sig;
struct onoff_client cli; struct onoff_client cli;
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_START_SLEEPS); ONOFF_START_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
start_state.retval = 14; start_state.retval = 14;
stop_state.retval = 31; stop_state.retval = 31;
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -1025,11 +1028,11 @@ static void test_cancel_request_ok(void)
notify(&start_state); notify(&start_state);
zassert_equal(srv.refs, 1, zassert_equal(srv.refs, 1,
"refs"); "refs");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
zassert_equal(cli_result(&cli), start_state.retval, zassert_equal(cli_result(&cli), start_state.retval,
"cancel notified"); "cancel notified");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
/* You can "cancel" an request that isn't active */ /* You can "cancel" an request that isn't active */
@ -1047,14 +1050,15 @@ static void test_cancel_request_ok(void)
static void test_blocked_restart(void) static void test_blocked_restart(void)
{ {
int rc; int rc;
struct onoff_service srv; struct onoff_manager srv;
unsigned int signalled = 0; unsigned int signalled = 0;
int result; int result;
struct k_poll_signal sig[2]; struct k_poll_signal sig[2];
struct onoff_client cli[2]; struct onoff_client cli[2];
const struct onoff_service_transitions transitions = const struct onoff_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL, ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_START_SLEEPS | ONOFF_SERVICE_STOP_SLEEPS); ONOFF_START_SLEEPS
| ONOFF_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.async = true; start_state.async = true;
@ -1062,7 +1066,7 @@ static void test_blocked_restart(void)
stop_state.async = true; stop_state.async = true;
stop_state.retval = 31; stop_state.retval = 31;
rc = onoff_service_init(&srv, &transitions); rc = onoff_manager_init(&srv, &transitions);
zassert_equal(rc, 0, zassert_equal(rc, 0,
"service init"); "service init");
@ -1109,7 +1113,7 @@ static void test_blocked_restart(void)
"isr sync"); "isr sync");
/* Fail-to-restart is not an error */ /* Fail-to-restart is not an error */
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
k_poll_signal_check(&sig[0], &signalled, &result); k_poll_signal_check(&sig[0], &signalled, &result);
@ -1127,21 +1131,17 @@ static void test_blocked_restart(void)
static void test_cancel_release(void) static void test_cancel_release(void)
{ {
static const struct onoff_transitions srv_transitions =
ONOFF_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_STOP_SLEEPS);
struct onoff_manager srv = ONOFF_MANAGER_INITIALIZER(&srv_transitions);
int rc; int rc;
struct onoff_service srv;
const struct onoff_service_transitions transitions =
ONOFF_SERVICE_TRANSITIONS_INITIALIZER(start, stop, NULL,
ONOFF_SERVICE_STOP_SLEEPS);
clear_transit(); clear_transit();
start_state.retval = 16; start_state.retval = 16;
stop_state.async = true; stop_state.async = true;
stop_state.retval = 94; stop_state.retval = 94;
rc = onoff_service_init(&srv, &transitions);
zassert_equal(rc, 0,
"service init");
init_spinwait(&spinwait_cli); init_spinwait(&spinwait_cli);
rc = onoff_request(&srv, &spinwait_cli); rc = onoff_request(&srv, &spinwait_cli);
zassert_true(rc > 0, zassert_true(rc > 0,
@ -1162,13 +1162,13 @@ static void test_cancel_release(void)
rc = onoff_cancel(&srv, &spinwait_cli); rc = onoff_cancel(&srv, &spinwait_cli);
zassert_equal(rc, -EWOULDBLOCK, zassert_equal(rc, -EWOULDBLOCK,
"cancel succeeded"); "cancel succeeded");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
notify(&stop_state); notify(&stop_state);
zassert_equal(cli_result(&spinwait_cli), stop_state.retval, zassert_equal(cli_result(&spinwait_cli), stop_state.retval,
"release pending"); "release pending");
zassert_false(onoff_service_has_error(&srv), zassert_false(onoff_has_error(&srv),
"has error"); "has error");
} }