kernel/timeout: fix handling expired timeouts in reverve queuing order
Queuing in the timeout_q of timeouts expiring on the same tick queue them in reverse order: as soon as the new timeout finds a timeout expiring on the same tick or later, it get prepended to that timeout: this allows exiting the traversal of the timeout as soon as possible, which is done with interrupts locked, thus reducing interrupt latency. However, this has the side-effect of handling the timeouts expiring on the same tick in the reverse order that they are queued. For example: thread_c, prio 4: uint32_t uptime = k_uptime_get_32(); while(uptime == k_uptime_get_32()); /* align on tick */ k_timer_start(&timer_a, 5, 0); k_timer_start(&timer_b, 5, 0); thread_a, prio 5: k_timer_status_sync(&timer_a); printk("thread_a got timer_a\n"); thread_b, prio 5: k_timer_status_sync(&timer_b); printk("thread_b got timer_b\n"); One could "reasonably" expect thread_a to run first, since both threads have the same prio, and timer_a was started before timer_b, thus inserted first in the timeout_q first (time-wise). However, thread_b will run before thread_a, since timer_b's timeout is prepended to timer_a's. This patch keeps the reversing of the order when adding timeouts in the timeout_q, thus preserving the same interrupt latency; however, when dequeuing them and adding them to the expired queue, we now reverse that order _again_, causing the timeouts to be handled in the expected order. Change-Id: Id83045f63e2be88809d6089b8ae62034e4e3facb Signed-off-by: Benjamin Walsh <walsh.benj@gmail.com>
This commit is contained in:
parent
5d35dba73d
commit
6f4bc80901
1 changed files with 12 additions and 1 deletions
|
@ -226,7 +226,18 @@ static inline void handle_timeouts(int32_t ticks)
|
|||
while (timeout && timeout->delta_ticks_from_prev == 0) {
|
||||
|
||||
sys_dlist_remove(next);
|
||||
sys_dlist_append(&expired, next);
|
||||
|
||||
/*
|
||||
* Reverse the order that that were queued in the timeout_q:
|
||||
* timeouts expiring on the same ticks are queued in the
|
||||
* reverse order, time-wise, that they are added to shorten the
|
||||
* amount of time with interrupts locked while walking the
|
||||
* timeout_q. By reversing the order _again_ when building the
|
||||
* expired queue, they end up being processed in the same order
|
||||
* they were added, time-wise.
|
||||
*/
|
||||
sys_dlist_prepend(&expired, next);
|
||||
|
||||
timeout->delta_ticks_from_prev = _EXPIRED;
|
||||
|
||||
irq_unlock(key);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue