Message ID | 93715d4ac59e160bf7ef244832d56b062b78e425.1551291557.git-series.mac@mcrowe.com |
---|---|
State | New |
Headers | show |
Series | Implement proposed POSIX _clockwait variants of existing _timedwait functions | expand |
On 27/02/2019 15:23, Mike Crowe wrote: > In preparation for adding POSIX clockwait variants of timedwait functions, > add a clockid_t parameter to futex_abstimed_wait functions and pass > CLOCK_REALTIME from all callers for the time being. > > Replace lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset which > takes a clockid_t parameter rather than the magic clockbit. > > * sysdeps/nptl/lowlevellock-futex.h, > sysdeps/unix/sysv/linux/lowlevellock-futex.h: Replace > lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset that takes a > clockid rather than a special clockbit. > > * sysdeps/nptl/lowlevellock-futex.h: Add lll_futex_supported_clockid so > that client functions can check whether their clockid parameter is valid > even if they don't ultimately end up calling lll_futex_clock_wait_bitset. > > * sysdeps/nptl/futex-internal.h, sysdeps/unix/sysv/linux/futex-internal.h > (futex_abstimed_wait, futex_abstimed_wait_cancelable): Add clockid_t > parameter to indicate which clock the absolute time passed should be > measured against. Pass that clockid onto lll_futex_clock_wait_bitset. > Add invalid clock as reason for returning -EINVAL. > > * sysdeps/nptl/futex-internal.h, sysdeps/unix/sysv/linux/futex-internal.h: > Introduce futex_abstimed_supported_clockid so that client functions can > check whether their clockid parameter is valid even if they don't > ultimately end up calling futex_abstimed_wait. > > * nptl/pthread_cond_wait.c (__pthread_cond_wait_common), > nptl/pthread_rwlock_common (__pthread_rwlock_rdlock_full, > __pthread_wrlock_full), nptl/sem_waitcommon (do_futex_wait): Pass > additional CLOCK_REALTIME to futex_abstimed_wait_cancelable. > > * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Switch to > lll_futex_clock_wait_bitset and pass CLOCK_REALTIME > --- > nptl/pthread_cond_wait.c | 2 +- > nptl/pthread_mutex_timedlock.c | 8 +++--- > nptl/pthread_rwlock_common.c | 8 +++--- > nptl/sem_waitcommon.c | 6 ++-- > sysdeps/nptl/futex-internal.h | 7 +++++- > sysdeps/nptl/lowlevellock-futex.h | 14 ++++++---- > sysdeps/unix/sysv/linux/futex-internal.h | 26 +++++++++++++------ > sysdeps/unix/sysv/linux/lowlevellock-futex.h | 29 ++++++++++++++++----- > 8 files changed, 71 insertions(+), 29 deletions(-) > > diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c > index 9a0f29e..daa4e25 100644 > --- a/nptl/pthread_cond_wait.c > +++ b/nptl/pthread_cond_wait.c > @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, > { > /* Use CLOCK_REALTIME. */ > err = futex_abstimed_wait_cancelable > - (cond->__data.__g_signals + g, 0, abstime, private); > + (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private); > } > } > Since we still assume that an architecture might not support futex with CLOCK_REALTIME, this part should check for __ASSUME_FUTEX_CLOCK_REALTIME as other parts. I proposed recently to just assume __ASSUME_FUTEX_CLOCK_REALTIME support [1], which simplifies this patch. [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00667.html > diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c > index 2f61a7d..c145a65 100644 > --- a/nptl/pthread_mutex_timedlock.c > +++ b/nptl/pthread_mutex_timedlock.c > @@ -241,7 +241,7 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, > if (__glibc_unlikely (abstime->tv_sec < 0)) > return ETIMEDOUT; > #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ > - || !defined lll_futex_timed_wait_bitset) > + || !defined lll_futex_clock_wait_bitset) > struct timeval tv; > struct timespec rt; > > @@ -288,12 +288,12 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, > > /* Block using the futex. */ > #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ > - || !defined lll_futex_timed_wait_bitset) > + || !defined lll_futex_clock_wait_bitset) > lll_futex_timed_wait (&mutex->__data.__lock, oldval, > &rt, PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); > #else > - int err = lll_futex_timed_wait_bitset (&mutex->__data.__lock, > - oldval, abstime, FUTEX_CLOCK_REALTIME, > + int err = lll_futex_clock_wait_bitset (&mutex->__data.__lock, > + oldval, CLOCK_REALTIME, abstime, > PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); > /* The futex call timed out. */ > if (err == -ETIMEDOUT) > diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c > index 2560734..89ba21a 100644 > --- a/nptl/pthread_rwlock_common.c > +++ b/nptl/pthread_rwlock_common.c > @@ -319,7 +319,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, > { > int private = __pthread_rwlock_get_private (rwlock); > int err = futex_abstimed_wait (&rwlock->__data.__readers, > - r, abstime, private); > + r, CLOCK_REALTIME, abstime, private); > /* We ignore EAGAIN and EINTR. On time-outs, we can just > return because we don't need to clean up anything. */ > if (err == ETIMEDOUT) > @@ -447,7 +447,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, > continue; > int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, > 1 | PTHREAD_RWLOCK_FUTEX_USED, > - abstime, private); > + CLOCK_REALTIME, abstime, private); > if (err == ETIMEDOUT) > { > /* If we timed out, we need to unregister. If no read phase > @@ -707,7 +707,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, > may_share_futex_used_flag = true; > int err = futex_abstimed_wait (&rwlock->__data.__writers_futex, > 1 | PTHREAD_RWLOCK_FUTEX_USED, > - abstime, private); > + CLOCK_REALTIME, abstime, private); > if (err == ETIMEDOUT) > { > if (prefer_writer) > @@ -806,7 +806,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, > continue; > int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, > PTHREAD_RWLOCK_FUTEX_USED, > - abstime, private); > + CLOCK_REALTIME, abstime, private); > if (err == ETIMEDOUT) > { > if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) > diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c > index 5646bea..425d040 100644 > --- a/nptl/sem_waitcommon.c > +++ b/nptl/sem_waitcommon.c > @@ -109,11 +109,13 @@ do_futex_wait (struct new_sem *sem, const struct timespec *abstime) > > #if __HAVE_64B_ATOMICS > err = futex_abstimed_wait_cancelable ( > - (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, abstime, > + (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, > + CLOCK_REALTIME, abstime, > sem->private); > #else > err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK, > - abstime, sem->private); > + CLOCK_REALTIME, abstime, > + sem->private); > #endif > > return err; > diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h > index 86a0818..54b7319 100644 > --- a/sysdeps/nptl/futex-internal.h > +++ b/sysdeps/nptl/futex-internal.h > @@ -159,16 +159,23 @@ futex_reltimed_wait_cancelable (unsigned int* futex_word, > unsigned int expected, > const struct timespec* reltime, int private); > > +/* Check whether the specified clockid is supported by > + futex_abstimed_wait and futex_abstimed_wait_cancelable. */ > +static __always_inline int > +futex_abstimed_supported_clockid (clockid_t clockid); > + > /* Like futex_reltimed_wait, but the provided timeout (ABSTIME) is an > absolute point in time; a call will time out after this point in time. */ > static __always_inline int > futex_abstimed_wait (unsigned int* futex_word, unsigned int expected, > + clockid_t clockid, > const struct timespec* abstime, int private); > > /* Like futex_reltimed_wait but is a POSIX cancellation point. */ > static __always_inline int > futex_abstimed_wait_cancelable (unsigned int* futex_word, > unsigned int expected, > + clockid_t clockid, > const struct timespec* abstime, int private); > > /* Atomically wrt other futex operations on the same futex, this unblocks the > diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h > index bb8effe..35fcfbb 100644 > --- a/sysdeps/nptl/lowlevellock-futex.h > +++ b/sysdeps/nptl/lowlevellock-futex.h > @@ -43,11 +43,15 @@ > #define lll_futex_timed_wait(futexp, val, timeout, private) \ > -ENOSYS > > -/* This macro should be defined only if FUTEX_CLOCK_REALTIME is also defined. > - If CLOCKBIT is zero, this is identical to lll_futex_timed_wait. > - If CLOCKBIT has FUTEX_CLOCK_REALTIME set, then it's the same but > - TIMEOUT is counted by CLOCK_REALTIME rather than CLOCK_MONOTONIC. */ > -#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \ > +/* Verify whether the supplied clockid is supported by > + lll_futex_clock_wait_bitset */ > +#define lll_futex_supported_clockid(clockid) \ > + (0) > + > +/* Wait until a lll_futex_wake call on FUTEXP, or the absolute TIMEOUT > + measured against CLOCKID elapses. CLOCKID may be CLOCK_REALTIME or > + CLOCK_MONOTONIC. */ > +#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \ > -ENOSYS > > /* Wake up up to NR waiters on FUTEXP. */ > diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h > index 55f0fab..68bfe7e 100644 > --- a/sysdeps/unix/sysv/linux/futex-internal.h > +++ b/sysdeps/unix/sysv/linux/futex-internal.h > @@ -162,15 +162,24 @@ futex_reltimed_wait_cancelable (unsigned int *futex_word, > > /* See sysdeps/nptl/futex-internal.h for details. */ > static __always_inline int > +futex_abstimed_supported_clockid (clockid_t clockid) > +{ > + return lll_futex_supported_clockid (clockid); > +} > + > +/* See sysdeps/nptl/futex-internal.h for details. */ > +static __always_inline int > futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, > + clockid_t clockid, > const struct timespec *abstime, int private) > { > /* Work around the fact that the kernel rejects negative timeout values > despite them being valid. */ > if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0))) > return ETIMEDOUT; > - int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime, > - FUTEX_CLOCK_REALTIME, private); > + int err = lll_futex_clock_wait_bitset (futex_word, expected, > + clockid, abstime, > + private); > switch (err) > { > case 0: > @@ -180,9 +189,10 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, > return -err; > > case -EFAULT: /* Must have been caused by a glibc or application bug. */ > - case -EINVAL: /* Either due to wrong alignment or due to the timeout not > - being normalized. Must have been caused by a glibc or > - application bug. */ > + case -EINVAL: /* Either due to wrong alignment, unsupported > + clockid or due to the timeout not being > + normalized. Must have been caused by a glibc or > + application bug. */ > case -ENOSYS: /* Must have been caused by a glibc bug. */ > /* No other errors are documented at this time. */ > default: > @@ -194,6 +204,7 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, > static __always_inline int > futex_abstimed_wait_cancelable (unsigned int *futex_word, > unsigned int expected, > + clockid_t clockid, > const struct timespec *abstime, int private) > { > /* Work around the fact that the kernel rejects negative timeout values > @@ -202,8 +213,9 @@ futex_abstimed_wait_cancelable (unsigned int *futex_word, > return ETIMEDOUT; > int oldtype; > oldtype = __pthread_enable_asynccancel (); > - int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime, > - FUTEX_CLOCK_REALTIME, private); > + int err = lll_futex_clock_wait_bitset (futex_word, expected, > + clockid, abstime, > + private); > __pthread_disable_asynccancel (oldtype); > switch (err) > { > diff --git a/sysdeps/unix/sysv/linux/lowlevellock-futex.h b/sysdeps/unix/sysv/linux/lowlevellock-futex.h > index 6f060b1..c3e7152 100644 > --- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h > +++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h > @@ -82,12 +82,29 @@ > __lll_private_flag (FUTEX_WAIT, private), \ > val, timeout) > > -#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \ > - lll_futex_syscall (6, futexp, \ > - __lll_private_flag (FUTEX_WAIT_BITSET | (clockbit), \ > - private), \ > - val, timeout, NULL /* Unused. */, \ > - FUTEX_BITSET_MATCH_ANY) > +/* Verify whether the supplied clockid is supported by > + lll_futex_clock_wait_bitset */ > +#define lll_futex_supported_clockid(clockid) \ > + (clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC) I think we need evaluate clockid with parentesis to avoid some macro evaluation issues. > + > +/* The kernel currently only supports CLOCK_MONOTONIC or > + * CLOCK_REALTIME timeouts for FUTEX_WAIT_BITSET. We could attempt to > + * convert others here but currently do not. > + */ > +#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \ > + ({ \ > + long int __ret; \ > + if (lll_futex_supported_clockid (clockid)) { \ I think even for macro definitions we need to use GNU style for brackets (which means break in a subsequent line). > + const unsigned int clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; \ > + __ret = lll_futex_syscall (6, futexp, \ > + __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, \ > + private), \ > + val, timeout, NULL /* Unused. */, \ > + FUTEX_BITSET_MATCH_ANY); \ > + } else \ > + __ret = -EINVAL; \ > + __ret; \ > + }) > > #define lll_futex_wake(futexp, nr, private) \ > lll_futex_syscall (4, futexp, \ >
On Tuesday 05 March 2019 at 09:39:58 -0300, Adhemerval Zanella wrote: > > diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c > > index 9a0f29e..daa4e25 100644 > > --- a/nptl/pthread_cond_wait.c > > +++ b/nptl/pthread_cond_wait.c > > @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, > > { > > /* Use CLOCK_REALTIME. */ > > err = futex_abstimed_wait_cancelable > > - (cond->__data.__g_signals + g, 0, abstime, private); > > + (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private); > > } > > } > > > > Since we still assume that an architecture might not support futex > with CLOCK_REALTIME, this part should check for __ASSUME_FUTEX_CLOCK_REALTIME > as other parts. > > I proposed recently to just assume __ASSUME_FUTEX_CLOCK_REALTIME > support [1], which simplifies this patch. Whilst trying to implement pthread_mutex_clockclock offline yesterday, I decided to propose the same thing. It looks like I don't need to. :) > [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00667.html It would certainly make my life easier if that patch was merged. Thanks. Mike.
On 10/03/2019 05:59, Mike Crowe wrote: > On Tuesday 05 March 2019 at 09:39:58 -0300, Adhemerval Zanella wrote: >>> diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c >>> index 9a0f29e..daa4e25 100644 >>> --- a/nptl/pthread_cond_wait.c >>> +++ b/nptl/pthread_cond_wait.c >>> @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, >>> { >>> /* Use CLOCK_REALTIME. */ >>> err = futex_abstimed_wait_cancelable >>> - (cond->__data.__g_signals + g, 0, abstime, private); >>> + (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private); >>> } >>> } >>> >> >> Since we still assume that an architecture might not support futex >> with CLOCK_REALTIME, this part should check for __ASSUME_FUTEX_CLOCK_REALTIME >> as other parts. >> >> I proposed recently to just assume __ASSUME_FUTEX_CLOCK_REALTIME >> support [1], which simplifies this patch. > > Whilst trying to implement pthread_mutex_clockclock offline yesterday, I > decided to propose the same thing. It looks like I don't need to. :) > >> [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00667.html > > It would certainly make my life easier if that patch was merged. > > Thanks. It is already merged.
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c index 9a0f29e..daa4e25 100644 --- a/nptl/pthread_cond_wait.c +++ b/nptl/pthread_cond_wait.c @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, { /* Use CLOCK_REALTIME. */ err = futex_abstimed_wait_cancelable - (cond->__data.__g_signals + g, 0, abstime, private); + (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private); } } diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index 2f61a7d..c145a65 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -241,7 +241,7 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, if (__glibc_unlikely (abstime->tv_sec < 0)) return ETIMEDOUT; #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ - || !defined lll_futex_timed_wait_bitset) + || !defined lll_futex_clock_wait_bitset) struct timeval tv; struct timespec rt; @@ -288,12 +288,12 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, /* Block using the futex. */ #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \ - || !defined lll_futex_timed_wait_bitset) + || !defined lll_futex_clock_wait_bitset) lll_futex_timed_wait (&mutex->__data.__lock, oldval, &rt, PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); #else - int err = lll_futex_timed_wait_bitset (&mutex->__data.__lock, - oldval, abstime, FUTEX_CLOCK_REALTIME, + int err = lll_futex_clock_wait_bitset (&mutex->__data.__lock, + oldval, CLOCK_REALTIME, abstime, PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); /* The futex call timed out. */ if (err == -ETIMEDOUT) diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c index 2560734..89ba21a 100644 --- a/nptl/pthread_rwlock_common.c +++ b/nptl/pthread_rwlock_common.c @@ -319,7 +319,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, { int private = __pthread_rwlock_get_private (rwlock); int err = futex_abstimed_wait (&rwlock->__data.__readers, - r, abstime, private); + r, CLOCK_REALTIME, abstime, private); /* We ignore EAGAIN and EINTR. On time-outs, we can just return because we don't need to clean up anything. */ if (err == ETIMEDOUT) @@ -447,7 +447,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, continue; int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, 1 | PTHREAD_RWLOCK_FUTEX_USED, - abstime, private); + CLOCK_REALTIME, abstime, private); if (err == ETIMEDOUT) { /* If we timed out, we need to unregister. If no read phase @@ -707,7 +707,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, may_share_futex_used_flag = true; int err = futex_abstimed_wait (&rwlock->__data.__writers_futex, 1 | PTHREAD_RWLOCK_FUTEX_USED, - abstime, private); + CLOCK_REALTIME, abstime, private); if (err == ETIMEDOUT) { if (prefer_writer) @@ -806,7 +806,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, continue; int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, PTHREAD_RWLOCK_FUTEX_USED, - abstime, private); + CLOCK_REALTIME, abstime, private); if (err == ETIMEDOUT) { if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c index 5646bea..425d040 100644 --- a/nptl/sem_waitcommon.c +++ b/nptl/sem_waitcommon.c @@ -109,11 +109,13 @@ do_futex_wait (struct new_sem *sem, const struct timespec *abstime) #if __HAVE_64B_ATOMICS err = futex_abstimed_wait_cancelable ( - (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, abstime, + (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, + CLOCK_REALTIME, abstime, sem->private); #else err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK, - abstime, sem->private); + CLOCK_REALTIME, abstime, + sem->private); #endif return err; diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h index 86a0818..54b7319 100644 --- a/sysdeps/nptl/futex-internal.h +++ b/sysdeps/nptl/futex-internal.h @@ -159,16 +159,23 @@ futex_reltimed_wait_cancelable (unsigned int* futex_word, unsigned int expected, const struct timespec* reltime, int private); +/* Check whether the specified clockid is supported by + futex_abstimed_wait and futex_abstimed_wait_cancelable. */ +static __always_inline int +futex_abstimed_supported_clockid (clockid_t clockid); + /* Like futex_reltimed_wait, but the provided timeout (ABSTIME) is an absolute point in time; a call will time out after this point in time. */ static __always_inline int futex_abstimed_wait (unsigned int* futex_word, unsigned int expected, + clockid_t clockid, const struct timespec* abstime, int private); /* Like futex_reltimed_wait but is a POSIX cancellation point. */ static __always_inline int futex_abstimed_wait_cancelable (unsigned int* futex_word, unsigned int expected, + clockid_t clockid, const struct timespec* abstime, int private); /* Atomically wrt other futex operations on the same futex, this unblocks the diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h index bb8effe..35fcfbb 100644 --- a/sysdeps/nptl/lowlevellock-futex.h +++ b/sysdeps/nptl/lowlevellock-futex.h @@ -43,11 +43,15 @@ #define lll_futex_timed_wait(futexp, val, timeout, private) \ -ENOSYS -/* This macro should be defined only if FUTEX_CLOCK_REALTIME is also defined. - If CLOCKBIT is zero, this is identical to lll_futex_timed_wait. - If CLOCKBIT has FUTEX_CLOCK_REALTIME set, then it's the same but - TIMEOUT is counted by CLOCK_REALTIME rather than CLOCK_MONOTONIC. */ -#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \ +/* Verify whether the supplied clockid is supported by + lll_futex_clock_wait_bitset */ +#define lll_futex_supported_clockid(clockid) \ + (0) + +/* Wait until a lll_futex_wake call on FUTEXP, or the absolute TIMEOUT + measured against CLOCKID elapses. CLOCKID may be CLOCK_REALTIME or + CLOCK_MONOTONIC. */ +#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \ -ENOSYS /* Wake up up to NR waiters on FUTEXP. */ diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h index 55f0fab..68bfe7e 100644 --- a/sysdeps/unix/sysv/linux/futex-internal.h +++ b/sysdeps/unix/sysv/linux/futex-internal.h @@ -162,15 +162,24 @@ futex_reltimed_wait_cancelable (unsigned int *futex_word, /* See sysdeps/nptl/futex-internal.h for details. */ static __always_inline int +futex_abstimed_supported_clockid (clockid_t clockid) +{ + return lll_futex_supported_clockid (clockid); +} + +/* See sysdeps/nptl/futex-internal.h for details. */ +static __always_inline int futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, + clockid_t clockid, const struct timespec *abstime, int private) { /* Work around the fact that the kernel rejects negative timeout values despite them being valid. */ if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0))) return ETIMEDOUT; - int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime, - FUTEX_CLOCK_REALTIME, private); + int err = lll_futex_clock_wait_bitset (futex_word, expected, + clockid, abstime, + private); switch (err) { case 0: @@ -180,9 +189,10 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, return -err; case -EFAULT: /* Must have been caused by a glibc or application bug. */ - case -EINVAL: /* Either due to wrong alignment or due to the timeout not - being normalized. Must have been caused by a glibc or - application bug. */ + case -EINVAL: /* Either due to wrong alignment, unsupported + clockid or due to the timeout not being + normalized. Must have been caused by a glibc or + application bug. */ case -ENOSYS: /* Must have been caused by a glibc bug. */ /* No other errors are documented at this time. */ default: @@ -194,6 +204,7 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected, static __always_inline int futex_abstimed_wait_cancelable (unsigned int *futex_word, unsigned int expected, + clockid_t clockid, const struct timespec *abstime, int private) { /* Work around the fact that the kernel rejects negative timeout values @@ -202,8 +213,9 @@ futex_abstimed_wait_cancelable (unsigned int *futex_word, return ETIMEDOUT; int oldtype; oldtype = __pthread_enable_asynccancel (); - int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime, - FUTEX_CLOCK_REALTIME, private); + int err = lll_futex_clock_wait_bitset (futex_word, expected, + clockid, abstime, + private); __pthread_disable_asynccancel (oldtype); switch (err) { diff --git a/sysdeps/unix/sysv/linux/lowlevellock-futex.h b/sysdeps/unix/sysv/linux/lowlevellock-futex.h index 6f060b1..c3e7152 100644 --- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h +++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h @@ -82,12 +82,29 @@ __lll_private_flag (FUTEX_WAIT, private), \ val, timeout) -#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \ - lll_futex_syscall (6, futexp, \ - __lll_private_flag (FUTEX_WAIT_BITSET | (clockbit), \ - private), \ - val, timeout, NULL /* Unused. */, \ - FUTEX_BITSET_MATCH_ANY) +/* Verify whether the supplied clockid is supported by + lll_futex_clock_wait_bitset */ +#define lll_futex_supported_clockid(clockid) \ + (clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC) + +/* The kernel currently only supports CLOCK_MONOTONIC or + * CLOCK_REALTIME timeouts for FUTEX_WAIT_BITSET. We could attempt to + * convert others here but currently do not. + */ +#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \ + ({ \ + long int __ret; \ + if (lll_futex_supported_clockid (clockid)) { \ + const unsigned int clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; \ + __ret = lll_futex_syscall (6, futexp, \ + __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, \ + private), \ + val, timeout, NULL /* Unused. */, \ + FUTEX_BITSET_MATCH_ANY); \ + } else \ + __ret = -EINVAL; \ + __ret; \ + }) #define lll_futex_wake(futexp, nr, private) \ lll_futex_syscall (4, futexp, \