@@ -37,7 +37,7 @@ aux := era alt_digit lc-time-cleanup
tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
- tst-strptime3 bug-getdate1 tst-strptime-whitespace
+ tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-timercmp
include ../Rules
@@ -157,8 +157,7 @@ extern int futimesat (int __fd, const char *__file,
#ifdef __USE_MISC
-/* Convenience macros for operations on timevals.
- NOTE: `timercmp' does not work for >= or <=. */
+/* Convenience macros for operations on timevals. */
# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
# define timercmp(a, b, CMP) \
new file mode 100644
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+static void prepare (void);
+#define PREPARE(argc, argv) prepare ()
+
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
+
+
+#define NTEST 100
+struct test {
+ struct timeval tv;
+ double d;
+} test[NTEST];
+
+/*
+ * We populate test[] with struct timevals with tv_sec in the range
+ * [-50,50]. This guarantees that the corresponding double values,
+ * though not able to represent tv_sec + tv_usec*1e-6 exactly, have
+ * sufficient granularity to distinguish different struct timevals.
+ */
+static void
+prepare (void)
+{
+ for (int i = 0; i < NTEST; ++i) {
+ long s = (lrand48() % 101) - 50;
+ long us = (lrand48() % 1000000);
+ test[i].tv.tv_sec = s;
+ test[i].tv.tv_usec = us;
+ test[i].d = (double)s + 1e-6 * us;
+ }
+}
+
+static void
+fail(const struct test *a, const struct test *b, int x, int y, const char *cmp)
+{
+ printf("({.tv_sec = %ld, .tv_usec = %06ld} %s "
+ "{.tv_sec = %ld, .tv_usec = %06ld}) == %d, ",
+ (long)a->tv.tv_sec, (long)a->tv.tv_usec, cmp,
+ (long)b->tv.tv_sec, (long)b->tv.tv_usec, x);
+ printf("expected (%.6f %s %.6f) == %d\n", a->d, cmp, b->d, y);
+}
+
+#define CHECK(a, b, cmp) do { \
+ int x = !!(timercmp(&(a)->tv, &(b)->tv, cmp)); \
+ int y = !!((a)->d cmp (b)->d); \
+ if (x != y) { \
+ fail(a, b, x, y, #cmp); \
+ result = 1; \
+ } \
+ } while(0);
+
+static int
+do_test(void)
+{
+ int result = 0;
+ for (int i = 0; i < NTEST; ++i) {
+ for (int j = i; j < NTEST; ++j) {
+ const struct test *a = &test[i];
+ const struct test *b = &test[j];
+ CHECK(a, b, ==);
+ CHECK(a, b, !=);
+ CHECK(a, b, <=);
+ CHECK(a, b, >=);
+ CHECK(a, b, <);
+ CHECK(a, b, >);
+ }
+ }
+ return result;
+}
The manual page timercmp(3) says "Some systems (but not Linux/glibc), have a broken timercmp() implementation, in which CMP of >=, <=, and == do not work". However, <sys/time.h> contains "NOTE: `timercmp' does not work for >= or <=.". Looking at the implementation of the macro, AFAICT the manual is correct. To be sure, I wrote a simple test program, which confirms this. Signed-off-by: Rasmus Villemoes <rv@rasmusvillemoes.dk> --- time/Makefile | 2 +- time/sys/time.h | 3 +-- time/tst-timercmp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 time/tst-timercmp.c