timer: make timer_del() idempotent, add timer_init().
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 29 Oct 2014 05:40:21 +0000 (16:10 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 30 Oct 2014 22:52:11 +0000 (09:22 +1030)
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 <rusty@rustcorp.com.au>
ccan/timer/test/run-add.c
ccan/timer/test/run-expiry.c
ccan/timer/test/run-ff.c
ccan/timer/test/run.c
ccan/timer/timer.c
ccan/timer/timer.h

index a7ea4f602a9c255d20741d17359a26ea98d4222a..e97bf781ddcc82e644d82165b9d7d373deee351c 100644 (file)
@@ -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;
index d2969d25d95b21de5da9b0605cf8361644b5f84f..1c276c2c9016332d1101343f815980bae9d177d2 100644 (file)
@@ -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);
index 148b7f7922e4ddd8d952c66b9d155833c96a601c..49c6e3744c1e3e9991e9fea9db09f5ac2f3decdd 100644 (file)
@@ -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));
index f7b711f2c8530cb98183baf10ed07770f3fc4264..51648fb1c7978a5ba51aeb33d03c6b5ea0fb4d74 100644 (file)
@@ -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));
        }
index c1979fd32d97244a52b930e04ef50bc51733319a..0abf05cd419ee8111312450872e80b53fee1ebb2 100644 (file)
@@ -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;
index aeb2aebc5dacb0396fe5ce319c4668812acb9df9..7a9fb07518a880c3097c5e99d388bddc14d82346 100644 (file)
@@ -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);