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>
133 lines
4.8 KiB
C
133 lines
4.8 KiB
C
/*
|
|
* Copyright (c) 2015 Wind River Systems, Inc.
|
|
* Copyright (c) 2019 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Timer driver API
|
|
*
|
|
*
|
|
* Declare API implemented by system timer driver and used by kernel components.
|
|
*/
|
|
|
|
#ifndef ZEPHYR_INCLUDE_DRIVERS_SYSTEM_TIMER_H_
|
|
#define ZEPHYR_INCLUDE_DRIVERS_SYSTEM_TIMER_H_
|
|
|
|
#include <stdbool.h>
|
|
#include <device.h>
|
|
#include <stdbool.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Initialize system clock driver
|
|
*
|
|
* The system clock is a Zephyr device created globally. This is its
|
|
* initialization callback. It is a weak symbol that will be
|
|
* implemented as a noop if undefined in the clock driver.
|
|
*/
|
|
extern int z_clock_driver_init(struct device *device);
|
|
|
|
/**
|
|
* @brief Initialize system clock driver
|
|
*
|
|
* The system clock is a Zephyr device created globally. This is its
|
|
* device control callback, used in a few devices for power
|
|
* management. It is a weak symbol that will be implemented as a noop
|
|
* if undefined in the clock driver.
|
|
*/
|
|
extern int z_clock_device_ctrl(struct device *device, u32_t ctrl_command,
|
|
void *context, device_pm_cb cb, void *arg);
|
|
|
|
/**
|
|
* @brief Set system clock timeout
|
|
*
|
|
* Informs the system clock driver that the next needed call to
|
|
* z_clock_announce() will not be until the specified number of ticks
|
|
* from the the current time have elapsed. Note that spurious calls
|
|
* to z_clock_announce() are allowed (i.e. it's legal to announce
|
|
* every tick and implement this function as a noop), the requirement
|
|
* is that one tick announcement should occur within one tick BEFORE
|
|
* the specified expiration (that is, passing ticks==1 means "announce
|
|
* the next tick", this convention was chosen to match legacy usage).
|
|
* Similarly a ticks value of zero (or even negative) is legal and
|
|
* 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_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
|
|
* system uptime counter is allowed to be wrong, see
|
|
* k_enable_sys_clock_always_on()).
|
|
*
|
|
* Note also that it is conventional for the kernel to pass INT_MAX
|
|
* for ticks if it wants to preserve the uptime tick count but doesn't
|
|
* have a specific event to await. The intent here is that the driver
|
|
* will schedule any needed timeout as far into the future as
|
|
* possible. For the specific case of INT_MAX, the next call to
|
|
* z_clock_announce() may occur at any point in the future, not just
|
|
* at INT_MAX ticks. But the correspondence between the announced
|
|
* ticks and real-world time must be correct.
|
|
*
|
|
* A final note about SMP: note that the call to z_clock_set_timeout()
|
|
* is made on any CPU, and reflects the next timeout desired globally.
|
|
* The resulting calls(s) to z_clock_announce() must be properly
|
|
* serialized by the driver such that a given tick is announced
|
|
* exactly once across the system. The kernel does not (cannot,
|
|
* really) attempt to serialize things by "assigning" timeouts to
|
|
* specific CPUs.
|
|
*
|
|
* @param ticks Timeout in tick units
|
|
* @param idle Hint to the driver that the system is about to enter
|
|
* the idle state immediately after setting the timeout
|
|
*/
|
|
extern void z_clock_set_timeout(s32_t ticks, bool idle);
|
|
|
|
/**
|
|
* @brief Timer idle exit notification
|
|
*
|
|
* This notifies the timer driver that the system is exiting the idle
|
|
* and allows it to do whatever bookkeeping is needed to restore timer
|
|
* operation and compute elapsed ticks.
|
|
*
|
|
* @note Legacy timer drivers also use this opportunity to call back
|
|
* into z_clock_announce() to notify the kernel of expired ticks.
|
|
* This is allowed for compatibility, but not recommended. The kernel
|
|
* will figure that out on its own.
|
|
*/
|
|
extern void z_clock_idle_exit(void);
|
|
|
|
/**
|
|
* @brief Announce time progress to the kernel
|
|
*
|
|
* Informs the kernel that the specified number of ticks have elapsed
|
|
* since the last call to z_clock_announce() (or system startup for
|
|
* the first call). The timer driver is expected to delivery these
|
|
* announcements as close as practical (subject to hardware and
|
|
* latency limitations) to tick boundaries.
|
|
*
|
|
* @param ticks Elapsed time, in ticks
|
|
*/
|
|
extern void z_clock_announce(s32_t ticks);
|
|
|
|
/**
|
|
* @brief Ticks elapsed since last z_clock_announce() call
|
|
*
|
|
* Queries the clock driver for the current time elapsed since the
|
|
* last call to z_clock_announce() was made. The kernel will call
|
|
* this with appropriate locking, the driver needs only provide an
|
|
* instantaneous answer.
|
|
*/
|
|
extern u32_t z_clock_elapsed(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* ZEPHYR_INCLUDE_DRIVERS_SYSTEM_TIMER_H_ */
|