Skip to content

Commit

Permalink
kernel/timeout: Make timeout arguments an opaque type
Browse files Browse the repository at this point in the history
Add a k_timeout_t type, and use it everywhere that kernel API
functions were accepting a millisecond timeout argument.  Instead of
forcing milliseconds everywhere (which are often not integrally
representable as system ticks), do the conversion to ticks at the
point where the timeout is created.  This avoids an extra unit
conversion in some application code, and allows us to express the
timeout in units other than milliseconds to achieve greater precision.

The existing K_MSEC() et. al. macros now return initializers for a
k_timeout_t.

The K_NO_WAIT and K_FOREVER constants have now become k_timeout_t
values, which means they cannot be operated on as integers.
Applications which have their own APIs that need to inspect these
vs. user-provided timeouts can now use a K_TIMEOUT_EQ() predicate to
test for equality.

Timer drivers, which receive an integer tick count in ther
z_clock_set_timeout() functions, now use the integer-valued
K_TICKS_FOREVER constant instead of K_FOREVER.

For the initial release, to preserve source compatibility, a
CONFIG_LEGACY_TIMEOUT_API kconfig is provided.  When true, the
k_timeout_t will remain a compatible 32 bit value that will work with
any legacy Zephyr application.

Some subsystems present timeout (or timeout-like) values to their own
users as APIs that would re-use the kernel's own constants and
conventions.  These will require some minor design work to adapt to
the new scheme (in most cases just using k_timeout_t directly in their
own API), and they have not been changed in this patch, instead
selecting CONFIG_LEGACY_TIMEOUT_API via kconfig.  These subsystems
include: CAN Bus, the Microbit display driver, I2S, LoRa modem
drivers, the UART Async API, Video hardware drivers, the console
subsystem, and the network buffer abstraction.

k_sleep() now takes a k_timeout_t argument, with a k_msleep() variant
provided that works identically to the original API.

Most of the changes here are just type/configuration management and
documentation, but there are logic changes in mempool, where a loop
that used a timeout numerically has been reworked using a new
z_timeout_end_calc() predicate.  Also in queue.c, a (when POLL was
enabled) a similar loop was needlessly used to try to retry the
k_poll() call after a spurious failure.  But k_poll() does not fail
spuriously, so the loop was removed.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
  • Loading branch information
Andy Ross authored and nashif committed Mar 31, 2020
1 parent 32bb239 commit 7832738
Show file tree
Hide file tree
Showing 66 changed files with 440 additions and 277 deletions.
2 changes: 1 addition & 1 deletion boards/arm/qemu_cortex_m0/nrf_timer_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
ARG_UNUSED(idle);

#ifdef CONFIG_TICKLESS_KERNEL
ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
1 change: 1 addition & 0 deletions drivers/can/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
menuconfig CAN
bool "CAN Drivers"
select LEGACY_TIMEOUT_API
help
Enable CAN Driver Configuration

Expand Down
1 change: 1 addition & 0 deletions drivers/display/Kconfig.microbit
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ config MICROBIT_DISPLAY
depends on BOARD_BBC_MICROBIT
depends on PRINTK
depends on GPIO
select LEGACY_TIMEOUT_API
help
Enable this to be able to display images and text on the 5x5
LED matrix display on the BBC micro:bit.
Expand Down
1 change: 1 addition & 0 deletions drivers/i2s/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
menuconfig I2S
bool "I2S bus drivers"
select LEGACY_TIMEOUT_API
help
Enable support for the I2S (Inter-IC Sound) hardware bus.

Expand Down
1 change: 1 addition & 0 deletions drivers/lora/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
menuconfig LORA
bool "LoRa support"
depends on NEWLIB_LIBC
select LEGACY_TIMEOUT_API
help
Include LoRa drivers in the system configuration.

Expand Down
1 change: 1 addition & 0 deletions drivers/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ config SERIAL_SUPPORT_INTERRUPT
config UART_ASYNC_API
bool "Enable new asynchronous UART API [EXPERIMENTAL]"
depends on SERIAL_SUPPORT_ASYNC
select LEGACY_TIMEOUT_API
help
This option enables new asynchronous UART API.

Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/apic_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ void z_clock_set_timeout(s32_t n, bool idle)

if (n < 1) {
full_ticks = 0;
} else if ((n == K_FOREVER) || (n > MAX_TICKS)) {
} else if ((n == K_TICKS_FOREVER) || (n > MAX_TICKS)) {
full_ticks = MAX_TICKS - 1;
} else {
full_ticks = n - 1;
Expand Down
5 changes: 3 additions & 2 deletions drivers/timer/arcv2_timer0.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
* However for single core using 32-bits arc timer, idle cannot
* be ignored, as 32-bits timer will overflow in a not-long time.
*/
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && ticks == K_FOREVER) {
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && ticks == K_TICKS_FOREVER) {
timer0_control_register_set(0);
timer0_count_register_set(0);
timer0_limit_register_set(0);
Expand All @@ -268,7 +268,8 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
arch_irq_unlock(key);
#endif
#else
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle && ticks == K_FOREVER) {
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle
&& ticks == K_TICKS_FOREVER) {
timer0_control_register_set(0);
timer0_count_register_set(0);
timer0_limit_register_set(0);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/arm_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
return;
}

ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/cavs_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
ARG_UNUSED(idle);

#ifdef CONFIG_TICKLESS_KERNEL
ticks = ticks == K_FOREVER ? MAX_TICKS : ticks;
ticks = ticks == K_TICKS_FOREVER ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/cc13x2_cc26x2_rtc_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)

#ifdef CONFIG_TICKLESS_KERNEL

ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t) MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
5 changes: 3 additions & 2 deletions drivers/timer/cortex_m_systick.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
* the counter. (Note: we can assume if idle==true that
* interrupts are already disabled)
*/
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle && ticks == K_FOREVER) {
if (IS_ENABLED(CONFIG_TICKLESS_IDLE) && idle
&& ticks == K_TICKS_FOREVER) {
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
last_load = TIMER_STOPPED;
return;
Expand All @@ -181,7 +182,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
#if defined(CONFIG_TICKLESS_KERNEL)
u32_t delay;

ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
4 changes: 2 additions & 2 deletions drivers/timer/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
ARG_UNUSED(idle);

#if defined(CONFIG_TICKLESS_KERNEL) && !defined(CONFIG_QEMU_TICKLESS_WORKAROUND)
if (ticks == K_FOREVER && idle) {
if (ticks == K_TICKS_FOREVER && idle) {
GENERAL_CONF_REG &= ~GCONF_ENABLE;
return;
}

ticks = ticks == K_FOREVER ? max_ticks : ticks;
ticks = ticks == K_TICKS_FOREVER ? max_ticks : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)max_ticks), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/legacy_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
if (idle) {
z_timer_idle_enter(ticks);
} else {
z_set_time(ticks == K_FOREVER ? 0 : ticks);
z_set_time(ticks == K_TICKS_FOREVER ? 0 : ticks);
}
#endif
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/timer/loapic_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ void z_timer_idle_enter(s32_t ticks /* system ticks */
)
{
#ifdef CONFIG_TICKLESS_KERNEL
if (ticks != K_FOREVER) {
if (ticks != K_TICKS_FOREVER) {
/* Need to reprogram only if current program is smaller */
if (ticks > programmed_full_ticks) {
z_set_time(ticks);
Expand All @@ -417,7 +417,7 @@ void z_timer_idle_enter(s32_t ticks /* system ticks */

cycles = current_count_register_get();

if ((ticks == K_FOREVER) || (ticks > max_system_ticks)) {
if ((ticks == K_TICKS_FOREVER) || (ticks > max_system_ticks)) {
/*
* The number of cycles until the timer must fire next might not fit
* in the 32-bit counter register. To work around this, program
Expand Down
4 changes: 2 additions & 2 deletions drivers/timer/mchp_xec_rtos_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ void z_clock_set_timeout(s32_t n, bool idle)
u32_t full_cycles; /* full_ticks represented as cycles */
u32_t partial_cycles; /* number of cycles to first tick boundary */

if (idle && (n == K_FOREVER)) {
if (idle && (n == K_TICKS_FOREVER)) {
/*
* We are not in a locked section. Are writes to two
* global objects safe from pre-emption?
Expand All @@ -147,7 +147,7 @@ void z_clock_set_timeout(s32_t n, bool idle)

if (n < 1) {
full_ticks = 0;
} else if ((n == K_FOREVER) || (n > MAX_TICKS)) {
} else if ((n == K_TICKS_FOREVER) || (n > MAX_TICKS)) {
full_ticks = MAX_TICKS - 1;
} else {
full_ticks = n - 1;
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/native_posix_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
/* Note that we treat INT_MAX literally as anyhow the maximum amount of
* ticks we can report with z_clock_announce() is INT_MAX
*/
if (ticks == K_FOREVER) {
if (ticks == K_TICKS_FOREVER) {
silent_ticks = INT64_MAX;
} else if (ticks > 0) {
silent_ticks = ticks - 1;
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/nrf_rtc_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
ARG_UNUSED(idle);

#ifdef CONFIG_TICKLESS_KERNEL
ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks;
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/riscv_machine_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
return;
}

ticks = ticks == K_FOREVER ? MAX_TICKS : ticks;
ticks = ticks == K_TICKS_FOREVER ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/xlnx_psttc_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
cycles = read_count();

/* Calculate timeout counter value */
if (ticks == K_FOREVER) {
if (ticks == K_TICKS_FOREVER) {
next_cycles = cycles + CYCLES_NEXT_MAX;
} else {
next_cycles = cycles + ((u32_t)ticks * CYCLES_PER_TICK);
Expand Down
2 changes: 1 addition & 1 deletion drivers/timer/xtensa_sys_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void z_clock_set_timeout(s32_t ticks, bool idle)
ARG_UNUSED(idle);

#if defined(CONFIG_TICKLESS_KERNEL) && !defined(CONFIG_QEMU_TICKLESS_WORKAROUND)
ticks = ticks == K_FOREVER ? MAX_TICKS : ticks;
ticks = ticks == K_TICKS_FOREVER ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0);

k_spinlock_key_t key = k_spin_lock(&lock);
Expand Down
1 change: 1 addition & 0 deletions drivers/video/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#
menuconfig VIDEO
bool "VIDEO hardware support"
select LEGACY_TIMEOUT_API
help
Enable support for the VIDEO.

Expand Down
2 changes: 1 addition & 1 deletion include/drivers/timer/system_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ extern int z_clock_device_ctrl(struct device *device, u32_t ctrl_command,
* treated identically: it simply indicates the kernel would like the
* next tick announcement as soon as possible.
*
* Note that ticks can also be passed the special value K_FOREVER,
* Note that ticks can also be passed the special value K_TICKS_FOREVER,
* indicating that no future timer interrupts are expected or required
* and that the system is permitted to enter an indefinite sleep even
* if this could cause rollover of the internal counter (i.e. the
Expand Down
Loading

0 comments on commit 7832738

Please sign in to comment.