Skip to content

Commit

Permalink
posix: clock_nanosleep tests
Browse files Browse the repository at this point in the history
Adds error and lower bounds tests for the posix clock_nanosleep
function. Refactors common test functions to be shared by both
clock_nanosleep and nanosleep tests.

Signed-off-by: Tom Finet <tom.codeninja@gmail.com>
  • Loading branch information
TomFinet committed Aug 28, 2023
1 parent 0f29d9e commit 92456f9
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 33 deletions.
16 changes: 6 additions & 10 deletions tests/posix/common/src/clock.c
Expand Up @@ -20,8 +20,7 @@ ZTEST(posix_apis, test_clock)
printk("POSIX clock APIs\n");

/* TESTPOINT: Pass invalid clock type */
zassert_equal(clock_gettime(CLOCK_INVALID, &ts), -1,
NULL);
zassert_equal(clock_gettime(CLOCK_INVALID, &ts), -1, NULL);
zassert_equal(errno, EINVAL);

zassert_ok(clock_gettime(CLOCK_MONOTONIC, &ts));
Expand All @@ -37,8 +36,7 @@ ZTEST(posix_apis, test_clock)
}

/*TESTPOINT: Check if POSIX clock API test passes*/
zassert_equal(secs_elapsed, SLEEP_SECONDS,
"POSIX clock API test failed");
zassert_equal(secs_elapsed, SLEEP_SECONDS, "POSIX clock API test failed");

printk("POSIX clock APIs test done\n");
}
Expand All @@ -63,8 +61,7 @@ ZTEST(posix_apis, test_realtime)
nts.tv_nsec = NSEC_PER_SEC / 2U;

/* TESTPOINT: Pass invalid clock type */
zassert_equal(clock_settime(CLOCK_INVALID, &nts), -1,
NULL);
zassert_equal(clock_settime(CLOCK_INVALID, &nts), -1, NULL);
zassert_equal(errno, EINVAL);

ret = clock_settime(CLOCK_MONOTONIC, &nts);
Expand All @@ -86,8 +83,7 @@ ZTEST(posix_apis, test_realtime)
zassert_equal(ret, 0, "Fail to read realtime clock");

int64_t delta =
((int64_t)rts.tv_sec * NSEC_PER_SEC -
(int64_t)nts.tv_sec * NSEC_PER_SEC) +
((int64_t)rts.tv_sec * NSEC_PER_SEC - (int64_t)nts.tv_sec * NSEC_PER_SEC) +
((int64_t)rts.tv_nsec - (int64_t)nts.tv_nsec);

/* Make the delta milliseconds. */
Expand Down Expand Up @@ -119,7 +115,7 @@ ZTEST(posix_apis, test_realtime)
* from clock_gettime
*/
zassert_true(rts.tv_sec >= tv.tv_sec, "gettimeofday didn't"
" provide correct result");
" provide correct result");
zassert_true(rts.tv_nsec >= tv.tv_usec * NSEC_PER_USEC,
"gettimeofday didn't provide correct result");
"gettimeofday didn't provide correct result");
}
143 changes: 120 additions & 23 deletions tests/posix/common/src/nanosleep.c
Expand Up @@ -11,20 +11,32 @@
#include <zephyr/sys_clock.h>
#include <zephyr/ztest.h>

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 = {};

/*
* 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);
Expand All @@ -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);

/*
Expand All @@ -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);
Expand All @@ -77,61 +89,146 @@ 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};
struct timespec req = {s, 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 */
}

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 up;
clock_gettime(CLOCK_MONOTONIC, &up);

/* sleep until absolute 1s + 1ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
up.tv_sec + 1, 1);

/* sleep until absolute 1s + 1us */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
up.tv_sec + 1, 1000);

/* sleep for 500000000ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
up.tv_sec + 1, 500000000);

/* sleep until absolute 2s */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
up.tv_sec + 2, 0);

/* sleep until absolute 2s + 1ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
up.tv_sec + 2, 1);

/* sleep until absolute 2s + 1us + 1ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
up.tv_sec + 2, 1001);

struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);

/* absolute sleep until realtime 4s + 1ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 1);

/* absolute sleep until realtime 4s + 1us */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 1000);

/* absolute sleep until realtime 4s + 500000000ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 500000000);

/* absolute sleep until realtime 5s */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 0);

/* absolute sleep until realtime 5s + 1ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 1);

/* absolute sleep until realtime 5s + 1us + 1ns */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 1001);
}

0 comments on commit 92456f9

Please sign in to comment.