tests: posix: clock: ensure overflow is consistent
Add a test to verify previous fixes when calculating time in
seconds for `clock_gettime()`.
@@ -122,3 +122,67 @@ ZTEST(posix_apis, test_posix_realtime)
zassert_true(rts.tv_nsec >= tv.tv_usec * NSEC_PER_USEC,
"gettimeofday didn't provide correct result");
}
+
+static inline bool ts_gt(const struct timespec *a, const struct timespec *b)
+{
+ __ASSERT_NO_MSG(a->tv_nsec < NSEC_PER_SEC);
+ __ASSERT_NO_MSG(a->tv_nsec >= 0);
+ __ASSERT_NO_MSG(b->tv_nsec < NSEC_PER_SEC);
+ __ASSERT_NO_MSG(b->tv_nsec >= 0);
+
+ if (a->tv_sec > b->tv_sec) {
+ return true;
+ }
+
+ if (a->tv_sec < b->tv_sec) {
+ return false;
+ }
+
+ if (a->tv_nsec > b->tv_nsec) {
+ return true;
+ }
+
+ return false;
+}
+
+static inline void ts_print(const char *label, const struct timespec *ts)
+{
+ printk("%s: {%" PRIu64 ", %" PRIu64 "}\n", label, (uint64_t)ts->tv_sec,
+ (uint64_t)ts->tv_nsec);
+}
+
+ZTEST(posix_apis, test_clock_gettime_rollover)
+{
+ uint64_t t;
+ struct timespec ts[3];
+ const uint64_t rollover_s = UINT64_MAX / CONFIG_SYS_CLOCK_TICKS_PER_SEC;
+
+ printk("CONFIG_SYS_CLOCK_TICKS_PER_SEC: %u\n", CONFIG_SYS_CLOCK_TICKS_PER_SEC);
+ printk("rollover_s: %" PRIu64 "\n", rollover_s);
+
+ t = UINT64_MAX - 1;
+ /* align to tick boundary */
+ k_sleep(K_TICKS(1));
+ sys_clock_tick_set(t);
+ zassert_ok(clock_gettime(CLOCK_MONOTONIC, &ts[0]));
+ ts_print("t-1", &ts[0]);
+ zassert_equal(rollover_s, ts[0].tv_sec);
+
+ t = UINT64_MAX;
+ /* align to tick boundary */
+ k_sleep(K_TICKS(1));
+ sys_clock_tick_set(t);
+ zassert_ok(clock_gettime(CLOCK_MONOTONIC, &ts[1]));
+ ts_print("t+0", &ts[1]);
+ zassert_equal(rollover_s, ts[1].tv_sec);
+ zassert_true(ts_gt(&ts[1], &ts[0]));
+
+ t = UINT64_MAX + 1;
+ /* align to tick boundary */
+ k_sleep(K_TICKS(1));
+ sys_clock_tick_set(t);
+ zassert_ok(clock_gettime(CLOCK_MONOTONIC, &ts[2]));
+ ts_print("t+1", &ts[2]);
+ zassert_equal(0, ts[2].tv_sec);
+ zassert_true(ts_gt(&ts[1], &ts[2]));
+}
