kernel: Clamp k_sleep() return value on overflow

k_sleep() returns a 32 bit count of milliseconds, as that was its
historical API.  But it now accepts a potentially 64 bit tick count as
an argument, leading to situations where an early wakeup will produce
sleep times that aren't representable.  Clamp this instead of
truncating to an arbitrary value.

Naive code will likely do the right thing with the large return (just
sleeping an extra round), and sophisticated apps can detect INT_MAX to
enable more elaborate retry logic.

(Also fixes a somewhat unfortunate puncutation error in the docs that
implied that it returns zero on early wakeup!)

Fixes: #84669

Signed-off-by: Andy Ross <andyross@google.com>
This commit is contained in:
Andy Ross 2025-02-28 08:55:33 -08:00 committed by Alberto Escolar
commit 8b4ed6655a
2 changed files with 9 additions and 8 deletions

View file

@ -545,9 +545,10 @@ __syscall int k_thread_join(struct k_thread *thread, k_timeout_t timeout);
*
* @param timeout Desired duration of sleep.
*
* @return Zero if the requested time has elapsed or if the thread was woken up
* by the \ref k_wakeup call, the time left to sleep rounded up to the nearest
* millisecond.
* @return Zero if the requested time has elapsed or the time left to
* sleep rounded up to the nearest millisecond (e.g. if the thread was
* awoken by the \ref k_wakeup call). Will be clamped to INT_MAX in
* the case where the remaining time is unrepresentable in an int32_t.
*/
__syscall int32_t k_sleep(k_timeout_t timeout);

View file

@ -1123,12 +1123,12 @@ int32_t z_impl_k_sleep(k_timeout_t timeout)
ticks = z_tick_sleep(ticks);
int32_t ret = K_TIMEOUT_EQ(timeout, K_FOREVER) ? K_TICKS_FOREVER :
k_ticks_to_ms_ceil64(ticks);
/* k_sleep() still returns 32 bit milliseconds for compatibility */
int64_t ms = K_TIMEOUT_EQ(timeout, K_FOREVER) ? K_TICKS_FOREVER :
CLAMP(k_ticks_to_ms_ceil64(ticks), 0, INT_MAX);
SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ret);
return ret;
SYS_PORT_TRACING_FUNC_EXIT(k_thread, sleep, timeout, ms);
return (int32_t) ms;
}
#ifdef CONFIG_USERSPACE