kernel: sched: Optimize sleeping function

Accessing system timer registers can be costly and it shall be avoided
if possible. When thread is waken up in z_tick_sleep it may be because
timeout expired or because thread was waken up before sleeping period
passed.

Add function to detect if timeout is aborted (before it was expired).
Use it in the sleep function and avoid reading system ticks if timeout
was not aborted.

Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruściński 2025-04-04 09:32:15 +02:00 committed by Benjamin Cabé
commit 6d35969a55
3 changed files with 22 additions and 0 deletions

View file

@ -22,6 +22,9 @@ extern "C" {
#ifdef CONFIG_SYS_CLOCK_EXISTS
/* Value written to dticks when timeout is aborted. */
#define TIMEOUT_DTICKS_ABORTED (IS_ENABLED(CONFIG_TIMEOUT_64BIT) ? INT64_MIN : INT32_MIN)
static inline void z_init_timeout(struct _timeout *to)
{
sys_dnode_init(&to->node);
@ -37,6 +40,12 @@ static inline bool z_is_inactive_timeout(const struct _timeout *to)
return !sys_dnode_is_linked(&to->node);
}
static inline bool z_is_aborted_timeout(const struct _timeout *to)
{
/* When timeout is aborted then dticks is set to special value. */
return to->dticks == TIMEOUT_DTICKS_ABORTED;
}
static inline void z_init_thread_timeout(struct _thread_base *thread_base)
{
z_init_timeout(&thread_base->timeout);
@ -54,6 +63,12 @@ static inline void z_abort_thread_timeout(struct k_thread *thread)
z_abort_timeout(&thread->base.timeout);
}
static inline bool z_is_aborted_thread_timeout(struct k_thread *thread)
{
return z_is_aborted_timeout(&thread->base.timeout);
}
int32_t z_get_next_timeout_expiry(void);
k_ticks_t z_timeout_remaining(const struct _timeout *timeout);
@ -63,7 +78,9 @@ k_ticks_t z_timeout_remaining(const struct _timeout *timeout);
/* Stubs when !CONFIG_SYS_CLOCK_EXISTS */
#define z_init_thread_timeout(thread_base) do {} while (false)
#define z_abort_thread_timeout(to) do {} while (false)
#define z_is_aborted_thread_timeout(to) false
#define z_is_inactive_timeout(to) 1
#define z_is_aborted_timeout(to) false
#define z_get_next_timeout_expiry() ((int32_t) K_TICKS_FOREVER)
#define z_set_timeout_expiry(ticks, is_idle) do {} while (false)

View file

@ -1108,6 +1108,10 @@ static int32_t z_tick_sleep(k_timeout_t timeout)
(void)z_swap(&_sched_spinlock, key);
if (!z_is_aborted_thread_timeout(_current)) {
return 0;
}
/* We require a 32 bit unsigned subtraction to care a wraparound */
uint32_t left_ticks = expected_wakeup_ticks - sys_clock_tick_get_32();

View file

@ -162,6 +162,7 @@ int z_abort_timeout(struct _timeout *to)
bool is_first = (to == first());
remove_timeout(to);
to->dticks = TIMEOUT_DTICKS_ABORTED;
ret = 0;
if (is_first) {
sys_clock_set_timeout(next_timeout(elapsed()), false);