zephyr: New Kernel Timeout API

New Kernel Timeout API

Opaque timeout type

A new type will be added, k_timeout_t, which represents an abstracted expiration time interpreted by the kernel. This will not have user-visible fields. It is intended to be initialized only via a new macro API.

  1. The data type stored in the timeout will be exposed to the user as an unsigned k_ticks_t typedef. The size of this type (and thus the internal precision of the kernel timeout tracking) will be selectable via a CONFIG_SYS_TIMEOUT_64BIT kconfig. Systems with long uptimes and rapid tick rates will be able to select a 64 timeout type to prevent rollover.

  2. K_TIMEOUT_{MS,US,NS,CYC,TICKS}(val) macros will be added which evaluate to a static initializer for a k_timeout_t representing an expiration in the relevant units from the current tick.

  3. K_NO_WAIT and K_FOREVER will become values of type k_timeout_t, but otherwise retain their current behavior. They will no longer be usable as arithmetic rvalues, even to test them for equality with other timeouts.

  4. K_TIMEOUT_EQ(a, b) will be added as a macro predicate to compare the values of two k_timeout_t objects for equality.

API use of new timeouts

The following public functions, which currently take a numeric delay in milliseconds, will have that argument modified to accept a k_timeout_t instead.

  • k_delayed_work_submit()
  • k_delayed_work_submit_to_queue()
  • k_fifo_get()
  • k_futex_wait()
  • k_lifo_get()
  • k_mbox_data_block_get()
  • k_mbox_get()
  • k_mbox_put()
  • k_mem_pool_alloc()
  • k_mem_slab_alloc()
  • k_msgq_get()
  • k_msgq_put()
  • k_mutex_lock()
  • k_pipe_get()
  • k_pipe_put()
  • k_poll()
  • k_queue_get()
  • k_sem_take()
  • k_sleep()
  • k_stack_pop()
  • k_timer_start()
  • k_thread_create()
  • sys_mutex_lock()
  • sys_sem_take()

New APIs

New APIs are added to permit the inspection of the expiration time of running timeout handles in tick units (to allow sophisticated applications to minimize unit conversion error) and as an absolute/uptime value (to avoid race conditions).

  • k_delayed_work_end_ticks() - end time in ticks of a delayed work item
  • k_delayed_work_remaining_ticks() - time remaining in ticks of a delayed work item
  • k_thread_timeout_end_ticks() - end time in ticks of a sleeping/pending thread
  • k_thread_timeout_remaining_ticks() - time remaining in ticks of a sleeping/pending thread
  • k_timer_remaining_ticks() - time remaining in ticks of a running timer

Also some convenience additions:

  • k_msleep() - Identical to current k_sleep(), takes s32_t count of milliseconds
  • k_uptime_ticks() - Exposes the internal tick counter to users who need it

Legacy Mode

These changes represent source-incompatible changes to public APIs. For apps requiring source compatibility, a “legacy” mode is provided by the CONFIG_SYS_TIMEOUT_LEGACY_API kconfig. In this mode, both k_ticks_t and k_timeout_t become typedefs for a 32 bit integer and are interpreted by all kernels APIs as a count of milliseconds, with the K_NO_WAIT and K_FOREVER tokens having the values they do in current code. Legacy mode is, obviously, not compatible with 64 bit timeouts.

Legacy will be the default in the initial version. It is not expected that all subsystems will work with new timeouts immediately.

Absolute Timeout Expiration

The ability will be added to set a timeout to expire at an absolute time value, in the same space as k_uptime_get(). That is, a timeout specified at an uptime of “1234 ms” will expire on the tick after the internal tick counter passes 1234 ms.

  • K_TIMEOUT_ABSOLUTE_{TICKS,CYC,MS,US,NS}(val) macros will be added which evaluate to a static initializer for a k_timeout_t representing an expiration in the relevant units when the system uptime reaches the specified value.

Static Thread Delay Argument

K_THREAD_DEFINE() has a final argument that currently takes a delay in milliseconds, but cannot use the new timeout mechanism for technical reasons (it has to be precomputed by the compiler and can’t be the result of an inlined C function, even one with constant arguments). Existing code will typically pass K_NO_WAIT and K_FOREVER as values for this argument, and that will have to change as timeouts are non-integral values. Instead, a new K_THREAD_NO_START token will be defined to allow for the behavior currently captured by K_FOREVER. Existing usage of K_NO_WAIT can simply specify zero milliseconds without ambiguity.

Obviously, apps built in legacy mode will continue to work with the existing tokens without change.

Note: Longer term, it would be nicer to evolved the k_thread_create() API to remove the delay parameter (which is very rarely used, and somewhat odd when compared with other OSes) in favor of encouraging apps to use a k_timer to do this themselves. Then “no start” could simply be a flag passed in the options parameter. This would be a good opportunity to remove two of the three parameter words, which again is an odd API and almost entirely unused. But that’s for a different pull request.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (15 by maintainers)

Most upvoted comments

@andyross from my side RFC looks ok and i see no other issues.