diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 50760141c..c6048534b 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -2515,6 +2515,41 @@ pthread::resume (pthread_t *thread) return 0; } +static inline int +pthread_convert_abstime (clockid_t clock_id, const struct timespec *abstime, + PLARGE_INTEGER timeout) +{ + struct timespec tp; + + /* According to SUSv3, the abstime value must be checked for validity. */ + if (abstime->tv_sec < 0 + || abstime->tv_nsec < 0 + || abstime->tv_nsec > 999999999) + return EINVAL; + + /* Check for immediate timeout before converting */ + clock_gettime (clock_id, &tp); + if (tp.tv_sec > abstime->tv_sec + || (tp.tv_sec == abstime->tv_sec + && tp.tv_nsec > abstime->tv_nsec)) + return ETIMEDOUT; + + timeout->QuadPart = abstime->tv_sec * NSPERSEC + + (abstime->tv_nsec + 99LL) / 100LL; + switch (clock_id) + { + case CLOCK_REALTIME: + timeout->QuadPart += FACTOR; + break; + default: + /* other clocks must be handled as relative timeout */ + timeout->QuadPart -= tp.tv_sec * NSPERSEC + tp.tv_nsec / 100LL; + timeout->QuadPart *= -1LL; + break; + } + return 0; +} + extern "C" int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) { @@ -2841,7 +2876,6 @@ extern "C" int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { - struct timespec tp; LARGE_INTEGER timeout; pthread_testcancel (); @@ -2852,34 +2886,10 @@ pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, if (err) return err; - /* According to SUSv3, the abstime value must be checked for validity. */ - if (abstime->tv_sec < 0 - || abstime->tv_nsec < 0 - || abstime->tv_nsec > 999999999) - __leave; + err = pthread_convert_abstime ((*cond)->clock_id, abstime, &timeout); + if (err) + return err; - clock_gettime ((*cond)->clock_id, &tp); - - /* Check for immediate timeout before converting */ - if (tp.tv_sec > abstime->tv_sec - || (tp.tv_sec == abstime->tv_sec - && tp.tv_nsec > abstime->tv_nsec)) - return ETIMEDOUT; - - timeout.QuadPart = abstime->tv_sec * NSPERSEC - + (abstime->tv_nsec + 99LL) / 100LL; - - switch ((*cond)->clock_id) - { - case CLOCK_REALTIME: - timeout.QuadPart += FACTOR; - break; - default: - /* other clocks must be handled as relative timeout */ - timeout.QuadPart -= tp.tv_sec * NSPERSEC + tp.tv_nsec / 100LL; - timeout.QuadPart *= -1LL; - break; - } return (*cond)->wait (*mutex, &timeout); } __except (NO_ERROR) {} @@ -3597,16 +3607,11 @@ semaphore::_trywait () } int -semaphore::_timedwait (const struct timespec *abstime) +semaphore::_wait (PLARGE_INTEGER timeout) { - LARGE_INTEGER timeout; - __try { - timeout.QuadPart = abstime->tv_sec * NSPERSEC - + (abstime->tv_nsec + 99) / 100 + FACTOR; - - switch (cygwait (win32_obj_id, &timeout, + switch (cygwait (win32_obj_id, timeout, cw_cancel | cw_cancel_self | cw_sig_eintr)) { case WAIT_OBJECT_0: @@ -3623,38 +3628,11 @@ semaphore::_timedwait (const struct timespec *abstime) return -1; } } - __except (NO_ERROR) - { - /* According to SUSv3, abstime need not be checked for validity, - if the semaphore can be locked immediately. */ - if (_trywait ()) - { - set_errno (EINVAL); - return -1; - } - } + __except (NO_ERROR) {} __endtry return 0; } -int -semaphore::_wait () -{ - switch (cygwait (win32_obj_id, cw_infinite, - cw_cancel | cw_cancel_self | cw_sig_eintr)) - { - case WAIT_OBJECT_0: - break; - case WAIT_SIGNALED: - set_errno (EINTR); - return -1; - default: - pthread_printf ("cygwait failed. %E"); - break; - } - return 0; -} - void semaphore::_fixup_before_fork () { @@ -3840,13 +3818,30 @@ semaphore::trywait (sem_t *sem) int semaphore::timedwait (sem_t *sem, const struct timespec *abstime) { + LARGE_INTEGER timeout; + if (!is_good_object (sem)) { set_errno (EINVAL); return -1; } - return (*sem)->_timedwait (abstime); + /* According to SUSv3, abstime need not be checked for validity, + if the semaphore can be locked immediately. */ + if (!(*sem)->_trywait ()) + return 0; + + __try + { + int err = pthread_convert_abstime (CLOCK_REALTIME, abstime, &timeout); + if (err) + return err; + + return (*sem)->_wait (&timeout); + } + __except (NO_ERROR) {} + __endtry + return EINVAL; } int diff --git a/winsup/cygwin/thread.h b/winsup/cygwin/thread.h index 48fb6fbb9..9bb861824 100644 --- a/winsup/cygwin/thread.h +++ b/winsup/cygwin/thread.h @@ -693,11 +693,10 @@ public: } private: - int _wait (); void _post (); int _getvalue (int *sval); int _trywait (); - int _timedwait (const struct timespec *abstime); + int _wait (PLARGE_INTEGER timeout = NULL); void _fixup_before_fork (); void _fixup_after_fork ();