From a9d42b8d3bf2b37f47caa428e869fceb4bb33082 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 29 Oct 2014 16:10:21 +1030 Subject: [PATCH] timer: make timer_del() idempotent, add timer_init(). This catches duplicate timer_add() calls, as well as meaning we don't need to track if the timer is active before calling timer_del(). Signed-off-by: Rusty Russell --- ccan/timer/test/run-add.c | 1 + ccan/timer/test/run-expiry.c | 1 + ccan/timer/test/run-ff.c | 1 + ccan/timer/test/run.c | 9 +++++++++ ccan/timer/timer.c | 16 +++++++++++++++- ccan/timer/timer.h | 23 +++++++++++++++++------ 6 files changed, 44 insertions(+), 7 deletions(-) diff --git a/ccan/timer/test/run-add.c b/ccan/timer/test/run-add.c index a7ea4f60..e97bf781 100644 --- a/ccan/timer/test/run-add.c +++ b/ccan/timer/test/run-add.c @@ -32,6 +32,7 @@ int main(void) add_level(&timers, i); i = 0; + timer_init(&t); for (diff = 0; diff < (1ULL << MAX_ORD)+2; diff = next(diff)) { i++; for (timers.base = 0; diff --git a/ccan/timer/test/run-expiry.c b/ccan/timer/test/run-expiry.c index d2969d25..1c276c2c 100644 --- a/ccan/timer/test/run-expiry.c +++ b/ccan/timer/test/run-expiry.c @@ -13,6 +13,7 @@ int main(void) timers_init(&timers, grains_to_time(1364984760903400ULL)); ok1(timers.base == 1364984760903400ULL); + timer_init(&t); timer_add(&timers, &t, grains_to_time(1364984761003398ULL)); ok1(t.time == 1364984761003398ULL); ok1(timers.first == 1364984761003398ULL); diff --git a/ccan/timer/test/run-ff.c b/ccan/timer/test/run-ff.c index 148b7f79..49c6e374 100644 --- a/ccan/timer/test/run-ff.c +++ b/ccan/timer/test/run-ff.c @@ -18,6 +18,7 @@ int main(void) plan_tests(3); timers_init(&timers, timeabs_from_usec(1364726722653919ULL)); + timer_init(&t); timer_add(&timers, &t, timeabs_from_usec(1364726722703919ULL)); ok1(!timers_expire(&timers, timeabs_from_usec(1364726722653920ULL))); expired = timers_expire(&timers, timeabs_from_usec(1364726725454187ULL)); diff --git a/ccan/timer/test/run.c b/ccan/timer/test/run.c index f7b711f2..51648fb1 100644 --- a/ccan/timer/test/run.c +++ b/ccan/timer/test/run.c @@ -24,6 +24,10 @@ int main(void) ok1(timers_check(&timers, NULL)); ok1(!timer_earliest(&timers, &earliest)); + timer_init(&t[0]); + /* timer_del can be called immediately after init. */ + timer_del(&timers, &t[0]); + timer_add(&timers, &t[0], timeabs_from_nsec(1)); ok1(timers_check(&timers, NULL)); ok1(timer_earliest(&timers, &earliest)); @@ -32,10 +36,15 @@ int main(void) ok1(timers_check(&timers, NULL)); ok1(!timer_earliest(&timers, &earliest)); + /* timer_del can be called twice, no problems. */ + timer_del(&timers, &t[0]); + /* Check timer ordering. */ for (i = 0; i < 32; i++) { + timer_init(&t[i*2]); timer_add(&timers, &t[i*2], timeabs_from_nsec(1ULL << i)); ok1(timers_check(&timers, NULL)); + timer_init(&t[i*2+1]); timer_add(&timers, &t[i*2+1], timeabs_from_nsec((1ULL << i) + 1)); ok1(timers_check(&timers, NULL)); } diff --git a/ccan/timer/timer.c b/ccan/timer/timer.c index c1979fd3..0abf05cd 100644 --- a/ccan/timer/timer.c +++ b/ccan/timer/timer.c @@ -63,8 +63,20 @@ static void timer_add_raw(struct timers *timers, struct timer *t) list_add_tail(l, &t->list); } +void timer_init(struct timer *t) +{ + list_node_init(&t->list); +} + +static bool list_node_initted(const struct list_node *n) +{ + return n->prev == n; +} + void timer_add(struct timers *timers, struct timer *t, struct timeabs when) { + assert(list_node_initted(&t->list)); + t->time = time_to_grains(when); /* Added in the past? Treat it as imminent. */ @@ -79,7 +91,7 @@ void timer_add(struct timers *timers, struct timer *t, struct timeabs when) /* FIXME: inline */ void timer_del(struct timers *timers, struct timer *t) { - list_del(&t->list); + list_del_init(&t->list); } static void timers_far_get(struct timers *timers, @@ -285,6 +297,8 @@ struct timer *timers_expire(struct timers *timers, struct timeabs expire) /* This *may* be NULL, if we deleted the first timer */ t = list_pop(&timers->level[0]->list[off], struct timer, list); + if (t) + list_node_init(&t->list); } while (!t && update_first(timers)); return t; diff --git a/ccan/timer/timer.h b/ccan/timer/timer.h index aeb2aebc..7a9fb075 100644 --- a/ccan/timer/timer.h +++ b/ccan/timer/timer.h @@ -44,29 +44,40 @@ void timers_init(struct timers *timers, struct timeabs start); */ void timers_cleanup(struct timers *timers); +/** + * timer_init - initialize a timer. + * @timer: the timer to initialize + * + * Example: + * struct timer t; + * + * timer_init(&t); + */ +void timer_init(struct timer *t); + /** * timer_add - insert a timer. * @timers: the struct timers - * @timer: the (uninitialized) timer to add + * @timer: the (initialized or timer_del'd) timer to add * @when: when @timer expires. * * This efficiently adds @timer to @timers, to expire @when (rounded to * TIMER_GRANULARITY nanoseconds). * * Example: - * struct timer t; - * * // Timeout in 100ms. * timer_add(&timeouts, &t, timeabs_add(time_now(), time_from_msec(100))); */ void timer_add(struct timers *timers, struct timer *timer, struct timeabs when); /** - * timer_del - remove an unexpired timer. + * timer_del - remove a timer. * @timers: the struct timers - * @timer: the timer previously added with timer_add() + * @timer: the timer * - * This efficiently removes @timer from @timers. + * This efficiently removes @timer from @timers, if timer_add() was + * called. It can be called multiple times without bad effect, and + * can be called any time after timer_init(). * * Example: * timer_del(&timeouts, &t); -- 2.39.2