From patchwork Wed Feb 27 18:23:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Crowe X-Patchwork-Id: 31628 Received: (qmail 50986 invoked by alias); 27 Feb 2019 18:27:17 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 50966 invoked by uid 89); 27 Feb 2019 18:27:17 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.6 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=counted, Wait X-HELO: avasout02.plus.net X-CM-Score: 0.00 From: Mike Crowe To: libc-alpha@sourceware.org Cc: Mike Crowe Subject: [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls Date: Wed, 27 Feb 2019 18:23:51 +0000 Message-Id: <93715d4ac59e160bf7ef244832d56b062b78e425.1551291557.git-series.mac@mcrowe.com> In-Reply-To: References: In-Reply-To: References: 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); } } 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, \