Skip to content

Commit

Permalink
kernel/timeout: fix handling expired timeouts in reverve queuing order
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
bboccoqq authored and Anas Nashif committed Feb 16, 2017
1 parent 5d35dba commit 6f4bc80
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion kernel/sys_clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 6f4bc80

Please sign in to comment.