1 /* 2 * Copyright (c) 2018 Friedt Professional Engineering Services, Inc 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #include <stdint.h> 8 #include <kernel.h> 9 #include <limits.h> 10 #include <errno.h> 11 /* required for struct timespec */ 12 #include <posix/time.h> 13 #include <sys/util.h> 14 #include <sys_clock.h> 15 16 /** 17 * @brief Suspend execution for nanosecond intervals. 18 * 19 * See IEEE 1003.1 20 */ nanosleep(const struct timespec * rqtp,struct timespec * rmtp)21int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) 22 { 23 uint64_t ns; 24 uint64_t us; 25 const bool update_rmtp = rmtp != NULL; 26 27 if (rqtp == NULL) { 28 errno = EFAULT; 29 return -1; 30 } 31 32 if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 33 || rqtp->tv_nsec >= NSEC_PER_SEC) { 34 errno = EINVAL; 35 return -1; 36 } 37 38 if (rqtp->tv_sec == 0 && rqtp->tv_nsec == 0) { 39 goto do_rmtp_update; 40 } 41 42 if (unlikely(rqtp->tv_sec >= ULLONG_MAX / NSEC_PER_SEC)) { 43 /* If a user passes this in, we could be here a while, but 44 * at least it's technically correct-ish 45 */ 46 ns = rqtp->tv_nsec + NSEC_PER_SEC 47 + k_sleep(K_SECONDS(rqtp->tv_sec - 1)) * NSEC_PER_MSEC; 48 } else { 49 ns = rqtp->tv_sec * NSEC_PER_SEC + rqtp->tv_nsec; 50 } 51 52 /* TODO: improve upper bound when hr timers are available */ 53 us = ceiling_fraction(ns, NSEC_PER_USEC); 54 do { 55 us = k_usleep(us); 56 } while (us != 0); 57 58 do_rmtp_update: 59 if (update_rmtp) { 60 rmtp->tv_sec = 0; 61 rmtp->tv_nsec = 0; 62 } 63 64 return 0; 65 } 66