cygwin: simplify pthread timedwait handling

- Introduce inline helper pthread_convert_abstime.  It converts
  an absolute timespec to a Windows LARGE_INTEGER timestamp,
  depending on the used clock.

- Use this function from pthread_cond_timedwait and semaphore::timedwait

- Merge semaphore::_wait and semaphore::_timedwait into single _wait
  method, taking a LARGER_INTEGER timestamp.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2017-08-03 19:08:31 +02:00
parent a346a26790
commit 68217c3178
2 changed files with 60 additions and 66 deletions

View file

@ -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

View file

@ -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 ();