diff --git a/include/posix/time.h b/include/posix/time.h index 28518b01fce..a61b1d6693f 100644 --- a/include/posix/time.h +++ b/include/posix/time.h @@ -91,6 +91,7 @@ int timer_delete(timer_t timerid); int timer_gettime(timer_t timerid, struct itimerspec *its); int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); +int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); #ifdef __cplusplus } diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index e1703eaaa26..7dfade5ec7e 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -24,6 +24,10 @@ zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) zephyr_library_sources_ifdef(CONFIG_EVENTFD eventfd.c) +if(NOT (CONFIG_BOARD_NATIVE_POSIX OR CONFIG_BOARD_NATIVE_POSIX_64BIT)) +zephyr_library_sources(nanosleep.c) +endif() + zephyr_library_include_directories( ${ZEPHYR_BASE}/kernel/include ${ZEPHYR_BASE}/arch/${ARCH}/include diff --git a/lib/posix/nanosleep.c b/lib/posix/nanosleep.c new file mode 100644 index 00000000000..1d451a60d9d --- /dev/null +++ b/lib/posix/nanosleep.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Friedt Professional Engineering Services, Inc + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +/* required for struct timespec */ +#include +#include + +/** + * @brief Suspend execution for nanosecond intervals. + * + * See IEEE 1003.1 + */ +int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + uint64_t ns; + const bool update_rmtp = rmtp != NULL; + + if (rqtp == NULL) { + errno = EFAULT; + return -1; + } + + if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 + || rqtp->tv_nsec >= NSEC_PER_SEC) { + errno = EINVAL; + return -1; + } + + if (rqtp->tv_sec == 0 && rqtp->tv_nsec == 0) { + goto do_rmtp_update; + } + + if (unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) { + /* If a user passes this in, we could be here a while, but + * at least it's technically correct-ish + */ + ns = rqtp->tv_nsec + NSEC_PER_SEC; + k_sleep(K_SECONDS(rqtp->tv_sec - 1)); + } else { + ns = rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec; + } + + /* currently we have no mechanism to achieve greater resolution */ + k_busy_wait(ns / NSEC_PER_USEC); + +do_rmtp_update: + if (update_rmtp) { + rmtp->tv_sec = 0; + rmtp->tv_nsec = 0; + } + + return 0; +}