mach: compliance fixes for nanosleep Make the nanosleep Mach implementation behave a bit more POSIX compliant: * check for invalid values of the `requested_time' parameter * check for an interrupted __mach_msg call, and only in that case modify `remaining' with the remaining time (correctly calculated, as before it was set to the elapsed time); fail with EINTR in this case 2012-04-28 Pino Toscano * sysdeps/mach/nanosleep.c: Return EINVAL for invalid values of `requested_time'. Properly set the remaining time and return EINTR if interrupted. --- a/sysdeps/mach/nanosleep.c +++ b/sysdeps/mach/nanosleep.c @@ -27,24 +27,38 @@ __nanosleep (const struct timespec *requ { mach_port_t recv; struct timeval before, after; + + if (requested_time->tv_sec < 0 + || requested_time->tv_nsec < 0 + || requested_time->tv_nsec >= 1000000000) + { + errno = EINVAL; + return -1; + } + const mach_msg_timeout_t ms = requested_time->tv_sec * 1000 + (requested_time->tv_nsec + 999999) / 1000000; - recv = __mach_reply_port (); if (remaining && __gettimeofday (&before, NULL) < 0) return -1; - (void) __mach_msg (NULL, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT, - 0, 0, recv, ms, MACH_PORT_NULL); + error_t err = __mach_msg (NULL, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT, + 0, 0, recv, ms, MACH_PORT_NULL); __mach_port_destroy (mach_task_self (), recv); - if (remaining && __gettimeofday (&after, NULL) < 0) - return -1; - - if (remaining) + if (err == EMACH_RCV_INTERRUPTED) { - timersub (&after, &before, &after); - TIMEVAL_TO_TIMESPEC (&after, remaining); + if (remaining && __gettimeofday (&after, NULL) >= 0) + { + struct timeval req_time, elapsed, rem; + TIMESPEC_TO_TIMEVAL (&req_time, requested_time); + timersub (&after, &before, &elapsed); + timersub (&req_time, &elapsed, &rem); + TIMEVAL_TO_TIMESPEC (&rem, remaining); + } + + errno = EINTR; + return -1; } return 0;