Browse Source

timer: change to use time_mono (api break!)

Remove timer_add() in favor of explicit timer_addrel and timer_addmono.

Someone hit a real-life case where time went backwards, and we asserted.
The correct fix is to use time_mono() where available, but as all known
users actually want a relative timeout, have a helper for that case.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 9 years ago
parent
commit
4ba1049041

+ 4 - 5
ccan/timer/_info

@@ -31,21 +31,20 @@
  *		struct timer *t;
  *		struct timed_string *s;
  *
- *		timers_init(&timers, time_now());
+ *		timers_init(&timers, time_mono());
  *		list_head_init(&strings);
  *
  *		while (argv[1]) {
  *			s = malloc(sizeof(*s));
  *			s->string = argv[1];
- *			timer_add(&timers, &s->timer,
- *				  timeabs_add(time_now(),
- *					      time_from_msec(atol(argv[2]))));
+ *			timer_addrel(&timers, &s->timer,
+ *				     time_from_msec(atol(argv[2])));
  *			list_add_tail(&strings, &s->node);
  *			argv += 2;
  *		}
  *
  *		while (!list_empty(&strings)) {
- *			struct timeabs now = time_now();
+ *			struct timemono now = time_mono();
  *			list_for_each(&strings, s, node)
  *				printf("%s", s->string);
  *			while ((t = timers_expire(&timers, now)) != NULL) {

+ 2 - 2
ccan/timer/test/run-add.c

@@ -20,7 +20,7 @@ int main(void)
 	struct timer t;
 	uint64_t diff;
 	unsigned int i;
-	struct timeabs epoch = { { 0, 0 } };
+	struct timemono epoch = { { 0, 0 } };
 
 	/* This is how many tests you plan to run */
 	plan_tests(2 + (18 + (MAX_ORD - 4) * 3) * (18 + (MAX_ORD - 4) * 3));
@@ -38,7 +38,7 @@ int main(void)
 		for (timers.base = 0;
 		     timers.base < (1ULL << MAX_ORD)+2;
 		     timers.base = next(timers.base)) {
-			timer_add(&timers, &t, grains_to_time(timers.base + diff));
+			timer_addmono(&timers, &t, grains_to_time(timers.base + diff));
 			ok1(timers_check(&timers, NULL));
 			timer_del(&timers, &t);
 		}

+ 4 - 4
ccan/timer/test/run-corrupt.c

@@ -7,17 +7,17 @@
 static void new_timer(struct timers *timers, unsigned long nsec)
 {
 	struct timer *timer;
-	struct timeabs when;
+	struct timemono when;
 
 	timer = malloc(sizeof(*timer));
 	timer_init(timer);
 	when.ts.tv_sec = 0; when.ts.tv_nsec = nsec;
-	timer_add(timers, timer, when);
+	timer_addmono(timers, timer, when);
 }
 
 static void update_and_expire(struct timers *timers)
 {
-	struct timeabs when;
+	struct timemono when;
 
 	timer_earliest(timers, &when);
 	free(timers_expire(timers, when));
@@ -25,7 +25,7 @@ static void update_and_expire(struct timers *timers)
 
 int main(int argc, char *argv[])
 {
-	struct timeabs when;
+	struct timemono when;
 	struct timers timers;
 
 	plan_tests(7);

File diff suppressed because it is too large
+ 403 - 403
ccan/timer/test/run-corrupt2.c


+ 1 - 1
ccan/timer/test/run-expiry.c

@@ -14,7 +14,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));
+	timer_addmono(&timers, &t, grains_to_time(1364984761003398ULL));
 	ok1(t.time == 1364984761003398ULL);
 	ok1(timers.first == 1364984761003398ULL);
 	ok1(!timers_expire(&timers, grains_to_time(1364984760903444ULL)));

+ 8 - 8
ccan/timer/test/run-ff.c

@@ -3,10 +3,10 @@
 #include <ccan/timer/timer.c>
 #include <ccan/tap/tap.h>
 
-static struct timeabs timeabs_from_usec(unsigned long long usec)
+static struct timemono timemono_from_usec(unsigned long long usec)
 {
-	struct timeabs epoch = { { 0, 0 } };
-	return timeabs_add(epoch, time_from_usec(usec));
+	struct timemono epoch = { { 0, 0 } };
+	return timemono_add(epoch, time_from_usec(usec));
 }
 
 int main(void)
@@ -17,13 +17,13 @@ int main(void)
 	/* This is how many tests you plan to run */
 	plan_tests(3);
 
-	timers_init(&timers, timeabs_from_usec(1364726722653919ULL));
+	timers_init(&timers, timemono_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));
+	timer_addmono(&timers, &t, timemono_from_usec(1364726722703919ULL));
+	ok1(!timers_expire(&timers, timemono_from_usec(1364726722653920ULL)));
+	expired = timers_expire(&timers, timemono_from_usec(1364726725454187ULL));
 	ok1(expired == &t);
-	ok1(!timers_expire(&timers, timeabs_from_usec(1364726725454187ULL)));
+	ok1(!timers_expire(&timers, timemono_from_usec(1364726725454187ULL)));
 	timers_cleanup(&timers);
 
 	/* This exits depending on whether all tests passed */

File diff suppressed because it is too large
+ 403 - 403
ccan/timer/test/run-original-corrupt.c


+ 31 - 13
ccan/timer/test/run.c

@@ -1,25 +1,31 @@
 #define CCAN_TIMER_DEBUG
 #include <ccan/timer/timer.h>
+#include <ccan/time/time.h>
+
+#define time_mono() fake_mono_time
+
+static struct timemono fake_mono_time;
+
 /* Include the C files directly. */
 #include <ccan/timer/timer.c>
 #include <ccan/tap/tap.h>
 
-static struct timeabs timeabs_from_nsec(unsigned long long nsec)
+static struct timemono timemono_from_nsec(unsigned long long nsec)
 {
-	struct timeabs epoch = { { 0, 0 } };
-	return timeabs_add(epoch, time_from_nsec(nsec));
+	struct timemono epoch = { { 0, 0 } };
+	return timemono_add(epoch, time_from_nsec(nsec));
 }
 
 int main(void)
 {
 	struct timers timers;
 	struct timer t[64];
-	struct timeabs earliest;
+	struct timemono earliest;
 	uint64_t i;
-	struct timeabs epoch = { { 0, 0 } };
+	const struct timemono epoch = { { 0, 0 } };
 
 	/* This is how many tests you plan to run */
-	plan_tests(488);
+	plan_tests(495);
 
 	timers_init(&timers, epoch);
 	ok1(timers_check(&timers, NULL));
@@ -29,10 +35,10 @@ int main(void)
 	/* timer_del can be called immediately after init. */
 	timer_del(&timers, &t[0]);
 
-	timer_add(&timers, &t[0], timeabs_from_nsec(1));
+	timer_addmono(&timers, &t[0], timemono_from_nsec(1));
 	ok1(timers_check(&timers, NULL));
 	ok1(timer_earliest(&timers, &earliest));
-	ok1(timeabs_eq(earliest, grains_to_time(t[0].time)));
+	ok1(timemono_eq(earliest, grains_to_time(t[0].time)));
 	timer_del(&timers, &t[0]);
 	ok1(timers_check(&timers, NULL));
 	ok1(!timer_earliest(&timers, &earliest));
@@ -43,10 +49,10 @@ int main(void)
 	/* 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));
+		timer_addmono(&timers, &t[i*2], timemono_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));
+		timer_addmono(&timers, &t[i*2+1], timemono_from_nsec((1ULL << i) + 1));
 		ok1(timers_check(&timers, NULL));
 	}
 
@@ -68,9 +74,9 @@ int main(void)
 	for (i = 0; i < 32; i++) {
 		uint64_t exp = (uint64_t)TIMER_GRANULARITY << i;
 
-		timer_add(&timers, &t[i*2], timeabs_from_nsec(exp));
+		timer_addmono(&timers, &t[i*2], timemono_from_nsec(exp));
 		ok1(timers_check(&timers, NULL));
-		timer_add(&timers, &t[i*2+1], timeabs_from_nsec(exp + 1));
+		timer_addmono(&timers, &t[i*2+1], timemono_from_nsec(exp + 1));
 		ok1(timers_check(&timers, NULL));
 	}
 
@@ -90,7 +96,19 @@ int main(void)
 	}
 
 	ok1(!timer_earliest(&timers, &earliest));
-
+	ok1(timers_check(&timers, NULL));
+	timers_cleanup(&timers);
+	
+	/* Relative timers. */
+	timers_init(&timers, epoch);
+	fake_mono_time = timemono_from_nsec(TIMER_GRANULARITY);
+	timer_addrel(&timers, &t[0], time_from_sec(1));
+	ok1(timer_earliest(&timers, &earliest));
+	ok1(timers_check(&timers, NULL));
+	ok1(earliest.ts.tv_sec == 1 && earliest.ts.tv_nsec == TIMER_GRANULARITY);
+	ok1(timers_expire(&timers, earliest) == &t[0]);
+	ok1(!timer_earliest(&timers, &earliest));
+	ok1(timers_check(&timers, NULL));
 	timers_cleanup(&timers);
 
 	/* This exits depending on whether all tests passed */

+ 26 - 7
ccan/timer/timer.c

@@ -12,15 +12,15 @@ struct timer_level {
 	struct list_head list[PER_LEVEL];
 };
 
-static uint64_t time_to_grains(struct timeabs t)
+static uint64_t time_to_grains(struct timemono t)
 {
 	return t.ts.tv_sec * ((uint64_t)1000000000 / TIMER_GRANULARITY)
 		+ (t.ts.tv_nsec / TIMER_GRANULARITY);
 }
 
-static struct timeabs grains_to_time(uint64_t grains)
+static struct timemono grains_to_time(uint64_t grains)
 {
-	struct timeabs t;
+	struct timemono t;
 
 	t.ts.tv_sec = grains / (1000000000 / TIMER_GRANULARITY);
 	t.ts.tv_nsec = (grains % (1000000000 / TIMER_GRANULARITY))
@@ -28,7 +28,7 @@ static struct timeabs grains_to_time(uint64_t grains)
 	return t;
 }
 
-void timers_init(struct timers *timers, struct timeabs start)
+void timers_init(struct timers *timers, struct timemono start)
 {
 	unsigned int i;
 
@@ -79,7 +79,26 @@ 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)
+void timer_addrel(struct timers *timers, struct timer *t, struct timerel rel)
+{
+	assert(list_node_initted(&t->list));
+
+	t->time = time_to_grains(timemono_add(time_mono(), rel));
+
+#if TIME_HAVE_MONOTONIC
+	assert(t->time >= timers->base);
+#else
+	/* Added in the past?  Treat it as imminent. */
+	if (t->time < timers->base)
+		t->time = timers->base;
+#endif
+	if (t->time < timers->first)
+		timers->first = t->time;
+
+	timer_add_raw(timers, t);
+}
+
+void timer_addmono(struct timers *timers, struct timer *t, struct timemono when)
 {
 	assert(list_node_initted(&t->list));
 
@@ -241,7 +260,7 @@ static bool update_first(struct timers *timers)
 	return true;
 }
 
-bool timer_earliest(struct timers *timers, struct timeabs *first)
+bool timer_earliest(struct timers *timers, struct timemono *first)
 {
 	if (!update_first(timers))
 		return false;
@@ -298,7 +317,7 @@ static void timer_fast_forward(struct timers *timers, uint64_t time)
 }
 
 /* Returns an expired timer. */
-struct timer *timers_expire(struct timers *timers, struct timeabs expire)
+struct timer *timers_expire(struct timers *timers, struct timemono expire)
 {
 	uint64_t now = time_to_grains(expire);
 	unsigned int off;

+ 30 - 10
ccan/timer/timer.h

@@ -29,9 +29,9 @@ struct timer;
  * Example:
  *	struct timers timeouts;
  *
- *	timers_init(&timeouts, time_now());
+ *	timers_init(&timeouts, time_mono());
  */
-void timers_init(struct timers *timers, struct timeabs start);
+void timers_init(struct timers *timers, struct timemono start);
 
 /**
  * timers_cleanup - free allocations within timers struct.
@@ -56,19 +56,39 @@ void timers_cleanup(struct timers *timers);
 void timer_init(struct timer *t);
 
 /**
- * timer_add - insert a timer.
+ * timer_addrel - insert a relative timer.
  * @timers: the struct timers
  * @timer: the (initialized or timer_del'd) timer to add
- * @when: when @timer expires.
+ * @rel: when @timer expires (relative).
+ *
+ * This efficiently adds @timer to @timers, to expire @rel (rounded to
+ * TIMER_GRANULARITY nanoseconds) after the current time.  This
+ * is a convenient wrapper around timer_addmono().
+ *
+ * Example:
+ *	// Timeout in 100ms.
+ *	timer_addrel(&timeouts, &t, time_from_msec(100));
+ */
+void timer_addrel(struct timers *timers, struct timer *timer, struct timerel rel);
+
+/**
+ * timer_addmono - insert an absolute timer.
+ * @timers: the struct timers
+ * @timer: the (initialized or timer_del'd) timer to add
+ * @when: when @timer expires (absolute).
  *
  * This efficiently adds @timer to @timers, to expire @when (rounded to
  * TIMER_GRANULARITY nanoseconds).
  *
+ * Note that if @when is before time_mono(), then it will be set to expire
+ * immediately.
+ *
  * Example:
  *	// Timeout in 100ms.
- *	timer_add(&timeouts, &t, timeabs_add(time_now(), time_from_msec(100)));
+ *	timer_addmono(&timeouts, &t, timemono_add(time_mono(), time_from_msec(100)));
  */
-void timer_add(struct timers *timers, struct timer *timer, struct timeabs when);
+void timer_addmono(struct timers *timers, struct timer *timer,
+		   struct timemono when);
 
 /**
  * timer_del - remove a timer.
@@ -94,10 +114,10 @@ void timer_del(struct timers *timers, struct timer *timer);
  * timer (rounded to TIMER_GRANULARITY nanoseconds), and returns true.
  *
  * Example:
- *	struct timeabs next = { { (time_t)-1ULL, -1UL } };
+ *	struct timemono next = { { (time_t)-1ULL, -1UL } };
  *	timer_earliest(&timeouts, &next);
  */
-bool timer_earliest(struct timers *timers, struct timeabs *first);
+bool timer_earliest(struct timers *timers, struct timemono *first);
 
 /**
  * timers_expire - update timers structure and remove one expire timer.
@@ -118,11 +138,11 @@ bool timer_earliest(struct timers *timers, struct timeabs *first);
  * Example:
  *	struct timer *expired;
  *
- *	while ((expired = timers_expire(&timeouts, time_now())) != NULL)
+ *	while ((expired = timers_expire(&timeouts, time_mono())) != NULL)
  *		printf("Timer expired!\n");
  *
  */
-struct timer *timers_expire(struct timers *timers, struct timeabs expire);
+struct timer *timers_expire(struct timers *timers, struct timemono expire);
 
 /**
  * timers_check - check timer structure for consistency

Some files were not shown because too many files changed in this diff