sys/time.h: Remove comment about timercmp and add test

Message ID 1400674124-1789-1-git-send-email-rv@rasmusvillemoes.dk
State New, archived
Headers

Commit Message

Rasmus Villemoes May 21, 2014, 12:08 p.m. UTC
  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
  

Patch

diff --git a/time/Makefile b/time/Makefile
index b7f3dba..20ddfb7 100644
--- a/time/Makefile
+++ b/time/Makefile
@@ -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
 
diff --git a/time/sys/time.h b/time/sys/time.h
index a3f219e..af3fed5 100644
--- a/time/sys/time.h
+++ b/time/sys/time.h
@@ -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) 						      \
diff --git a/time/tst-timercmp.c b/time/tst-timercmp.c
new file mode 100644
index 0000000..fcd9b17
--- /dev/null
+++ b/time/tst-timercmp.c
@@ -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;
+}