zephyr/lib/os/notify.c
Peter Bigot fadd98aad2 sys: add generic asynchronous notification infrastructure
k_poll() for a signal is often desired for notification of completion
of asynchronous operations, but there are APIs where it may be
necessary to invoke "asynchronous" operations from contexts where
sleep is disallowed, or before the kernel has been initialized.
Extract the general notification solution from the on-off service into
a utility that can be used for other APIs.

Also move documentation out to a resource management section.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
2020-04-06 16:41:41 +02:00

85 lines
1.7 KiB
C

/*
* Copyright (c) 2019 Peter Bigot Consulting, LLC
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <sys/notify.h>
int sys_notify_validate(struct sys_notify *notify)
{
int rv = 0;
if (notify == NULL) {
return -EINVAL;
}
/* Validate configuration based on mode */
switch (sys_notify_get_method(notify)) {
case SYS_NOTIFY_METHOD_SPINWAIT:
break;
case SYS_NOTIFY_METHOD_CALLBACK:
if (notify->method.callback == NULL) {
rv = -EINVAL;
}
break;
#ifdef CONFIG_POLL
case SYS_NOTIFY_METHOD_SIGNAL:
if (notify->method.signal == NULL) {
rv = -EINVAL;
}
break;
#endif /* CONFIG_POLL */
default:
rv = -EINVAL;
break;
}
/* Clear the result here instead of in all callers. */
if (rv == 0) {
notify->result = 0;
}
return rv;
}
sys_notify_generic_callback sys_notify_finalize(struct sys_notify *notify,
int res)
{
struct k_poll_signal *sig = NULL;
sys_notify_generic_callback rv = 0;
u32_t method = sys_notify_get_method(notify);
/* Store the result and capture secondary notification
* information.
*/
notify->result = res;
switch (method) {
case SYS_NOTIFY_METHOD_SPINWAIT:
break;
case SYS_NOTIFY_METHOD_CALLBACK:
rv = notify->method.callback;
break;
case SYS_NOTIFY_METHOD_SIGNAL:
sig = notify->method.signal;
break;
default:
__ASSERT_NO_MSG(false);
}
/* Mark completion by clearing the flags field to the
* completed state, releasing any spin-waiters, then complete
* secondary notification.
*/
compiler_barrier();
notify->flags = SYS_NOTIFY_METHOD_COMPLETED;
if (IS_ENABLED(CONFIG_POLL) && (sig != NULL)) {
k_poll_signal_raise(sig, res);
}
return rv;
}