diff --git a/tests/posix/common/src/nanosleep.c b/tests/posix/common/src/nanosleep.c index ec565ac85138ae..5e4d3bcf88d405 100644 --- a/tests/posix/common/src/nanosleep.c +++ b/tests/posix/common/src/nanosleep.c @@ -11,7 +11,19 @@ #include #include -ZTEST(posix_apis, test_nanosleep_errors_errno) +#define SELECT_NANOSLEEP 1 +#define SELECT_CLOCK_NANOSLEEP 0 + +static inline int select_nanosleep(int selection, clockid_t clock_id, int flags, + const struct timespec *rqtp, struct timespec *rmtp) +{ + if (selection == SELECT_NANOSLEEP) { + return nanosleep(rqtp, rmtp); + } + return clock_nanosleep(clock_id, flags, rqtp, rmtp); +} + +static void common_errors(int selection, clockid_t clock_id, int flags) { struct timespec rem = {}; struct timespec req = {}; @@ -19,12 +31,12 @@ ZTEST(posix_apis, test_nanosleep_errors_errno) /* * invalid parameters */ - zassert_equal(nanosleep(NULL, NULL), -1); + zassert_equal(select_nanosleep(selection, clock_id, flags, NULL, NULL), -1); zassert_equal(errno, EFAULT); /* NULL request */ errno = 0; - zassert_equal(nanosleep(NULL, &rem), -1); + zassert_equal(select_nanosleep(selection, clock_id, flags, NULL, &rem), -1); zassert_equal(errno, EFAULT); /* Expect rem to be the same when function returns */ zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0); @@ -33,23 +45,23 @@ ZTEST(posix_apis, test_nanosleep_errors_errno) /* negative times */ errno = 0; req = (struct timespec){.tv_sec = -1, .tv_nsec = 0}; - zassert_equal(nanosleep(&req, NULL), -1); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, NULL), -1); zassert_equal(errno, EINVAL); errno = 0; req = (struct timespec){.tv_sec = 0, .tv_nsec = -1}; - zassert_equal(nanosleep(&req, NULL), -1); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, NULL), -1); zassert_equal(errno, EINVAL); errno = 0; req = (struct timespec){.tv_sec = -1, .tv_nsec = -1}; - zassert_equal(nanosleep(&req, NULL), -1); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, NULL), -1); zassert_equal(errno, EINVAL); /* nanoseconds too high */ errno = 0; req = (struct timespec){.tv_sec = 0, .tv_nsec = 1000000000}; - zassert_equal(nanosleep(&req, NULL), -1); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, NULL), -1); zassert_equal(errno, EINVAL); /* @@ -59,13 +71,13 @@ ZTEST(posix_apis, test_nanosleep_errors_errno) /* Happy path, plus make sure the const input is unmodified */ req = (struct timespec){.tv_sec = 1, .tv_nsec = 1}; - zassert_equal(nanosleep(&req, NULL), 0); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, NULL), 0); zassert_equal(errno, 0); zassert_equal(req.tv_sec, 1); zassert_equal(req.tv_nsec, 1); /* Sleep for 0.0 s. Expect req & rem to be the same when function returns */ - zassert_equal(nanosleep(&req, &rem), 0); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, &rem), 0); zassert_equal(errno, 0); zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0); zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0); @@ -77,15 +89,43 @@ ZTEST(posix_apis, test_nanosleep_errors_errno) * Expect rem to be zero after returning. */ req = (struct timespec){.tv_sec = 0, .tv_nsec = 1}; - zassert_equal(nanosleep(&req, &req), 0); + zassert_equal(select_nanosleep(selection, clock_id, flags, &req, &req), 0); zassert_equal(errno, 0); zassert_equal(req.tv_sec, 0, "actual: %d expected: %d", req.tv_sec, 0); zassert_equal(req.tv_nsec, 0, "actual: %d expected: %d", req.tv_nsec, 0); } -static void common(const uint32_t s, uint32_t ns) +ZTEST(posix_apis, test_nanosleep_errors_errno) +{ + common_errors(SELECT_NANOSLEEP, CLOCK_REALTIME, 0); +} + +ZTEST(posix_apis, test_clock_nanosleep_errors_errno) +{ + struct timespec rem = {}; + struct timespec req = {}; + + common_errors(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME); + + /* Absolute timeout in the past. */ + clock_gettime(CLOCK_MONOTONIC, &req); + zassert_equal(clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &req, &rem), 0); + zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0); + zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0); + + /* Absolute timeout in the past relative to the realtime clock. */ + clock_gettime(CLOCK_REALTIME, &req); + zassert_equal(clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &req, &rem), 0); + zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0); + zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0); +} + +static void common_lower_bound_check(int selection, clockid_t clock_id, int flags, const uint32_t s, + uint32_t ns) { int r; + uint64_t actual_ns; + uint64_t exp_ns; uint32_t now; uint32_t then; struct timespec rem = {0, 0}; @@ -93,24 +133,24 @@ static void common(const uint32_t s, uint32_t ns) errno = 0; then = k_cycle_get_32(); - r = nanosleep(&req, &rem); + r = select_nanosleep(selection, clock_id, flags, &req, &rem); now = k_cycle_get_32(); - zassert_equal(r, 0, "actual: %d expected: %d", r, -1); + zassert_equal(r, 0, "actual: %d expected: %d", r, 0); zassert_equal(errno, 0, "actual: %d expected: %d", errno, 0); zassert_equal(req.tv_sec, s, "actual: %d expected: %d", req.tv_sec, s); zassert_equal(req.tv_nsec, ns, "actual: %d expected: %d", req.tv_nsec, ns); zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0); zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0); - uint64_t actual_ns = k_cyc_to_ns_ceil64((now - then)); - uint64_t exp_ns = (uint64_t)s * NSEC_PER_SEC + ns; + actual_ns = k_cyc_to_ns_ceil64((now - then * selection)); + + exp_ns = (uint64_t)s * NSEC_PER_SEC + ns; /* round up to the nearest microsecond for k_busy_wait() */ exp_ns = DIV_ROUND_UP(exp_ns, NSEC_PER_USEC) * NSEC_PER_USEC; /* lower bounds check */ - zassert_true(actual_ns >= exp_ns, - "actual: %llu expected: %llu", actual_ns, exp_ns); + zassert_true(actual_ns >= exp_ns, "actual: %llu expected: %llu", actual_ns, exp_ns); /* TODO: Upper bounds check when hr timers are available */ } @@ -118,20 +158,81 @@ static void common(const uint32_t s, uint32_t ns) ZTEST(posix_apis, test_nanosleep_execution) { /* sleep for 1ns */ - common(0, 1); + common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 0, 1); /* sleep for 1us + 1ns */ - common(0, 1001); + common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 0, 1001); /* sleep for 500000000ns */ - common(0, 500000000); + common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 0, 500000000); /* sleep for 1s */ - common(1, 0); + common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 1, 0); /* sleep for 1s + 1ns */ - common(1, 1); + common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 1, 1); /* sleep for 1s + 1us + 1ns */ - common(1, 1001); + common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 1, 1001); +} + +ZTEST(posix_apis, test_clock_nanosleep_execution) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + /* absolute sleeps with the monotonic clock and reference time ts */ + + /* until 1s + 1ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME, + ts.tv_sec + 1, 1); + + /* until 1s + 1us past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME, + ts.tv_sec + 1, 1000); + + /* until 1s + 500000000ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME, + ts.tv_sec + 1, 500000000); + + /* until 2s past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME, + ts.tv_sec + 2, 0); + + /* until 2s + 1ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME, + ts.tv_sec + 2, 1); + + /* until 2s + 1us + 1ns past reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME, + ts.tv_sec + 2, 1001); + + clock_gettime(CLOCK_REALTIME, &ts); + + /* absolute sleeps with the real time clock and adjusted reference time ts */ + + /* until 1s + 1ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, + ts.tv_sec + 1, 1); + + /* until 1s + 1us past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, + ts.tv_sec + 1, 1000); + + /* until 1s + 500000000ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, + ts.tv_sec + 1, 500000000); + + /* until 2s past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, + ts.tv_sec + 2, 0); + + /* until 2s + 1ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, + ts.tv_sec + 2, 1); + + /* until 2s + 1us + 1ns past the reference time */ + common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME, + ts.tv_sec + 2, 1001); }