Skip to content

Commit 8375fb7

Browse files
Holman GreenhandAnas Nashif
authored andcommitted
kernel: Allow late processing of timeouts
This change proposes to handle the case where the handle_timeouts function is called after a number of ticks greater than the first timeout delta of the _timeout_q list. In the current implementation if the case occurs, after subtracting the number of ticks the delta_ticks_from_prev field becomes negative and the first timeout is never processed. It is therefore necessary to treat this case and to prevent delta_ticks_from_prev from becoming negative. Moreover, the lag produced by the initial delay must also be applied to following timeouts by browsing the list until it was entirely consumed. Fixes #5401 Signed-off-by: Holman Greenhand <[email protected]>
1 parent 4b69e61 commit 8375fb7

File tree

1 file changed

+44
-21
lines changed

1 file changed

+44
-21
lines changed

kernel/sys_clock.c

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -179,52 +179,75 @@ static inline void handle_timeouts(s32_t ticks)
179179

180180
key = irq_lock();
181181

182-
struct _timeout *head =
183-
(struct _timeout *)sys_dlist_peek_head(&_timeout_q);
182+
sys_dnode_t *next = sys_dlist_peek_head(&_timeout_q);
183+
struct _timeout *timeout = (struct _timeout *)next;
184184

185185
K_DEBUG("head: %p, delta: %d\n",
186-
head, head ? head->delta_ticks_from_prev : -2112);
186+
timeout, timeout ? timeout->delta_ticks_from_prev : -2112);
187187

188-
if (!head) {
188+
if (!next) {
189189
irq_unlock(key);
190190
return;
191191
}
192192

193-
head->delta_ticks_from_prev -= ticks;
194-
195193
/*
196194
* Dequeue all expired timeouts from _timeout_q, relieving irq lock
197195
* pressure between each of them, allowing handling of higher priority
198196
* interrupts. We know that no new timeout will be prepended in front
199197
* of a timeout which delta is 0, since timeouts of 0 ticks are
200198
* prohibited.
201199
*/
202-
sys_dnode_t *next = &head->node;
203-
struct _timeout *timeout = (struct _timeout *)next;
204200

205201
_handling_timeouts = 1;
206202

207-
while (timeout && timeout->delta_ticks_from_prev == 0) {
208-
209-
sys_dlist_remove(next);
203+
while (next) {
210204

211205
/*
212-
* Reverse the order that that were queued in the timeout_q:
213-
* timeouts expiring on the same ticks are queued in the
214-
* reverse order, time-wise, that they are added to shorten the
215-
* amount of time with interrupts locked while walking the
216-
* timeout_q. By reversing the order _again_ when building the
217-
* expired queue, they end up being processed in the same order
218-
* they were added, time-wise.
206+
* In the case where ticks number is greater than the first
207+
* timeout delta of the list, the lag produced by this initial
208+
* difference must also be applied to others timeouts in list
209+
* until it was entirely consumed.
219210
*/
220-
sys_dlist_prepend(&expired, next);
221211

222-
timeout->delta_ticks_from_prev = _EXPIRED;
212+
s32_t tmp = timeout->delta_ticks_from_prev;
213+
214+
if (timeout->delta_ticks_from_prev < ticks) {
215+
timeout->delta_ticks_from_prev = 0;
216+
} else {
217+
timeout->delta_ticks_from_prev -= ticks;
218+
}
219+
220+
ticks -= tmp;
221+
222+
next = sys_dlist_peek_next(&_timeout_q, next);
223+
224+
if (timeout->delta_ticks_from_prev == 0) {
225+
sys_dnode_t *node = &timeout->node;
226+
227+
sys_dlist_remove(node);
228+
229+
/*
230+
* Reverse the order that that were queued in the
231+
* timeout_q: timeouts expiring on the same ticks are
232+
* queued in the reverse order, time-wise, that they are
233+
* added to shorten the amount of time with interrupts
234+
* locked while walking the timeout_q. By reversing the
235+
* order _again_ when building the expired queue, they
236+
* end up being processed in the same order they were
237+
* added, time-wise.
238+
*/
239+
240+
sys_dlist_prepend(&expired, node);
241+
242+
timeout->delta_ticks_from_prev = _EXPIRED;
243+
244+
} else if (ticks <= 0) {
245+
break;
246+
}
223247

224248
irq_unlock(key);
225249
key = irq_lock();
226250

227-
next = sys_dlist_peek_head(&_timeout_q);
228251
timeout = (struct _timeout *)next;
229252
}
230253

0 commit comments

Comments
 (0)