blob: ec565ac85138aecea052eb3607eae19e660fe984 [file] [log] [blame]
/*
* Copyright (c) 2018 Friedt Professional Engineering Services, Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <stdint.h>
#include <time.h>
#include <zephyr/sys_clock.h>
#include <zephyr/ztest.h>
ZTEST(posix_apis, test_nanosleep_errors_errno)
{
struct timespec rem = {};
struct timespec req = {};
/*
* invalid parameters
*/
zassert_equal(nanosleep(NULL, NULL), -1);
zassert_equal(errno, EFAULT);
/* NULL request */
errno = 0;
zassert_equal(nanosleep(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);
zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0);
/* negative times */
errno = 0;
req = (struct timespec){.tv_sec = -1, .tv_nsec = 0};
zassert_equal(nanosleep(&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(errno, EINVAL);
errno = 0;
req = (struct timespec){.tv_sec = -1, .tv_nsec = -1};
zassert_equal(nanosleep(&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(errno, EINVAL);
/*
* Valid parameters
*/
errno = 0;
/* 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(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(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);
/*
* req and rem point to the same timespec
*
* Normative spec says they may be the same.
* Expect rem to be zero after returning.
*/
req = (struct timespec){.tv_sec = 0, .tv_nsec = 1};
zassert_equal(nanosleep(&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)
{
int r;
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);
now = k_cycle_get_32();
zassert_equal(r, 0, "actual: %d expected: %d", r, -1);
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;
/* 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);
/* TODO: Upper bounds check when hr timers are available */
}
ZTEST(posix_apis, test_nanosleep_execution)
{
/* sleep for 1ns */
common(0, 1);
/* sleep for 1us + 1ns */
common(0, 1001);
/* sleep for 500000000ns */
common(0, 500000000);
/* sleep for 1s */
common(1, 0);
/* sleep for 1s + 1ns */
common(1, 1);
/* sleep for 1s + 1us + 1ns */
common(1, 1001);
}