!134 [sync] PR-132: nptl: Add POSIX-proposed pthread_cond_clockwait

From: @openeuler-sync-bot
Reviewed-by: @liqingqing_1229
Signed-off-by: @liqingqing_1229
This commit is contained in:
openeuler-ci-bot 2021-04-27 20:27:14 +08:00 committed by Gitee
commit 9770e71816
4 changed files with 1566 additions and 2 deletions

View File

@ -0,0 +1,390 @@
From 99d01ffcc386d1bfb681fb0684fcf6a6a996beb3 Mon Sep 17 00:00:00 2001
From: Mike Crowe <mac@mcrowe.com>
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 <adhemerval.zanella@linaro.org>
---
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 <mac@mcrowe.com>
+
+ 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 <adhemerval.zanella@linaro.org>
[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

View File

@ -0,0 +1,455 @@
From 519839965197291924895a3988804e325035beee Mon Sep 17 00:00:00 2001
From: Mike Crowe <mac@mcrowe.com>
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 <adhemerval.zanella@linaro.org>
---
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
+ <http://www.gnu.org/licenses/>. */
+
+/* Return the sum of two timespec values A and B. On overflow, return
+ an extremal value. This assumes 0 <= tv_nsec < TIMESPEC_HZ. */
+
+#include <config.h>
+#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
+ <http://www.gnu.org/licenses/>. */
+
+/* Return the difference between two timespec values A and B. On
+ overflow, return an extremal value. This assumes 0 <= tv_nsec <
+ TIMESPEC_HZ. */
+
+#include <config.h>
+#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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/timespec.h>
+#include <stdio.h>
+#include <stdint.h>
+
+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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_TIMESPEC_H
+#define SUPPORT_TIMESPEC_H
+
+#include <stdio.h>
+#include <time.h>
+#include <support/check.h>
+#include <support/xtime.h>
+
+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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xtime.h>
+#include <support/xthread.h>
+
+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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef SUPPORT_TIME_H
+#define SUPPORT_TIME_H
+
+#include <time.h>
+
+__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

View File

@ -0,0 +1,713 @@
From afe4de7d283ebd88157126c5494ce1796194c16e Mon Sep 17 00:00:00 2001
From: Mike Crowe <mac@mcrowe.com>
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 <adhemerval.zanella@linaro.org>
---
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 <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/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 <drepper@redhat.com>, 2003.
@@ -21,145 +21,64 @@
#include <stdio.h>
#include <time.h>
#include <unistd.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <support/timespec.h>
+#include <support/xthread.h>
+#include <support/xtime.h>
+/* 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 <support/test-driver.c>
+
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <support/check.h>
+#include <support/timespec.h>
+#include <support/xthread.h>
+
+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 <support/test-driver.c>
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <support/check.h>
+#include <support/timespec.h>
+#include <support/xthread.h>
+
+
+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 <support/test-driver.c>
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

View File

@ -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<zhujunhao8@huawei.com> - 2.28-64
* Wed Apr 21 2021 xuhuijie<xuhuijie2@huawei.com> - 2.28-65
- Add POSIX-proposed pthread_cond_clockwait
* Tue Mar 16 2021 zhujunhao<zhujunhao8@huawei.com> - 2.28-64
- Replace openeuler by vendor
* Mon Feb 8 2021 Wang Shuo<wangshuo_1994@foxmail.com> - 2.28-63