blob: 6a4eff45a9d2837cd02611c3692d07252c9091e7 [file]
/*
* Copyright (c) 2015 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_KERNEL_INCLUDE_TIMEOUT_Q_H_
#define ZEPHYR_KERNEL_INCLUDE_TIMEOUT_Q_H_
/**
* @file
* @brief timeout queue for threads on kernel objects
*/
#include <zephyr/kernel.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_SYS_CLOCK_EXISTS
/*
* Per-node timeout helpers (Kconfig choice TIMEOUT_BACKEND).
*
* z_init_timeout() and z_is_inactive_timeout() operate on a single
* struct _timeout and are needed tree-wide (timer.c, work.c, poll.c, ...),
* so they live here and depend only on the chosen backend's struct _timeout
* fields (see kernel_structs.h). The queue itself (the z_timeout_q_*()
* operations and the backend instance) is private to kernel/timeout.c, which
* includes the matching backend implementation header directly.
*/
#if defined(CONFIG_TIMEOUT_BACKEND_MINHEAP)
static inline void z_init_timeout(struct _timeout *to)
{
to->heap_handle.idx = 0U;
to->abs_ticks = 0;
}
static inline bool z_is_inactive_timeout(const struct _timeout *to)
{
return to->heap_handle.idx == 0U;
}
#elif defined(CONFIG_TIMEOUT_BACKEND_WHEEL)
static inline void z_init_timeout(struct _timeout *to)
{
sys_dnode_init(&to->node);
to->flags = 0U;
to->dticks = 0;
}
static inline bool z_is_inactive_timeout(const struct _timeout *to)
{
return !sys_dnode_is_linked(&to->node);
}
#else /* CONFIG_TIMEOUT_BACKEND_DLIST or _BUCKET */
static inline void z_init_timeout(struct _timeout *to)
{
sys_dnode_init(&to->node);
to->dticks = 0;
}
static inline bool z_is_inactive_timeout(const struct _timeout *to)
{
return !sys_dnode_is_linked(&to->node);
}
#endif
/* Adds the timeout to the queue.
*
* @return Absolute tick value when timeout will expire.
*/
k_ticks_t z_add_timeout(struct _timeout *to, _timeout_func_t fn, k_timeout_t timeout);
/* Attempt to abort a timeout. Safe to use for callers that need to be
* certain the handler is not in flight (e.g. when about to free the
* timeout's storage), as long as the caller is prepared to drop any
* locks the handler may need and retry.
*
* Returns:
* 0 — the timeout was active and has been removed from the queue.
* -EINVAL — the timeout was not active (never linked, already done, or
* a same-CPU IRQ aborted while the handler was paused on this
* CPU; in that case the in-flight slot is marked superseded
* so handlers that need to bail may check via
* z_timeout_inflight_superseded()).
* -EAGAIN — the handler is currently in flight on another CPU. The caller
* must drop any lock that the handler may need and retry. A short
* arch_spin_relax() has already been done before this return.
*
* On -EAGAIN, the only correct response is to drop outer locks and call again.
* After a non-EAGAIN return, the handler is guaranteed not to be in flight.
*/
int z_try_abort_timeout(struct _timeout *to);
/* True if @to is the currently in-flight timeout and a same-CPU aborter
* has marked the slot as superseded. Handlers with non-idempotent side
* effects (e.g. k_timer's expiry_fn) should call this at entry, after
* taking their own lock, and bail if it returns true.
*/
bool z_timeout_inflight_superseded(const struct _timeout *to);
static inline void z_init_thread_timeout(struct _thread_base *thread_base)
{
z_init_timeout(&thread_base->timeout);
}
extern void z_thread_timeout(struct _timeout *timeout);
static inline k_ticks_t z_add_thread_timeout(struct k_thread *thread, k_timeout_t ticks)
{
return z_add_timeout(&thread->base.timeout, z_thread_timeout, ticks);
}
static inline int z_try_abort_thread_timeout(struct k_thread *thread)
{
return z_try_abort_timeout(&thread->base.timeout);
}
uint32_t z_get_next_timeout_expiry(void);
k_ticks_t z_timeout_remaining(const struct _timeout *timeout);
#else
/* Stubs when !CONFIG_SYS_CLOCK_EXISTS */
#define z_init_thread_timeout(thread_base) do {} while (false)
#define z_try_abort_thread_timeout(to) 0
#define z_is_inactive_timeout(to) 1
#define z_get_next_timeout_expiry() ((uint32_t) K_TICKS_FOREVER)
#define z_set_timeout_expiry(ticks, is_idle) do {} while (false)
static inline k_ticks_t z_add_thread_timeout(struct k_thread *thread, k_timeout_t ticks)
{
ARG_UNUSED(thread);
ARG_UNUSED(ticks);
return 0;
}
#endif /* CONFIG_SYS_CLOCK_EXISTS */
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_KERNEL_INCLUDE_TIMEOUT_Q_H_ */