time: make timemono a first-class citizen.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 31 Oct 2016 00:32:32 +0000 (11:02 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 31 Oct 2016 00:32:32 +0000 (11:02 +1030)
Include assert checks, implement timemono_eq().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/time/test/run-check.c
ccan/time/time.c
ccan/time/time.h

index 11bcc57642b911ca90f00c177809293dc12f3256..c134afc3ec1ac655e8913d361815cebbffd9597c 100644 (file)
@@ -17,10 +17,11 @@ void abort(void)
 int main(void)
 {
        struct timeabs t1, t2, epoch = { { 0, 0 } };
+       struct timemono t1m, t2m;
        struct timerel t3, t4, zero = { { 0, 0 } };
        int fds[2];
 
-       plan_tests(64);
+       plan_tests(69);
 
        /* Test time_now */
        t1 = time_now();
@@ -43,6 +44,21 @@ int main(void)
        ok1(timerel_eq(t3, t3));
        ok1(!timerel_eq(t3, zero));
 
+       /* Test time_mono */
+       t1m = time_mono();
+       t2m = time_mono();
+
+       ok1(!time_less_(t2m.ts, t1m.ts));
+
+       t3.ts.tv_sec = 1;
+       t3.ts.tv_nsec = 0;
+
+       ok1(time_less(timemono_between(t2m, t1m), t3));
+       ok1(time_less(timemono_since(t1m), t3));
+
+       ok1(timemono_add(t1m, t3).ts.tv_sec == t1m.ts.tv_sec + 1);
+       ok1(timemono_add(t2m, t3).ts.tv_nsec == t2m.ts.tv_nsec);
+
        /* Make sure t2 > t1. */
        t3.ts.tv_sec = 0;
        t3.ts.tv_nsec = 1;
index d0542f5654e86f06e69bc40c530ce0c989643e92..27f0d52a30987df194ea710e8f4af6a4cd74dfc4 100644 (file)
@@ -33,7 +33,7 @@ struct timemono time_mono(void)
 #else /* Best we can do */
        ret.ts = time_now().ts;
 #endif /* !HAVE_TIME_MONOTONIC */
-       return ret;
+       return TIMEMONO_CHECK(ret);
 }
 
 struct timerel time_divide(struct timerel t, unsigned long div)
@@ -128,3 +128,11 @@ struct timeabs timeabs_check(struct timeabs t, const char *abortstr)
        ret.ts = time_check_(t.ts, abortstr);
        return ret;
 }
+
+struct timemono timemono_check(struct timemono t, const char *abortstr)
+{
+       struct timemono ret;
+
+       ret.ts = time_check_(t.ts, abortstr);
+       return ret;
+}
index f2b335cf45de0af387c2b0a9e1cba09c73ceb86a..70ebdc9a7751ca5be434329421618c58f177c9c7 100644 (file)
@@ -22,10 +22,13 @@ struct timespec {
        timerel_check((t), __FILE__ ":" stringify(__LINE__) " (" stringify(t) ") ")
 #define TIMEABS_CHECK(t) \
        timeabs_check((t), __FILE__ ":" stringify(__LINE__) " (" stringify(t) ") ")
+#define TIMEMONO_CHECK(t) \
+       timemono_check((t), __FILE__ ":" stringify(__LINE__) " (" stringify(t) ") ")
 #else
 #define TIME_CHECK(t) (t)
 #define TIMEREL_CHECK(t) (t)
 #define TIMEABS_CHECK(t) (t)
+#define TIMEMONO_CHECK(t) (t)
 #endif
 
 /**
@@ -95,7 +98,7 @@ struct timerel timerel_check(struct timerel in, const char *abortstr);
 
 /**
  * timeabs_check - check if an absolute time is malformed.
- * @in: the relative time to check (returned)
+ * @in: the absolute time to check (returned)
  * @abortstr: the string to print to stderr before aborting (if set).
  *
  * This can be used to make sure a time isn't negative and doesn't
@@ -113,6 +116,26 @@ struct timerel timerel_check(struct timerel in, const char *abortstr);
  */
 struct timeabs timeabs_check(struct timeabs in, const char *abortstr);
 
+/**
+ * timemono_check - check if a monotonic time is malformed.
+ * @in: the monotonic time to check (returned)
+ * @abortstr: the string to print to stderr before aborting (if set).
+ *
+ * This can be used to make sure a time isn't negative and doesn't
+ * have a tv_nsec >= 1000000000.  If it is, and @abortstr is non-NULL,
+ * that will be printed and abort() is called.  Otherwise, if
+ * @abortstr is NULL then the returned timemono will be normalized and
+ * tv_sec set to 0 if it was negative.
+ *
+ * Note that if ccan/time is compiled with DEBUG, then it will call this
+ * for all passed and returned times.
+ *
+ * Example:
+ *     printf("Now is %lu seconds since mono start\n",
+ *             (long)timemono_check(time_mono(), "time_mono failed?").ts.tv_sec);
+ */
+struct timemono timemono_check(struct timemono in, const char *abortstr);
+
 /**
  * time_now - return the current time
  *
@@ -231,6 +254,32 @@ static inline bool timeabs_eq(struct timeabs a, struct timeabs b)
                && a.ts.tv_nsec == b.ts.tv_nsec;
 }
 
+/**
+ * timemono_eq - is a equal to b?
+ * @a: one monotonic time.
+ * @b: another monotonic time.
+ *
+ * Example:
+ *     #include <sys/types.h>
+ *     #include <sys/wait.h>
+ *
+ *     // Can we fork in under a nanosecond?
+ *     static bool fast_fork(void)
+ *     {
+ *             struct timemono start = time_mono();
+ *             if (fork() != 0) {
+ *                     exit(0);
+ *             }
+ *             wait(NULL);
+ *             return timemono_eq(start, time_mono());
+ *     }
+ */
+static inline bool timemono_eq(struct timemono a, struct timemono b)
+{
+       return TIMEMONO_CHECK(a).ts.tv_sec == TIMEMONO_CHECK(b).ts.tv_sec
+               && a.ts.tv_nsec == b.ts.tv_nsec;
+}
+
 /**
  * timerel_eq - is a equal to b?
  * @a: one relative time.
@@ -328,7 +377,7 @@ static inline struct timerel timemono_since(struct timemono old)
 {
        struct timemono now = time_mono();
 
-       return timemono_between(now, old);
+       return timemono_between(now, TIMEMONO_CHECK(old));
 }
 
 /**