diff --git a/libcxx/include/__support/ibm/nanosleep.h b/libcxx/include/__support/ibm/nanosleep.h --- a/libcxx/include/__support/ibm/nanosleep.h +++ b/libcxx/include/__support/ibm/nanosleep.h @@ -12,27 +12,42 @@ #include -inline int nanosleep(const struct timespec* req, struct timespec* rem) -{ - // The nanosleep() function is not available on z/OS. Therefore, we will call - // sleep() to sleep for whole seconds and usleep() to sleep for any remaining - // fraction of a second. Any remaining nanoseconds will round up to the next - // microsecond. - - useconds_t __micro_sec = (rem->tv_nsec + 999) / 1000; - if (__micro_sec > 999999) - { - ++rem->tv_sec; - __micro_sec -= 1000000; - } - while (rem->tv_sec) - rem->tv_sec = sleep(rem->tv_sec); - if (__micro_sec) { - rem->tv_nsec = __micro_sec * 1000; - return usleep(__micro_sec); - } - rem->tv_nsec = 0; - return 0; +inline int nanosleep(const struct timespec* __req, struct timespec* __rem) { + // The nanosleep() function is not available on z/OS. Therefore, we will call + // sleep() to sleep for whole seconds and usleep() to sleep for any remaining + // fraction of a second. Any remaining nanoseconds will round up to the next + // microsecond. + if (__req->tv_sec < 0 || __req->tv_nsec < 0 || __req->tv_nsec > 999999999) { + errno = EINVAL; + return -1; + } + useconds_t __micro_sec = + static_cast((__req->tv_nsec + 999) / 1000); + time_t __sec = __req->tv_sec; + if (__micro_sec > 999999) { + ++__sec; + __micro_sec -= 1000000; + } + __sec = sleep(static_cast(__sec)); + if (__sec) { + if (__rem) { + __rem->tv_sec = __sec; + __rem->tv_nsec = __micro_sec * 1000; + } + errno = EINTR; + return -1; + } + if (__micro_sec) { + int rc = usleep(__micro_sec); + if (rc != 0 && __rem) { + __rem->tv_sec = 0; + __rem->tv_nsec = __micro_sec * 1000; + // errno is already set + return -1; + } + return rc; + } + return 0; } #endif // _LIBCPP_SUPPORT_IBM_NANOSLEEP_H