From 868013be85d11b45c037c56e5b148319168e9458 Mon Sep 17 00:00:00 2001 From: xuhuijie <546391727@qq.com> Date: Wed, 21 Apr 2021 16:44:24 +0800 Subject: [PATCH] nptl: Add POSIX-proposed pthread_cond_clockwait (cherry picked from commit 407544687c2dae5a89a807a7b77e0f11afa44bd2) --- ...-parameter-to-futex-timed-wait-calls.patch | 390 ++++++++++ ...-0002-support-Add-timespec.h-xtime.h.patch | 455 +++++++++++ ...OSIX-proposed-pthread_cond_clockwait.patch | 713 ++++++++++++++++++ glibc.spec | 10 +- 4 files changed, 1566 insertions(+), 2 deletions(-) create mode 100644 backport-0001-nptl-Add-clockid-parameter-to-futex-timed-wait-calls.patch create mode 100644 backport-0002-support-Add-timespec.h-xtime.h.patch create mode 100644 backport-0003-nptl-Add-POSIX-proposed-pthread_cond_clockwait.patch diff --git a/backport-0001-nptl-Add-clockid-parameter-to-futex-timed-wait-calls.patch b/backport-0001-nptl-Add-clockid-parameter-to-futex-timed-wait-calls.patch new file mode 100644 index 0000000..0128c4e --- /dev/null +++ b/backport-0001-nptl-Add-clockid-parameter-to-futex-timed-wait-calls.patch @@ -0,0 +1,390 @@ +From 99d01ffcc386d1bfb681fb0684fcf6a6a996beb3 Mon Sep 17 00:00:00 2001 +From: Mike Crowe +Date: Fri, 21 Jun 2019 14:53:40 +0000 +Subject: [PATCH] nptl: Add clockid parameter to futex timed wait calls + +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): Remove + code to calculate relative timeout for + __PTHREAD_COND_CLOCK_MONOTONIC_MASK and just pass CLOCK_MONOTONIC + or CLOCK_REALTIME as required to futex_abstimed_wait_cancelable. + * 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 + +Reviewed-by: Adhemerval Zanella +--- + ChangeLog | 33 ++++++++++++++++++++ + nptl/pthread_cond_wait.c | 32 ++++--------------- + nptl/pthread_mutex_timedlock.c | 4 +-- + nptl/pthread_rwlock_common.c | 8 ++--- + nptl/sem_waitcommon.c | 6 ++-- + sysdeps/nptl/futex-internal.h | 9 +++++- + sysdeps/nptl/lowlevellock-futex.h | 14 ++++++--- + sysdeps/unix/sysv/linux/futex-internal.h | 24 ++++++++++---- + sysdeps/unix/sysv/linux/lowlevellock-futex.h | 32 +++++++++++++++---- + 9 files changed, 110 insertions(+), 52 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index 24a97096..1f8cf24f 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,36 @@ ++2019-07-12 Mike Crowe ++ ++ nptl: Add clockid parameter to futex timed wait calls ++ * 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): Remove ++ code to calculate relative timeout for ++ __PTHREAD_COND_CLOCK_MONOTONIC_MASK and just pass CLOCK_MONOTONIC ++ or CLOCK_REALTIME as required to futex_abstimed_wait_cancelable. ++ * 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 ++ + 2019-04-23 Adhemerval Zanella + + [BZ #18035] +diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c +index 3e110541..3294fa3a 100644 +--- a/nptl/pthread_cond_wait.c ++++ b/nptl/pthread_cond_wait.c +@@ -509,35 +509,15 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex, + values despite them being valid. */ + if (__glibc_unlikely (abstime->tv_sec < 0)) + err = ETIMEDOUT; +- +- else if ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0) +- { +- /* CLOCK_MONOTONIC is requested. */ +- struct timespec rt; +- if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0) +- __libc_fatal ("clock_gettime does not support " +- "CLOCK_MONOTONIC"); +- /* Convert the absolute timeout value to a relative +- timeout. */ +- rt.tv_sec = abstime->tv_sec - rt.tv_sec; +- rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec; +- if (rt.tv_nsec < 0) +- { +- rt.tv_nsec += 1000000000; +- --rt.tv_sec; +- } +- /* Did we already time out? */ +- if (__glibc_unlikely (rt.tv_sec < 0)) +- err = ETIMEDOUT; +- else +- err = futex_reltimed_wait_cancelable +- (cond->__data.__g_signals + g, 0, &rt, private); +- } + else + { +- /* Use CLOCK_REALTIME. */ ++ 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, abstime, private); ++ (cond->__data.__g_signals + g, 0, clockid, abstime, ++ private); + } + } + +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index 888c12fe..46fcf8d8 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -292,8 +292,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + 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 597a8532..1918f7c9 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) +@@ -444,7 +444,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)) + continue; + int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, +- 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ 1 | PTHREAD_RWLOCK_FUTEX_USED, CLOCK_REALTIME, abstime, private); + if (err == ETIMEDOUT) + { + /* If we timed out, we need to unregister. If no read phase +@@ -704,7 +704,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + in this group. */ + may_share_futex_used_flag = true; + int err = futex_abstimed_wait (&rwlock->__data.__writers_futex, +- 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ 1 | PTHREAD_RWLOCK_FUTEX_USED, CLOCK_REALTIME, abstime, private); + if (err == ETIMEDOUT) + { + if (prefer_writer) +@@ -801,7 +801,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, + PTHREAD_RWLOCK_FUTEX_USED)) + continue; + int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, +- PTHREAD_RWLOCK_FUTEX_USED, abstime, private); ++ PTHREAD_RWLOCK_FUTEX_USED, CLOCK_REALTIME, abstime, private); + if (err == ETIMEDOUT) + { + if (rwlock->__data.__flags +diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c +index 30984be2..1811a32c 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 1a562478..353fdfb9 100644 +--- a/sysdeps/nptl/futex-internal.h ++++ b/sysdeps/nptl/futex-internal.h +@@ -49,7 +49,7 @@ + futex word. + + Both absolute and relative timeouts can be used. An absolute timeout +- expires when the given specific point in time on the CLOCK_REALTIME clock ++ expires when the given specific point in time on the specified clock + passes, or when it already has passed. A relative timeout expires when + the given duration of time on the CLOCK_MONOTONIC clock passes. Relative + timeouts may be imprecise (see futex_supports_exact_relative_timeouts). +@@ -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 27b81b83..68ce7516 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 96a07b05..8023cb85 100644 +--- a/sysdeps/unix/sysv/linux/futex-internal.h ++++ b/sysdeps/unix/sysv/linux/futex-internal.h +@@ -160,17 +160,26 @@ 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,8 +189,9 @@ 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 ++ 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. */ +@@ -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 fc834ed1..337faf1e 100644 +--- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h ++++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h +@@ -82,12 +82,32 @@ + __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; \ ++ const int op = \ ++ __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, private); \ ++ \ ++ __ret = lll_futex_syscall (6, futexp, op, val, \ ++ timeout, NULL /* Unused. */, \ ++ FUTEX_BITSET_MATCH_ANY); \ ++ } \ ++ else \ ++ __ret = -EINVAL; \ ++ __ret; \ ++ }) + + #define lll_futex_wake(futexp, nr, private) \ + lll_futex_syscall (4, futexp, \ +-- +2.23.0 + diff --git a/backport-0002-support-Add-timespec.h-xtime.h.patch b/backport-0002-support-Add-timespec.h-xtime.h.patch new file mode 100644 index 0000000..32c7728 --- /dev/null +++ b/backport-0002-support-Add-timespec.h-xtime.h.patch @@ -0,0 +1,455 @@ +From 519839965197291924895a3988804e325035beee Mon Sep 17 00:00:00 2001 +From: Mike Crowe +Date: Thu, 9 May 2019 14:19:21 -0300 +Subject: [PATCH] support: Add timespec.h xtime.h Add xclock_gettime + +It adds useful functions for tests that use struct timespec. + +Checked on x86_64-linux-gnu and i686-linux-gnu. + + * support/timespec.h: New file. Provide timespec helper functions + along with macros in the style of those in check.h. + * support/timespec.c: New file. Implement check functions declared + in support/timespec.h. + * support/timespec-add.c: New file from gnulib containing + timespec_add implementation that handles overflow. + * support/timespec-sub.c: New file from gnulib containing + timespec_sub implementation that handles overflow. + * support/xclock_gettime.c (xclock_gettime): New file. Provide + clock_gettime wrapper for use in tests that fails the test rather + than returning failure. + * support/xtime.h: New file to declare xclock_gettime. + * support/Makefile: Add xclock_gettime.c timespec.c timespec-add.c timespec-sub.c. + +Reviewed-by: Adhemerval Zanella +--- + support/Makefile | 4 ++ + support/timespec-add.c | 71 ++++++++++++++++++++++++++++++++++++ + support/timespec-sub.c | 71 ++++++++++++++++++++++++++++++++++++ + support/timespec.c | 59 ++++++++++++++++++++++++++++++ + support/timespec.h | 79 ++++++++++++++++++++++++++++++++++++++++ + support/xclock_gettime.c | 31 ++++++++++++++++ + support/xtime.h | 43 ++++++++++++++++++++++ + 7 files changed, 358 insertions(+) + create mode 100644 support/timespec-add.c + create mode 100644 support/timespec-sub.c + create mode 100644 support/timespec.c + create mode 100644 support/timespec.h + create mode 100644 support/xclock_gettime.c + create mode 100644 support/xtime.h + +diff --git a/support/Makefile b/support/Makefile +index 9bc68583..90c10bac 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -65,6 +65,9 @@ libsupport-routines = \ + support_test_main \ + support_test_verify_impl \ + temp_file \ ++ timespec \ ++ timespec-add \ ++ timespec-sub \ + write_message \ + xaccept \ + xaccept4 \ +@@ -72,6 +75,7 @@ libsupport-routines = \ + xbind \ + xcalloc \ + xchroot \ ++ xclock_gettime \ + xclose \ + xconnect \ + xdlfcn \ +diff --git a/support/timespec-add.c b/support/timespec-add.c +new file mode 100644 +index 00000000..f26abce1 +--- /dev/null ++++ b/support/timespec-add.c +@@ -0,0 +1,71 @@ ++/* Add two struct timespec values. ++ Copyright (C) 2011-2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Return the sum of two timespec values A and B. On overflow, return ++ an extremal value. This assumes 0 <= tv_nsec < TIMESPEC_HZ. */ ++ ++#include ++#include "timespec.h" ++ ++#include "intprops.h" ++ ++struct timespec ++timespec_add (struct timespec a, struct timespec b) ++{ ++ time_t rs = a.tv_sec; ++ time_t bs = b.tv_sec; ++ int ns = a.tv_nsec + b.tv_nsec; ++ int nsd = ns - TIMESPEC_HZ; ++ int rns = ns; ++ time_t tmin = TYPE_MINIMUM (time_t); ++ time_t tmax = TYPE_MAXIMUM (time_t); ++ ++ if (0 <= nsd) ++ { ++ rns = nsd; ++ if (bs < tmax) ++ bs++; ++ else if (rs < 0) ++ rs++; ++ else ++ goto high_overflow; ++ } ++ ++ /* INT_ADD_WRAPV is not appropriate since time_t might be unsigned. ++ In theory time_t might be narrower than int, so plain ++ INT_ADD_OVERFLOW does not suffice. */ ++ if (! INT_ADD_OVERFLOW (rs, bs) && tmin <= rs + bs && rs + bs <= tmax) ++ rs += bs; ++ else ++ { ++ if (rs < 0) ++ { ++ rs = tmin; ++ rns = 0; ++ } ++ else ++ { ++ high_overflow: ++ rs = tmax; ++ rns = TIMESPEC_HZ - 1; ++ } ++ } ++ ++ return make_timespec (rs, rns); ++} +diff --git a/support/timespec-sub.c b/support/timespec-sub.c +new file mode 100644 +index 00000000..7c33a59f +--- /dev/null ++++ b/support/timespec-sub.c +@@ -0,0 +1,71 @@ ++/* Subtract two struct timespec values. ++ Copyright (C) 2011-2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Return the difference between two timespec values A and B. On ++ overflow, return an extremal value. This assumes 0 <= tv_nsec < ++ TIMESPEC_HZ. */ ++ ++#include ++#include "timespec.h" ++ ++#include "intprops.h" ++ ++struct timespec ++timespec_sub (struct timespec a, struct timespec b) ++{ ++ time_t rs = a.tv_sec; ++ time_t bs = b.tv_sec; ++ int ns = a.tv_nsec - b.tv_nsec; ++ int rns = ns; ++ time_t tmin = TYPE_MINIMUM (time_t); ++ time_t tmax = TYPE_MAXIMUM (time_t); ++ ++ if (ns < 0) ++ { ++ rns = ns + TIMESPEC_HZ; ++ if (bs < tmax) ++ bs++; ++ else if (- TYPE_SIGNED (time_t) < rs) ++ rs--; ++ else ++ goto low_overflow; ++ } ++ ++ /* INT_SUBTRACT_WRAPV is not appropriate since time_t might be unsigned. ++ In theory time_t might be narrower than int, so plain ++ INT_SUBTRACT_OVERFLOW does not suffice. */ ++ if (! INT_SUBTRACT_OVERFLOW (rs, bs) && tmin <= rs - bs && rs - bs <= tmax) ++ rs -= bs; ++ else ++ { ++ if (rs < 0) ++ { ++ low_overflow: ++ rs = tmin; ++ rns = 0; ++ } ++ else ++ { ++ rs = tmax; ++ rns = TIMESPEC_HZ - 1; ++ } ++ } ++ ++ return make_timespec (rs, rns); ++} +diff --git a/support/timespec.c b/support/timespec.c +new file mode 100644 +index 00000000..0a1a13ff +--- /dev/null ++++ b/support/timespec.c +@@ -0,0 +1,59 @@ ++/* Support code for timespec checks. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++void ++test_timespec_before_impl (const char *file, int line, ++ const struct timespec left, ++ const struct timespec right) ++{ ++ if (left.tv_sec > right.tv_sec ++ || (left.tv_sec == right.tv_sec ++ && left.tv_nsec > right.tv_nsec)) { ++ support_record_failure (); ++ const struct timespec diff = timespec_sub (left, right); ++ printf ("%s:%d: %jd.%09jds not before %jd.%09jds " ++ "(difference %jd.%09jds)\n", ++ file, line, ++ (intmax_t) left.tv_sec, (intmax_t) left.tv_nsec, ++ (intmax_t) right.tv_sec, (intmax_t) right.tv_nsec, ++ (intmax_t) diff.tv_sec, (intmax_t) diff.tv_nsec); ++ } ++} ++ ++void ++test_timespec_equal_or_after_impl (const char *file, int line, ++ const struct timespec left, ++ const struct timespec right) ++{ ++ if (left.tv_sec < right.tv_sec ++ || (left.tv_sec == right.tv_sec ++ && left.tv_nsec < right.tv_nsec)) { ++ support_record_failure (); ++ const struct timespec diff = timespec_sub (right, left); ++ printf ("%s:%d: %jd.%09jds not after %jd.%09jds " ++ "(difference %jd.%09jds)\n", ++ file, line, ++ (intmax_t) left.tv_sec, (intmax_t) left.tv_nsec, ++ (intmax_t) right.tv_sec, (intmax_t) right.tv_nsec, ++ (intmax_t) diff.tv_sec, (intmax_t) diff.tv_nsec); ++ } ++} +diff --git a/support/timespec.h b/support/timespec.h +new file mode 100644 +index 00000000..cf2c0318 +--- /dev/null ++++ b/support/timespec.h +@@ -0,0 +1,79 @@ ++/* Useful functions for tests that use struct timespec. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef SUPPORT_TIMESPEC_H ++#define SUPPORT_TIMESPEC_H ++ ++#include ++#include ++#include ++#include ++ ++struct timespec timespec_add (struct timespec, struct timespec) ++ __attribute__((const)); ++struct timespec timespec_sub (struct timespec, struct timespec) ++ __attribute__((const)); ++ ++static inline struct timespec ++make_timespec (time_t s, long int ns) ++{ ++ struct timespec r; ++ r.tv_sec = s; ++ r.tv_nsec = ns; ++ return r; ++} ++ ++enum { TIMESPEC_HZ = 1000000000 }; ++ ++void test_timespec_before_impl (const char *file, int line, ++ const struct timespec left, ++ const struct timespec right); ++ ++void test_timespec_equal_or_after_impl (const char *file, int line, ++ const struct timespec left, ++ const struct timespec right); ++ ++/* Check that the timespec on the left represents a time before the ++ time on the right. */ ++#define TEST_TIMESPEC_BEFORE(left, right) \ ++ test_timespec_before_impl (__FILE__, __LINE__, (left), (right)) ++ ++#define TEST_TIMESPEC_BEFORE_NOW(left, clockid) \ ++ ({ \ ++ struct timespec now; \ ++ const int saved_errno = errno; \ ++ xclock_gettime ((clockid), &now); \ ++ TEST_TIMESPEC_BEFORE ((left), now); \ ++ errno = saved_errno; \ ++ }) ++ ++/* Check that the timespec on the left represents a time equal to or ++ after the time on the right. */ ++#define TEST_TIMESPEC_EQUAL_OR_AFTER(left, right) \ ++ test_timespec_equal_or_after_impl (__FILE__, __LINE__, left, right) ++ ++#define TEST_TIMESPEC_NOW_OR_AFTER(clockid, right) \ ++ ({ \ ++ struct timespec now; \ ++ const int saved_errno = errno; \ ++ xclock_gettime ((clockid), &now); \ ++ TEST_TIMESPEC_EQUAL_OR_AFTER (now, (right)); \ ++ errno = saved_errno; \ ++ }) ++ ++#endif /* SUPPORT_TIMESPEC_H */ +diff --git a/support/xclock_gettime.c b/support/xclock_gettime.c +new file mode 100644 +index 00000000..5dd3ae9b +--- /dev/null ++++ b/support/xclock_gettime.c +@@ -0,0 +1,31 @@ ++/* clock_gettime with error checking. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xclock_gettime (clockid_t clockid, ++ struct timespec *ts) ++{ ++ const int ret = clock_gettime (clockid, ts); ++ if (ret < 0) ++ FAIL_EXIT1 ("clock_gettime (%d): %m", ++ clockid); ++} +diff --git a/support/xtime.h b/support/xtime.h +new file mode 100644 +index 00000000..9e6df5b9 +--- /dev/null ++++ b/support/xtime.h +@@ -0,0 +1,43 @@ ++/* Support functionality for using time. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef SUPPORT_TIME_H ++#define SUPPORT_TIME_H ++ ++#include ++ ++__BEGIN_DECLS ++ ++/* The following functions call the corresponding libc functions and ++ terminate the process on error. */ ++ ++void xclock_gettime (clockid_t clock, struct timespec *ts); ++ ++/* This helper can often simplify tests by avoiding an explicit ++ variable declaration or allowing that declaration to be const. */ ++ ++static inline struct timespec xclock_now (clockid_t clock) ++{ ++ struct timespec ts; ++ xclock_gettime (clock, &ts); ++ return ts; ++} ++ ++__END_DECLS ++ ++#endif /* SUPPORT_TIME_H */ +-- +2.23.0 + diff --git a/backport-0003-nptl-Add-POSIX-proposed-pthread_cond_clockwait.patch b/backport-0003-nptl-Add-POSIX-proposed-pthread_cond_clockwait.patch new file mode 100644 index 0000000..dab152e --- /dev/null +++ b/backport-0003-nptl-Add-POSIX-proposed-pthread_cond_clockwait.patch @@ -0,0 +1,713 @@ +From afe4de7d283ebd88157126c5494ce1796194c16e Mon Sep 17 00:00:00 2001 +From: Mike Crowe +Date: Fri, 21 Jun 2019 17:36:56 +0000 +Subject: [PATCH] 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/pthreadP.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/x86_64/64/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. + +[1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html + +Reviewed-by: Adhemerval Zanella +--- + ChangeLog | 29 +++ + manual/threads.texi | 20 ++ + nptl/Makefile | 1 + + nptl/Versions | 1 + + nptl/pthreadP.h | 5 + + nptl/pthread_cond_wait.c | 44 ++++- + nptl/tst-cond11.c | 183 +++++------------- + nptl/tst-cond26.c | 77 ++++++++ + nptl/tst-cond27.c | 66 +++++++ + sysdeps/nptl/pthread.h | 15 ++ + .../sysv/linux/aarch64/libpthread.abilist | 1 + + .../sysv/linux/x86_64/64/libpthread.abilist | 1 + + 12 files changed, 305 insertions(+), 138 deletions(-) + create mode 100644 nptl/tst-cond26.c + create mode 100644 nptl/tst-cond27.c + +diff --git a/ChangeLog b/ChangeLog +index 1f8cf24f..8601e9fe 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,5 +1,34 @@ + 2019-07-12 Mike Crowe + ++ 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/pthreadP.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/x86_64/64/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 clockid parameter to futex timed wait calls + * sysdeps/nptl/lowlevellock-futex.h, + sysdeps/unix/sysv/linux/lowlevellock-futex.h: Replace +diff --git a/manual/threads.texi b/manual/threads.texi +index 87fda7d8..f4c5447c 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -669,6 +669,26 @@ The system does not have sufficient memory. + @end table + @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 fb68f238..6a9cd8fa 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -250,6 +250,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 e7f691da..94d6fa92 100644 +--- a/nptl/Versions ++++ b/nptl/Versions +@@ -275,6 +275,7 @@ libpthread { + mtx_init; mtx_lock; mtx_timedlock; mtx_trylock; mtx_unlock; mtx_destroy; + call_once; cnd_broadcast; cnd_destroy; cnd_init; cnd_signal; + cnd_timedwait; cnd_wait; tss_create; tss_delete; tss_get; tss_set; ++ pthread_cond_clockwait; + } + + GLIBC_PRIVATE { +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index 19efe1e3..67de9d8c 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -492,6 +492,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 3294fa3a..fec86698 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 error. */ ++ if (clockid == CLOCK_MONOTONIC ++ && !futex_supports_exact_relative_timeouts ()) ++ return EINVAL; ++ ++ return __pthread_cond_wait_common (cond, mutex, clockid, abstime); + } + + versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2); + versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2); ++weak_alias (__pthread_cond_clockwait, pthread_cond_clockwait); +diff --git a/nptl/tst-cond11.c b/nptl/tst-cond11.c +index eebc8ac5..16d937c4 100644 +--- a/nptl/tst-cond11.c ++++ b/nptl/tst-cond11.c +@@ -1,4 +1,4 @@ +-/* Copyright (C) 2003-2018 Free Software Foundation, Inc. ++/* Copyright (C) 2003-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2003. + +@@ -21,145 +21,64 @@ + #include + #include + #include ++#include ++#include ++#include ++#include ++#include + ++/* A bogus clock value that tells run_test to use pthread_cond_timedwait ++ rather than pthread_condclockwait. */ ++#define CLOCK_USE_ATTR_CLOCK (-1) + + #if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 + static int +-run_test (clockid_t cl) ++run_test (clockid_t attr_clock, clockid_t wait_clock) + { + pthread_condattr_t condattr; + pthread_cond_t cond; + pthread_mutexattr_t mutattr; + pthread_mutex_t mut; + +- printf ("clock = %d\n", (int) cl); ++ printf ("attr_clock = %d\n", (int) attr_clock); + +- if (pthread_condattr_init (&condattr) != 0) +- { +- puts ("condattr_init failed"); +- return 1; +- } ++ TEST_COMPARE (pthread_condattr_init (&condattr), 0); ++ TEST_COMPARE (pthread_condattr_setclock (&condattr, attr_clock), 0); + +- if (pthread_condattr_setclock (&condattr, cl) != 0) +- { +- puts ("condattr_setclock failed"); +- return 1; +- } ++ clockid_t attr_clock_read; ++ TEST_COMPARE (pthread_condattr_getclock (&condattr, &attr_clock_read), 0); ++ TEST_COMPARE (attr_clock, attr_clock_read); + +- clockid_t cl2; +- if (pthread_condattr_getclock (&condattr, &cl2) != 0) +- { +- puts ("condattr_getclock failed"); +- return 1; +- } +- if (cl != cl2) +- { +- printf ("condattr_getclock returned wrong value: %d, expected %d\n", +- (int) cl2, (int) cl); +- return 1; +- } ++ TEST_COMPARE (pthread_cond_init (&cond, &condattr), 0); ++ TEST_COMPARE (pthread_condattr_destroy (&condattr), 0); + +- if (pthread_cond_init (&cond, &condattr) != 0) +- { +- puts ("cond_init failed"); +- return 1; +- } ++ xpthread_mutexattr_init (&mutattr); ++ xpthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK); ++ xpthread_mutex_init (&mut, &mutattr); ++ xpthread_mutexattr_destroy (&mutattr); + +- if (pthread_condattr_destroy (&condattr) != 0) +- { +- puts ("condattr_destroy failed"); +- return 1; +- } +- +- if (pthread_mutexattr_init (&mutattr) != 0) +- { +- puts ("mutexattr_init failed"); +- return 1; +- } ++ xpthread_mutex_lock (&mut); ++ TEST_COMPARE (pthread_mutex_lock (&mut), EDEADLK); + +- if (pthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK) != 0) +- { +- puts ("mutexattr_settype failed"); +- return 1; +- } +- +- if (pthread_mutex_init (&mut, &mutattr) != 0) +- { +- puts ("mutex_init failed"); +- return 1; +- } +- +- if (pthread_mutexattr_destroy (&mutattr) != 0) +- { +- puts ("mutexattr_destroy failed"); +- return 1; +- } +- +- if (pthread_mutex_lock (&mut) != 0) +- { +- puts ("mutex_lock failed"); +- return 1; +- } +- +- if (pthread_mutex_lock (&mut) != EDEADLK) +- { +- puts ("2nd mutex_lock did not return EDEADLK"); +- return 1; +- } +- +- struct timespec ts; +- if (clock_gettime (cl, &ts) != 0) +- { +- puts ("clock_gettime failed"); +- return 1; +- } ++ struct timespec ts_timeout; ++ xclock_gettime (wait_clock == CLOCK_USE_ATTR_CLOCK ? attr_clock : wait_clock, ++ &ts_timeout); + + /* Wait one second. */ +- ++ts.tv_sec; +- +- int e = pthread_cond_timedwait (&cond, &mut, &ts); +- if (e == 0) +- { +- puts ("cond_timedwait succeeded"); +- return 1; +- } +- else if (e != ETIMEDOUT) +- { +- puts ("cond_timedwait did not return ETIMEDOUT"); +- return 1; +- } +- +- struct timespec ts2; +- if (clock_gettime (cl, &ts2) != 0) +- { +- puts ("second clock_gettime failed"); +- return 1; +- } +- +- if (ts2.tv_sec < ts.tv_sec +- || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec < ts.tv_nsec)) +- { +- puts ("timeout too short"); +- return 1; +- } ++ ++ts_timeout.tv_sec; + +- if (pthread_mutex_unlock (&mut) != 0) +- { +- puts ("mutex_unlock failed"); +- return 1; +- } ++ if (wait_clock == CLOCK_USE_ATTR_CLOCK) { ++ TEST_COMPARE (pthread_cond_timedwait (&cond, &mut, &ts_timeout), ETIMEDOUT); ++ TEST_TIMESPEC_BEFORE_NOW (ts_timeout, attr_clock); ++ } else { ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, wait_clock, &ts_timeout), ++ ETIMEDOUT); ++ TEST_TIMESPEC_BEFORE_NOW (ts_timeout, wait_clock); ++ } + +- if (pthread_mutex_destroy (&mut) != 0) +- { +- puts ("mutex_destroy failed"); +- return 1; +- } +- +- if (pthread_cond_destroy (&cond) != 0) +- { +- puts ("cond_destroy failed"); +- return 1; +- } ++ xpthread_mutex_unlock (&mut); ++ xpthread_mutex_destroy (&mut); ++ TEST_COMPARE (pthread_cond_destroy (&cond), 0); + + return 0; + } +@@ -171,12 +90,11 @@ do_test (void) + { + #if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1 + +- puts ("_POSIX_CLOCK_SELECTION not supported, test skipped"); +- return 0; ++ FAIL_UNSUPPORTED ("_POSIX_CLOCK_SELECTION not supported, test skipped"); + + #else + +- int res = run_test (CLOCK_REALTIME); ++ run_test (CLOCK_REALTIME, CLOCK_USE_ATTR_CLOCK); + + # if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0 + # if _POSIX_MONOTONIC_CLOCK == 0 +@@ -184,21 +102,22 @@ do_test (void) + if (e < 0) + puts ("CLOCK_MONOTONIC not supported"); + else if (e == 0) +- { +- puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0"); +- res = 1; +- } ++ FAIL_RET ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0"); + else ++ { + # endif +- res |= run_test (CLOCK_MONOTONIC); ++ run_test (CLOCK_MONOTONIC, CLOCK_USE_ATTR_CLOCK); ++ run_test (CLOCK_REALTIME, CLOCK_MONOTONIC); ++ run_test (CLOCK_MONOTONIC, CLOCK_MONOTONIC); ++ run_test (CLOCK_MONOTONIC, CLOCK_REALTIME); ++ } + # else + puts ("_POSIX_MONOTONIC_CLOCK not defined"); + # endif + +- return res; ++ return 0; + #endif + } + +-#define TIMEOUT 3 +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include ++ +diff --git a/nptl/tst-cond26.c b/nptl/tst-cond26.c +new file mode 100644 +index 00000000..bb4d6c9b +--- /dev/null ++++ b/nptl/tst-cond26.c +@@ -0,0 +1,77 @@ ++/* Test unsupported/bad clocks passed to pthread_cond_clockwait. ++ ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; ++static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; ++ ++#define NOT_A_VALID_CLOCK 123456 ++ ++static int ++do_test (void) ++{ ++ xpthread_mutex_lock (&mut); ++ ++ const struct timespec ts = make_timespec (0, 0); ++ ++ /* These clocks are meaningless to sem_clockwait. */ ++#if defined(CLOCK_PROCESS_CPUTIME_ID) ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ CLOCK_PROCESS_CPUTIME_ID, &ts), EINVAL); ++#endif ++#if defined(CLOCK_THREAD_CPUTIME_ID) ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ CLOCK_THREAD_CPUTIME_ID, &ts), EINVAL); ++#endif ++ ++ /* These clocks might be meaningful, but are currently unsupported ++ by pthread_cond_clockwait. */ ++#if defined(CLOCK_REALTIME_COARSE) ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ CLOCK_REALTIME_COARSE, &ts), EINVAL); ++#endif ++#if defined(CLOCK_MONOTONIC_RAW) ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ CLOCK_MONOTONIC_RAW, &ts), EINVAL); ++#endif ++#if defined(CLOCK_MONOTONIC_COARSE) ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ CLOCK_MONOTONIC_COARSE, &ts), EINVAL); ++#endif ++#if defined(CLOCK_BOOTTIME) ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ CLOCK_BOOTTIME, &ts), EINVAL); ++#endif ++ ++ /* This is a completely invalid clock. */ ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, ++ NOT_A_VALID_CLOCK, &ts), EINVAL); ++ ++ return 0; ++} ++ ++#include +diff --git a/nptl/tst-cond27.c b/nptl/tst-cond27.c +new file mode 100644 +index 00000000..ad9658af +--- /dev/null ++++ b/nptl/tst-cond27.c +@@ -0,0 +1,66 @@ ++/* Test pthread_cond_clockwait timeout. ++ ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; ++static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; ++ ++ ++static int ++do_test_clock (clockid_t clockid) ++{ ++ /* Get the mutex. */ ++ xpthread_mutex_lock (&mut); ++ ++ /* Waiting for the condition will fail. But we want the timeout here. */ ++ const struct timespec ts_now = xclock_now (clockid); ++ const struct timespec ts_timeout = ++ timespec_add (ts_now, make_timespec (0, 500000000)); ++ ++ /* In theory pthread_cond_clockwait could return zero here due to ++ spurious wakeup. However that can't happen without a signal or an ++ additional waiter. */ ++ TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, clockid, &ts_timeout), ++ ETIMEDOUT); ++ ++ xpthread_mutex_unlock (&mut); ++ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ do_test_clock (CLOCK_MONOTONIC); ++ do_test_clock (CLOCK_REALTIME); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index df049abf..7eb2decf 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -1003,6 +1003,21 @@ extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, + const struct timespec *__restrict __abstime) + __nonnull ((1, 2, 3)); + ++# ifdef __USE_GNU ++/* Wait for condition variable COND to be signaled or broadcast until ++ ABSTIME measured by the specified clock. MUTEX is assumed to be ++ locked before. CLOCK is the clock to use. ABSTIME is an absolute ++ time specification against CLOCK's epoch. ++ ++ This function is a cancellation point and therefore not marked with ++ __THROW. */ ++extern int pthread_cond_clockwait (pthread_cond_t *__restrict __cond, ++ pthread_mutex_t *__restrict __mutex, ++ __clockid_t __clock_id, ++ const struct timespec *__restrict __abstime) ++ __nonnull ((1, 2, 4)); ++# endif ++ + /* Functions for handling condition variable attributes. */ + + /* Initialize condition variable attribute ATTR. */ +diff --git a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist +index 9a9e4cee..cd9f09fa 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist +@@ -235,6 +235,7 @@ GLIBC_2.28 mtx_lock F + GLIBC_2.28 mtx_timedlock F + GLIBC_2.28 mtx_trylock F + GLIBC_2.28 mtx_unlock F ++GLIBC_2.28 pthread_cond_clockwait F + GLIBC_2.28 thrd_create F + GLIBC_2.28 thrd_detach F + GLIBC_2.28 thrd_exit F +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist +index 931c8277..8add10d7 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist ++++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist +@@ -211,6 +211,7 @@ GLIBC_2.28 mtx_lock F + GLIBC_2.28 mtx_timedlock F + GLIBC_2.28 mtx_trylock F + GLIBC_2.28 mtx_unlock F ++GLIBC_2.28 pthread_cond_clockwait F + GLIBC_2.28 thrd_create F + GLIBC_2.28 thrd_detach F + GLIBC_2.28 thrd_exit F +-- +2.23.0 + diff --git a/glibc.spec b/glibc.spec index f2030ec..ea151d9 100644 --- a/glibc.spec +++ b/glibc.spec @@ -59,7 +59,7 @@ ############################################################################## Name: glibc Version: 2.28 -Release: 64 +Release: 65 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ @@ -119,6 +119,9 @@ Patch35: backport-aarch64-revert-memcpy-optimze-for-kunpeng-to-avoid-p.patch Patch36: backport-elf-Allow-dlopen-of-filter-object-to-work-BZ-16272.patch Patch37: backport-elf-Fix-pldd-BZ-18035.patch Patch38: backport-CVE-2021-3326-gconv-Fix-assertion-failure-in-ISO-2022-JP-3-module-.patch +Patch39: backport-0001-nptl-Add-clockid-parameter-to-futex-timed-wait-calls.patch +Patch40: backport-0002-support-Add-timespec.h-xtime.h.patch +Patch41: backport-0003-nptl-Add-POSIX-proposed-pthread_cond_clockwait.patch Provides: ldconfig rtld(GNU_HASH) bundled(gnulib) @@ -1143,7 +1146,10 @@ fi %doc hesiod/README.hesiod %changelog -* Thu Mar 16 2021 zhujunhao - 2.28-64 +* Wed Apr 21 2021 xuhuijie - 2.28-65 +- Add POSIX-proposed pthread_cond_clockwait + +* Tue Mar 16 2021 zhujunhao - 2.28-64 - Replace openeuler by vendor * Mon Feb 8 2021 Wang Shuo - 2.28-63 -- Gitee