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,
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::
:local:
:depth: 2
.. _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,
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
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
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.
sleep must be flagged in the configuration to support detecting unsafe
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
@ -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
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
shut out, and the manager 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
requests or releases until the manager is reset. Pending requests are
notified (and cancelled) when errors are discovered.
Transition operation completion notifications are provided through any
of the following mechanisms:
Transition operation completion notifications are provided through the
standard :ref:`async_notification`, supporting these methods:
* Signal: A pointer to a :c:type:`struct k_poll_signal` is provided, and
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
completion is signalled.
.. doxygengroup:: resource_mgmt_apis
.. doxygengroup:: resource_mgmt_onoff_apis
:project: Zephyr

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2019 Peter Bigot Consulting, LLC
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -16,7 +17,7 @@ extern "C" {
#endif
/**
* @defgroup resource_mgmt_apis Resource Management APIs
* @defgroup resource_mgmt_onoff_apis On-Off Service APIs
* @ingroup kernel_apis
* @{
*/
@ -24,57 +25,63 @@ extern "C" {
/**
* @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
* may cause the calling thread to wait. This blocks attempts
* 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
* stop transition function.
* As with @ref ONOFF_START_SLEEPS but describing the stop
* 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
* reset transition function.
* As with @ref ONOFF_START_SLEEPS but describing the reset
* transition function.
*/
ONOFF_SERVICE_RESET_SLEEPS = BIT(2),
ONOFF_RESET_SLEEPS = BIT(2),
/* Internal use. */
ONOFF_SERVICE_HAS_ERROR = BIT(3),
ONOFF_HAS_ERROR = BIT(3),
/* 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 */
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.
*
* 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.
*
* @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
* 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_notify_fn)(struct onoff_service *srv,
typedef void (*onoff_notify_fn)(struct onoff_manager *mgr,
int res);
/**
@ -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 reset function may be called only when
* onoff_service_has_error() returns true.
* The reset function may be called only when onoff_has_error()
* 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
* 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
* function returns.
*/
typedef void (*onoff_service_transition_fn)(struct onoff_service *srv,
onoff_service_notify_fn notify);
typedef void (*onoff_transition_fn)(struct onoff_manager *mgr,
onoff_notify_fn notify);
/** @brief On-off service transition functions. */
struct onoff_service_transitions {
struct onoff_transitions {
/* 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. */
onoff_service_transition_fn stop;
onoff_transition_fn stop;
/* Function to force the service state to reset, where supported. */
onoff_service_transition_fn reset;
onoff_transition_fn reset;
/* Flags identifying transition function capabilities. */
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
* 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.
* onoff_manager_init(), when the service provider is initialized. In
* case of error it may be reset through the onoff_reset() API.
*/
struct onoff_service {
struct onoff_manager {
/* List of clients waiting for completion of reset or
* transition to on.
*/
sys_slist_t clients;
/* Transition functions. */
const struct onoff_service_transitions *transitions;
const struct onoff_transitions *transitions;
/* Mutex protection for flags, clients, releaser, and refs. */
struct k_spinlock lock;
@ -149,7 +155,7 @@ struct onoff_service {
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.
*
@ -158,21 +164,30 @@ struct onoff_service {
* @param _reset a function used to clear errors and force the service to an off
* 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, \
.stop = _stop, \
.reset = _reset, \
.flags = _flags, \
}
#define ONOFF_SERVICE_TRANSITIONS_INITIALIZER(_start, _stop, _reset, _flags) \
__DEPRECATED_MACRO \
ONOFF_TRANSISTIONS_INITIALIZER(_start, _stop, _reset, _flags)
/** @internal */
#define ONOFF_SERVICE_INITIALIZER(_transitions) { \
#define ONOFF_MANAGER_INITIALIZER(_transitions) { \
.transitions = _transitions, \
.flags = (_transitions)->flags, \
}
#define ONOFF_SERVICE_INITIALIZER(_transitions) \
__DEPRECATED_MACRO \
ONOFF_MANAGER_INITIALIZER(_transitions)
/**
* @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.
*
* @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
* persistent as it is used by the service.
@ -190,8 +205,8 @@ struct onoff_service {
* @retval 0 on success
* @retval -EINVAL if start, stop, or flags are invalid
*/
int onoff_service_init(struct onoff_service *srv,
const struct onoff_service_transitions *transitions);
int onoff_manager_init(struct onoff_manager *mgr,
const struct onoff_transitions *transitions);
/* Forward declaration */
struct onoff_client;
@ -204,7 +219,7 @@ struct onoff_client;
* pre-kernel, ISR, or cooperative or pre-emptible threads.
* 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
* initiated the operation.
@ -216,7 +231,7 @@ struct onoff_client;
* service-specific, but the value shall be non-negative if the
* 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,
void *user_data,
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
* 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).
* client concurrent with release of the owned sys_notify structure.
*
* After control has reverted to the client the state object must be
* 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
* 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
* 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
* make the calling thread sleep.
*/
int onoff_request(struct onoff_service *srv,
int onoff_request(struct onoff_manager *mgr,
struct onoff_client *cli);
/**
@ -415,7 +426,7 @@ int onoff_request(struct onoff_service *srv,
* actual release fails. Always check the operation completion
* 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
* instructions on how to notify the client when release completes.
@ -431,7 +442,7 @@ int onoff_request(struct onoff_service *srv,
* to off
* @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);
/**
@ -439,13 +450,17 @@ int onoff_release(struct onoff_service *srv,
*
* This function can be used to determine whether the service has
* 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.
*/
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.
*
* 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
* 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
* 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.
*
* @param srv the service to be reset.
* @param mgr the manager to be reset.
*
* @param cli pointer to client state, including instructions on how
* to notify the client when reset completes. Behavior is undefined
@ -481,11 +493,11 @@ static inline bool onoff_service_has_error(const struct onoff_service *srv)
* operation.
*
* @retval 0 on success
* @retval -ENOTSUP if reset is not supported
* @retval -EINVAL if the parameters are invalid, or if the service
* @retval -EALREADY if the service does not have a recorded error
* @retval -ENOTSUP if reset is not supported by the service.
* @retval -EINVAL if the parameters are invalid.
* @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);
/**
@ -511,7 +523,7 @@ int onoff_service_reset(struct onoff_service *srv,
* If the cancellation fails the service retains control of the client
* 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
* 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
* already completed.
*/
int onoff_cancel(struct onoff_service *srv,
int onoff_cancel(struct onoff_manager *mgr,
struct onoff_client *cli);
/** @} */

View file

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

View file

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