doc: kernel: clocks: define "current time"
Scheduling relative timeouts from within timer callbacks (=sys clock ISR context) differs from scheduling relative timeouts from an application context. This change documents and explains the rationale of this distinction. Signed-off-by: Florian Grandel <fgrandel@code-for-humans.de>
This commit is contained in:
parent
ac95e57bbe
commit
5fa5534afc
2 changed files with 34 additions and 4 deletions
|
@ -100,9 +100,23 @@ For example:
|
|||
|
||||
All these values are specified using a :c:struct:`k_timeout_t` value. This is
|
||||
an opaque struct type that must be initialized using one of a family
|
||||
of kernel timeout macros. The most common, :c:macro:`K_MSEC` , defines
|
||||
a time in milliseconds after the current time (strictly: the time at
|
||||
which the kernel receives the timeout value).
|
||||
of kernel timeout macros. The most common, :c:macro:`K_MSEC`, defines
|
||||
a time in milliseconds after the current time.
|
||||
|
||||
What is meant by "current time" for relative timeouts depends on the context:
|
||||
|
||||
* When scheduling a relative timeout from within a timeout callback (e.g. from
|
||||
within the expiry function passed to :c:func:`k_timer_init` or the work handler
|
||||
passed to :c:func:`k_work_init_delayable`), "current time" is the exact time at
|
||||
which the currently firing timeout was originally scheduled even if the "real
|
||||
time" will already have advanced. This is to ensure that timers scheduled from
|
||||
within another timer's callback will always be calculated with a precise offset
|
||||
to the firing timer. It is thereby possible to fire at regular intervals without
|
||||
introducing systematic clock drift over time.
|
||||
|
||||
* When scheduling a timeout from application context, "current time" means the
|
||||
value returned by :c:func:`k_uptime_ticks` at the time at which the kernel
|
||||
receives the timeout value.
|
||||
|
||||
Other options for timeout initialization follow the unit conventions
|
||||
described above: :c:macro:`K_NSEC()`, :c:macro:`K_USEC`, :c:macro:`K_TICKS` and
|
||||
|
|
|
@ -21,7 +21,7 @@ static struct k_spinlock timeout_lock;
|
|||
#define MAX_WAIT (IS_ENABLED(CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE) \
|
||||
? K_TICKS_FOREVER : INT_MAX)
|
||||
|
||||
/* Cycles left to process in the currently-executing sys_clock_announce() */
|
||||
/* Ticks left to process in the currently-executing sys_clock_announce() */
|
||||
static int announce_remaining;
|
||||
|
||||
#if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME)
|
||||
|
@ -61,6 +61,22 @@ static void remove_timeout(struct _timeout *t)
|
|||
|
||||
static int32_t elapsed(void)
|
||||
{
|
||||
/* While sys_clock_announce() is executing, new relative timeouts will be
|
||||
* scheduled relatively to the currently firing timeout's original tick
|
||||
* value (=curr_tick) rather than relative to the current
|
||||
* sys_clock_elapsed().
|
||||
*
|
||||
* This means that timeouts being scheduled from within timeout callbacks
|
||||
* will be scheduled at well-defined offsets from the currently firing
|
||||
* timeout.
|
||||
*
|
||||
* As a side effect, the same will happen if an ISR with higher priority
|
||||
* preempts a timeout callback and schedules a timeout.
|
||||
*
|
||||
* The distinction is implemented by looking at announce_remaining which
|
||||
* will be non-zero while sys_clock_announce() is executing and zero
|
||||
* otherwise.
|
||||
*/
|
||||
return announce_remaining == 0 ? sys_clock_elapsed() : 0U;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue