diff options
author | Benjamin Herrenschmidt benh@kernel.crashing.org <benh@tika.localdomain> | 2006-11-28 12:14:03 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@tika.localdomain> | 2006-11-28 12:14:03 +1100 |
commit | 56d2a170bcddf2906d7ce6b5ba27a14c44947013 (patch) | |
tree | d7c078d0ccc75a629f4fac7741e48bf6bd493a0b | |
parent | d05c451f30a391b5fe582fa5a0d5e7a32673b57a (diff) |
Fix timeout handling with more than one timeout
The code would do a delete/insert pass while walking the
queue which had the effect of breaking the "order" linkage
(insert re-initializes pretty much everything).
I fixed that by adding a new _twin_queue_reorder() which
is to be called on an element that is to be re-ordered and
which works at any time, even during a queue walking and
using it from the timeout code.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | twin_queue.c | 16 | ||||
-rw-r--r-- | twin_timeout.c | 6 | ||||
-rw-r--r-- | twinint.h | 5 |
3 files changed, 24 insertions, 3 deletions
diff --git a/twin_queue.c b/twin_queue.c index 985d92a..171a6eb 100644 --- a/twin_queue.c +++ b/twin_queue.c @@ -53,6 +53,22 @@ _twin_queue_remove (twin_queue_t **head, } void +_twin_queue_reorder (twin_queue_t **head, + twin_queue_proc_t proc, + twin_queue_t *elem) +{ + twin_queue_t **prev, *q; + + _twin_queue_remove(head, elem); + + for (prev = head; (q = *prev); prev = &q->next) + if ((*proc) (elem, q) == TWIN_AFTER) + break; + elem->next = *prev; + *prev = elem; +} + +void _twin_queue_delete (twin_queue_t **head, twin_queue_t *old) { diff --git a/twin_timeout.c b/twin_timeout.c index 6640eca..189b305 100644 --- a/twin_timeout.c +++ b/twin_timeout.c @@ -63,9 +63,9 @@ _twin_run_timeout (void) delay = (*timeout->proc) (now, timeout->closure); if (delay >= 0) { - _twin_queue_remove ((twin_queue_t **) &head, - &timeout->queue); - _twin_queue_timeout (timeout, twin_now () + delay); + timeout->time = twin_now() + delay; + _twin_queue_reorder ((twin_queue_t **) &head, + _twin_timeout_order, &timeout->queue); } else _twin_queue_delete ((twin_queue_t **) &head, @@ -416,6 +416,11 @@ _twin_queue_remove (twin_queue_t **head, twin_queue_t *old); void +_twin_queue_reorder (twin_queue_t **head, + twin_queue_proc_t proc, + twin_queue_t *elem); + +void _twin_queue_delete (twin_queue_t **head, twin_queue_t *old); |