Browse Source

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 <rusty@rustcorp.com.au>
Rusty Russell 11 years ago
parent
commit
a9d42b8d3b

+ 1 - 0
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;

+ 1 - 0
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);

+ 1 - 0
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));

+ 9 - 0
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));
 	}

+ 15 - 1
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;

+ 17 - 6
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);