diff options
| author | Mike Crowe <mac@mcrowe.com> | 2019-06-21 17:36:56 +0000 |
|---|---|---|
| committer | Adhemerval Zanella <adhemerval.zanella@linaro.org> | 2019-07-12 13:36:24 +0000 |
| commit | afe4de7d283ebd88157126c5494ce1796194c16e (patch) | |
| tree | 8b170b34eee52377b2a13e9856dac3c888e721e7 | |
| parent | 6615f77978bd12f06157fae8d4523b3ec475062b (diff) | |
| download | glibc-afe4de7d283ebd88157126c5494ce1796194c16e.tar.xz glibc-afe4de7d283ebd88157126c5494ce1796194c16e.zip | |
nptl: Add POSIX-proposed pthread_cond_clockwait
Add:
int pthread_cond_clockwait (pthread_cond_t *cond,
pthread_mutex_t *mutex,
clockid_t clockid,
const struct timespec *abstime)
which behaves just like pthread_cond_timedwait except it always measures
abstime against the supplied clockid. Currently supports CLOCK_REALTIME
and
CLOCK_MONOTONIC and returns EINVAL if any other clock is specified.
Includes feedback from many others. This function was originally
proposed[1] as pthread_cond_timedwaitonclock_np, but The Austin Group
preferred the new name.
* nptl/Makefile: Add tst-cond26 and tst-cond27
* nptl/Versions (GLIBC_2.30): Add pthread_cond_clockwait
* sysdeps/nptl/pthread.h: Likewise
* nptl/forward.c: Add __pthread_cond_clockwait
* nptl/forward.c: Likewise
* nptl/pthreadP.h: Likewise
* sysdeps/nptl/pthread-functions.h: Likewise
* nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Add
clockid parameter and comment describing why we don't need to
check
its value. Use that value when calling
futex_abstimed_wait_cancelable rather than reading the clock
from
the flags. (__pthread_cond_wait): Pass unused clockid parameter.
(__pthread_cond_timedwait): Read clock from flags and pass it to
__pthread_cond_wait_common. (__pthread_cond_clockwait): Add new
function with weak alias from pthread_cond_clockwait.
* sysdeps/mach/hurd/i386/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
* (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30):
* Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
(GLIBC_2.30): Likewise.
* nptl/tst-cond11.c (run_test): Support testing
pthread_cond_clockwait too by using a special magic
CLOCK_USE_ATTR_CLOCK value to determine whether to call
pthread_cond_timedwait or pthread_cond_clockwait. (do_test):
Pass
CLOCK_USE_ATTR_CLOCK for existing tests, and add new tests using
all combinations of CLOCK_MONOTONIC and CLOCK_REALTIME.
* ntpl/tst-cond26.c: New test for passing unsupported and
* invalid
clocks to pthread_cond_clockwait.
* nptl/tst-cond27.c: Add test similar to tst-cond5.c, but using
struct timespec and pthread_cond_clockwait.
* manual/threads.texi: Document pthread_cond_clockwait. The
* comment
was provided by Carlos O'Donell.
[1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
37 files changed, 353 insertions, 18 deletions
@@ -1,5 +1,74 @@ 2019-07-12 Mike Crowe <mac@mcrowe.com> + nptl: Add POSIX-proposed pthread_cond_clockwait which behaves just + like pthread_cond_timedwait except it always measures abstime + against the supplied clockid. + * nptl/Makefile: Add tst-cond26 and tst-cond27 + * nptl/Versions (GLIBC_2.30): Add pthread_cond_clockwait + * sysdeps/nptl/pthread.h: Likewise + * nptl/forward.c: Add __pthread_cond_clockwait + * nptl/forward.c: Likewise + * nptl/pthreadP.h: Likewise + * sysdeps/nptl/pthread-functions.h: Likewise + * nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Add + clockid parameter and comment describing why we don't need to check + its value. Use that value when calling + futex_abstimed_wait_cancelable rather than reading the clock from + the flags. (__pthread_cond_wait): Pass unused clockid parameter. + (__pthread_cond_timedwait): Read clock from flags and pass it to + __pthread_cond_wait_common. (__pthread_cond_clockwait): Add new + function with weak alias from pthread_cond_clockwait. + * sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/microblaze/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist + (GLIBC_2.30): Likewise. + * sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist + (GLIBC_2.30): Likewise. + * nptl/tst-cond11.c (run_test): Support testing + pthread_cond_clockwait too by using a special magic + CLOCK_USE_ATTR_CLOCK value to determine whether to call + pthread_cond_timedwait or pthread_cond_clockwait. (do_test): Pass + CLOCK_USE_ATTR_CLOCK for existing tests, and add new tests using + all combinations of CLOCK_MONOTONIC and CLOCK_REALTIME. + * ntpl/tst-cond26.c: New test for passing unsupported and invalid + clocks to pthread_cond_clockwait. + * nptl/tst-cond27.c: Add test similar to tst-cond5.c, but using + struct timespec and pthread_cond_clockwait. + * manual/threads.texi: Document pthread_cond_clockwait. + nptl: Add POSIX-proposed sem_clockwait which behaves just like sem_timedwait, but measures abstime against the specified clock. * nptl/sem_waitcommon.c (do_futex_wait, __new_sem_wait_slow): Add diff --git a/manual/threads.texi b/manual/threads.texi index 0192eecf25..78a86af4de 100644 --- a/manual/threads.texi +++ b/manual/threads.texi @@ -679,6 +679,26 @@ against the clock specified by @var{clockid} rather than @code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}. @end deftypefun +@comment pthread.h +@comment POSIX-proposed +@deftypefun int pthread_cond_clockwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, + clockid_t @var{clockid}, const struct timespec *@var{abstime}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} +@c If exactly the same function with arguments is called from a signal +@c handler that interrupts between the mutex unlock and sleep then it +@c will unlock the mutex twice resulting in undefined behaviour. Keep +@c in mind that the unlock and sleep are only atomic with respect to other +@c threads (really a happens-after relationship for pthread_cond_broadcast +@c and pthread_cond_signal). +@c In the AC case we would cancel the thread and the mutex would remain +@c locked and we can't recover from that. +Behaves like @code{pthread_cond_timedwait} except the time @var{abstime} is +measured against the clock specified by @var{clockid} rather than the clock +specified or defaulted when @code{pthread_cond_init} was called. Currently, +@var{clockid} must be either @code{CLOCK_MONOTONIC} or +@code{CLOCK_REALTIME}. +@end deftypefun + @c FIXME these are undocumented: @c pthread_atfork @c pthread_attr_destroy diff --git a/nptl/Makefile b/nptl/Makefile index fefdeb3be4..76bfd89e23 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -251,6 +251,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \ tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond25 \ + tst-cond26 tst-cond27 \ tst-cond-except \ tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \ tst-robust6 tst-robust7 tst-robust8 tst-robust9 \ diff --git a/nptl/Versions b/nptl/Versions index 4f0e837507..3ab0ae596d 100644 --- a/nptl/Versions +++ b/nptl/Versions @@ -277,7 +277,7 @@ libpthread { } GLIBC_2.30 { - sem_clockwait; + sem_clockwait; pthread_cond_clockwait; } GLIBC_PRIVATE { diff --git a/nptl/forward.c b/nptl/forward.c index ed1e7d0350..50f358f2b1 100644 --- a/nptl/forward.c +++ b/nptl/forward.c @@ -164,6 +164,11 @@ FORWARD (__pthread_cond_timedwait, const struct timespec *abstime), (cond, mutex, abstime), 0) versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait, GLIBC_2_3_2); +FORWARD (__pthread_cond_clockwait, + (pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid, + const struct timespec *abstime), (cond, mutex, clockid, abstime), + 0) +weak_alias (__pthread_cond_clockwait, pthread_cond_clockwait); FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2), diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c index 73935f8be4..9c2a3d735c 100644 --- a/nptl/nptl-init.c +++ b/nptl/nptl-init.c @@ -95,6 +95,7 @@ static const struct pthread_functions pthread_functions = .ptr___pthread_cond_signal = __pthread_cond_signal, .ptr___pthread_cond_wait = __pthread_cond_wait, .ptr___pthread_cond_timedwait = __pthread_cond_timedwait, + .ptr___pthread_cond_clockwait = __pthread_cond_clockwait, # if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0, .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0, diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index 66527d8f2d..d80662ab07 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -449,6 +449,11 @@ extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); extern int __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); +extern int __pthread_cond_clockwait (pthread_cond_t *cond, + pthread_mutex_t *mutex, + clockid_t clockid, + const struct timespec *abstime) + __nonnull ((1, 2, 4)); extern int __pthread_condattr_destroy (pthread_condattr_t *attr); extern int __pthread_condattr_init (pthread_condattr_t *attr); extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *)); diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c index 7385562f57..558f930cd2 100644 --- a/nptl/pthread_cond_wait.c +++ b/nptl/pthread_cond_wait.c @@ -378,6 +378,7 @@ __condvar_cleanup_waiting (void *arg) */ static __always_inline int __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + clockid_t clockid, const struct timespec *abstime) { const int maxspin = 0; @@ -386,6 +387,11 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, LIBC_PROBE (cond_wait, 2, cond, mutex); + /* clockid will already have been checked by + __pthread_cond_clockwait or pthread_condattr_setclock, or we + don't use it if abstime is NULL, so we don't need to check it + here. */ + /* Acquire a position (SEQ) in the waiter sequence (WSEQ). We use an atomic operation because signals and broadcasts may update the group switch without acquiring the mutex. We do not need release MO here @@ -511,10 +517,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, err = ETIMEDOUT; else { - const clockid_t clockid = - ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0) ? - CLOCK_MONOTONIC : CLOCK_REALTIME; - err = futex_abstimed_wait_cancelable (cond->__data.__g_signals + g, 0, clockid, abstime, private); @@ -632,7 +634,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) { - return __pthread_cond_wait_common (cond, mutex, NULL); + /* clockid is unused when abstime is NULL. */ + return __pthread_cond_wait_common (cond, mutex, 0, NULL); } /* See __pthread_cond_wait_common. */ @@ -644,10 +647,39 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, it can assume that abstime is not NULL. */ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) return EINVAL; - return __pthread_cond_wait_common (cond, mutex, abstime); + + /* Relaxed MO is suffice because clock ID bit is only modified + in condition creation. */ + unsigned int flags = atomic_load_relaxed (&cond->__data.__wrefs); + clockid_t clockid = (flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) + ? CLOCK_MONOTONIC : CLOCK_REALTIME; + return __pthread_cond_wait_common (cond, mutex, clockid, abstime); +} + +/* See __pthread_cond_wait_common. */ +int +__pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + clockid_t clockid, + const struct timespec *abstime) +{ + /* Check parameter validity. This should also tell the compiler that + it can assume that abstime is not NULL. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + if (!futex_abstimed_supported_clockid (clockid)) + return EINVAL; + + /* If we do not support waiting using CLOCK_MONOTONIC, return an |
