[PATCH weston 1/8] shared: Add timespec_normalize helper

Alexandros Frantzis alexandros.frantzis at collabora.com
Mon Dec 4 13:34:01 UTC 2017


Add a helper function to normalize struct timespec values so that the
nanoseconds part is less than 1 second and has the same sign as the
seconds part (if the seconds part is not 0).

Normalization is required to ensure we can safely convert timespec
values to wayland protocol data, i.e, to tv_sec_hi, tv_sec_lo,
tv_sec_nsec triplets, and will be used in upcoming commits.

Signed-off-by: Alexandros Frantzis <alexandros.frantzis at collabora.com>
---
 shared/timespec-util.h | 28 ++++++++++++++++++++++
 tests/timespec-test.c  | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/shared/timespec-util.h b/shared/timespec-util.h
index f9736c27..a10edf5b 100644
--- a/shared/timespec-util.h
+++ b/shared/timespec-util.h
@@ -33,6 +33,34 @@
 
 #define NSEC_PER_SEC 1000000000
 
+/* Normalize a timespec
+ *
+ * \param r[out] normalized timespec
+ * \param a[in] timespec to normalize
+ *
+ * Normalize a timespec so that tv_nsec is less than 1 second
+ * and has the same sign as tv_sec (if tv_sec is non-zero).
+ *
+ */
+static inline void
+timespec_normalize(struct timespec *r, const struct timespec *a)
+{
+	if (a->tv_nsec >= NSEC_PER_SEC || a->tv_nsec <= -NSEC_PER_SEC) {
+		r->tv_sec = a->tv_sec + a->tv_nsec / NSEC_PER_SEC;
+		r->tv_nsec = a->tv_nsec % NSEC_PER_SEC;
+	} else {
+		*r = *a;
+	}
+
+	if (r->tv_sec > 0 && r->tv_nsec < 0) {
+		r->tv_sec -= 1;
+		r->tv_nsec += NSEC_PER_SEC;
+	} else if (r->tv_sec < 0 && r->tv_nsec > 0) {
+		r->tv_sec += 1;
+		r->tv_nsec -= NSEC_PER_SEC;
+	}
+}
+
 /* Subtract timespecs
  *
  * \param r[out] result: a - b
diff --git a/tests/timespec-test.c b/tests/timespec-test.c
index f127bcee..8c2296d1 100644
--- a/tests/timespec-test.c
+++ b/tests/timespec-test.c
@@ -38,6 +38,71 @@
 #include "shared/helpers.h"
 #include "zunitc/zunitc.h"
 
+ZUC_TEST(timespec_test, timespec_normalize)
+{
+	struct timespec a, r;
+
+	a.tv_sec = 0;
+	a.tv_nsec = 0;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, 0);
+	ZUC_ASSERT_EQ(r.tv_nsec, 0);
+
+	a.tv_sec = 1;
+	a.tv_nsec = NSEC_PER_SEC - 1;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, 1);
+	ZUC_ASSERT_EQ(r.tv_nsec, NSEC_PER_SEC - 1);
+
+	a.tv_sec = 1;
+	a.tv_nsec = NSEC_PER_SEC;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, 2);
+	ZUC_ASSERT_EQ(r.tv_nsec, 0);
+
+	a.tv_sec = 1;
+	a.tv_nsec = NSEC_PER_SEC + 1;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, 2);
+	ZUC_ASSERT_EQ(r.tv_nsec, 1);
+
+	a.tv_sec = -1;
+	a.tv_nsec = -NSEC_PER_SEC;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, -2);
+	ZUC_ASSERT_EQ(r.tv_nsec, 0);
+
+	a.tv_sec = -1;
+	a.tv_nsec = -(NSEC_PER_SEC + 1);
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, -2);
+	ZUC_ASSERT_EQ(r.tv_nsec, -1);
+
+	a.tv_sec = -3;
+	a.tv_nsec = NSEC_PER_SEC + 1;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, -1);
+	ZUC_ASSERT_EQ(r.tv_nsec, -(NSEC_PER_SEC - 1));
+
+	a.tv_sec = 3;
+	a.tv_nsec = -(NSEC_PER_SEC + 1);
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, 1);
+	ZUC_ASSERT_EQ(r.tv_nsec, NSEC_PER_SEC - 1);
+
+	a.tv_sec = -1;
+	a.tv_nsec = 2 * NSEC_PER_SEC + 1;
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, 1);
+	ZUC_ASSERT_EQ(r.tv_nsec, 1);
+
+	a.tv_sec = 1;
+	a.tv_nsec = -(2 * NSEC_PER_SEC + 1);
+	timespec_normalize(&r, &a);
+	ZUC_ASSERT_EQ(r.tv_sec, -1);
+	ZUC_ASSERT_EQ(r.tv_nsec, -1);
+}
+
 ZUC_TEST(timespec_test, timespec_sub)
 {
 	struct timespec a, b, r;
-- 
2.14.1



More information about the wayland-devel mailing list