unofficial mirror of libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
@ 2019-02-27 18:23 Mike Crowe
  2019-02-27 18:23 ` [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls Mike Crowe
                   ` (8 more replies)
  0 siblings, 9 replies; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

My attempts[1] to add a variant of pthread_cond_timedwait that would accept
a clockid_t parameter led me to propose[2] to The Austin Group the addition
of an entire family of functions that accept a clockid_t parameter to
indicate the clock that the timespec absolute timeout parameter should be
measured against. They responded positively to the request but an
implementation is required before the proposal can proceed.

This patch series is the first part of that implementation in glibc, it
contains four new functions:

int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
                           clockid_t clock, const struct timespec *abstime)

int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clock,
                               const struct timespec *abstime)

int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clock,
                               const struct timespec *abstime)

int sem_clockwait(sem_t *restrict, clockid_t clock_id, const struct
                  timespec *restrict)

These are implemented by replacing the underlying equivalent _timed
functions with ones that accept a clockid_t parameter, and then
implementing the existing _timed functions by passing CLOCK_REALTIME to the
new implementation. This requires clockid_t parameters to be added to the
underlying futex-internal and lowlevellock-futex functions.

pthread_mutex_clocklock is not yet implemented because doing so requires a
version of __lll_timedlock_wait that supports both CLOCK_MONOTONIC and
CLOCK_REALTIME. This function is currently architecture specific. I plan to
work on that next, if these changes are considered acceptable.

The mq_clockreceive and mq_clocksend functions corresponding to
mq_timedreceive and mq_timedsend require kernel changes before they can be
implemented in glibc.

As implemented, passing an unsupported or invalid clock to these functions
yields EINVAL. I considered returning ENOTSUP for valid-but-unsupported
clocks, but I was worried that there was a risk that the list of valid
clocks would not be updated when a new clock was added to glibc.

A number of tests have been updated to use struct timespec rather than
struct timeval so that they can call clock_gettime(CLOCK_MONOTONIC) rather
then gettimeofday. To make this easier I created the support/timespec.h
header file to contain functions to add and subtract timespec structures
borrowed from sysdeps/pthread/posix-timer.h. There's probably a better
place for these, but I don't know where that might be.

Rather than duplicating tests, I've parameterised them so that the same
tests can be run on the existing timedwait functions and the new clockwait
functions.

The changes have been tested with "make check" on x86_64 and arm64. Earlier
versions were tested on arm. I haven't updated the ChangeLog, NEWS or
architecture abilists yet (so some tests fail on arm64), but will do so if
the rest of the changes are acceptable.

Thanks to everyone that commented on previous versions of this patch (when
the single new function was called pthread_cond_timedwaitonclock_np.) They
have been a great help, and I hope that I have incorporated their feedback
correctly.

[1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
[2] http://austingroupbugs.net/view.php?id=1216

Mike Crowe (7):
  nptl: Add clockid parameter to futex timed wait calls
  nptl: Add POSIX-proposed sem_clockwait
  nptl: Add POSIX-proposed pthread_cond_clockwait
  nptl: pthread_rwlock: Move timeout validation into _full functions
  nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly
  nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval
  nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock

 conform/data/semaphore.h-data                        |   1 +-
 manual/threads.texi                                  |  58 ++++-
 nptl/Makefile                                        |   8 +-
 nptl/Versions                                        |   5 +-
 nptl/forward.c                                       |   5 +-
 nptl/nptl-init.c                                     |   1 +-
 nptl/pthreadP.h                                      |   4 +-
 nptl/pthread_cond_wait.c                             |  45 ++-
 nptl/pthread_mutex_timedlock.c                       |   8 +-
 nptl/pthread_rwlock_clockrdlock.c                    |  27 ++-
 nptl/pthread_rwlock_clockwrlock.c                    |  27 ++-
 nptl/pthread_rwlock_common.c                         |  32 +-
 nptl/pthread_rwlock_rdlock.c                         |   2 +-
 nptl/pthread_rwlock_timedrdlock.c                    |  12 +-
 nptl/pthread_rwlock_timedwrlock.c                    |  12 +-
 nptl/pthread_rwlock_wrlock.c                         |   2 +-
 nptl/sem_clockwait.c                                 |  45 +++-
 nptl/sem_timedwait.c                                 |   3 +-
 nptl/sem_wait.c                                      |   3 +-
 nptl/sem_waitcommon.c                                |  15 +-
 nptl/tst-abstime.c                                   |  28 ++-
 nptl/tst-cond11.c                                    |  30 +-
 nptl/tst-cond26.c                                    |  91 +++++++-
 nptl/tst-cond27.c                                    | 113 +++++++++-
 nptl/tst-rwlock14.c                                  | 159 +++++++++++-
 nptl/tst-rwlock6.c                                   | 132 ++++++----
 nptl/tst-rwlock7.c                                   | 108 +++++---
 nptl/tst-rwlock9.c                                   |  90 +++++--
 nptl/tst-sem13.c                                     |  50 +++-
 nptl/tst-sem17.c                                     |  57 ++++-
 nptl/tst-sem5.c                                      |  30 +-
 support/timespec.h                                   |  27 ++-
 sysdeps/nptl/futex-internal.h                        |   7 +-
 sysdeps/nptl/lowlevellock-futex.h                    |  14 +-
 sysdeps/nptl/pthread-functions.h                     |   4 +-
 sysdeps/nptl/pthread.h                               |  21 ++-
 sysdeps/pthread/semaphore.h                          |   4 +-
 sysdeps/unix/sysv/linux/futex-internal.h             |  26 +-
 sysdeps/unix/sysv/linux/lowlevellock-futex.h         |  29 +-
 sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   4 +-
 40 files changed, 1124 insertions(+), 215 deletions(-)
 create mode 100644 nptl/pthread_rwlock_clockrdlock.c
 create mode 100644 nptl/pthread_rwlock_clockwrlock.c
 create mode 100644 nptl/sem_clockwait.c
 create mode 100644 nptl/tst-cond26.c
 create mode 100644 nptl/tst-cond27.c
 create mode 100644 nptl/tst-sem17.c
 create mode 100644 support/timespec.h

base-commit: a04549c19407a29a271779598a9518f9baf959e0
-- 
git-series 0.9.1

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-03-05 12:39   ` Adhemerval Zanella
  2019-02-27 18:23 ` [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Mike Crowe
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

In preparation for adding POSIX clockwait variants of timedwait functions,
add a clockid_t parameter to futex_abstimed_wait functions and pass
CLOCK_REALTIME from all callers for the time being.

Replace lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset which
takes a clockid_t parameter rather than the magic clockbit.

* sysdeps/nptl/lowlevellock-futex.h,
  sysdeps/unix/sysv/linux/lowlevellock-futex.h: Replace
  lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset that takes a
  clockid rather than a special clockbit.

* sysdeps/nptl/lowlevellock-futex.h: Add lll_futex_supported_clockid so
  that client functions can check whether their clockid parameter is valid
  even if they don't ultimately end up calling lll_futex_clock_wait_bitset.

* sysdeps/nptl/futex-internal.h, sysdeps/unix/sysv/linux/futex-internal.h
  (futex_abstimed_wait, futex_abstimed_wait_cancelable): Add clockid_t
  parameter to indicate which clock the absolute time passed should be
  measured against. Pass that clockid onto lll_futex_clock_wait_bitset.
  Add invalid clock as reason for returning -EINVAL.

* sysdeps/nptl/futex-internal.h, sysdeps/unix/sysv/linux/futex-internal.h:
  Introduce futex_abstimed_supported_clockid so that client functions can
  check whether their clockid parameter is valid even if they don't
  ultimately end up calling futex_abstimed_wait.

* nptl/pthread_cond_wait.c (__pthread_cond_wait_common),
  nptl/pthread_rwlock_common (__pthread_rwlock_rdlock_full,
  __pthread_wrlock_full), nptl/sem_waitcommon (do_futex_wait): Pass
  additional CLOCK_REALTIME to futex_abstimed_wait_cancelable.

* nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Switch to
  lll_futex_clock_wait_bitset and pass CLOCK_REALTIME
---
 nptl/pthread_cond_wait.c                     |  2 +-
 nptl/pthread_mutex_timedlock.c               |  8 +++---
 nptl/pthread_rwlock_common.c                 |  8 +++---
 nptl/sem_waitcommon.c                        |  6 ++--
 sysdeps/nptl/futex-internal.h                |  7 +++++-
 sysdeps/nptl/lowlevellock-futex.h            | 14 ++++++----
 sysdeps/unix/sysv/linux/futex-internal.h     | 26 +++++++++++++------
 sysdeps/unix/sysv/linux/lowlevellock-futex.h | 29 ++++++++++++++++-----
 8 files changed, 71 insertions(+), 29 deletions(-)

diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
index 9a0f29e..daa4e25 100644
--- a/nptl/pthread_cond_wait.c
+++ b/nptl/pthread_cond_wait.c
@@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
 		{
 		  /* Use CLOCK_REALTIME.  */
 		  err = futex_abstimed_wait_cancelable
-		      (cond->__data.__g_signals + g, 0, abstime, private);
+		      (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private);
 		}
 	    }
 
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 2f61a7d..c145a65 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -241,7 +241,7 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
 	  if (__glibc_unlikely (abstime->tv_sec < 0))
 	    return ETIMEDOUT;
 #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
-     || !defined lll_futex_timed_wait_bitset)
+     || !defined lll_futex_clock_wait_bitset)
 	  struct timeval tv;
 	  struct timespec rt;
 
@@ -288,12 +288,12 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
 
 	  /* Block using the futex.  */
 #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
-     || !defined lll_futex_timed_wait_bitset)
+     || !defined lll_futex_clock_wait_bitset)
 	  lll_futex_timed_wait (&mutex->__data.__lock, oldval,
 				&rt, PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
 #else
-	  int err = lll_futex_timed_wait_bitset (&mutex->__data.__lock,
-	      oldval, abstime, FUTEX_CLOCK_REALTIME,
+	  int err = lll_futex_clock_wait_bitset (&mutex->__data.__lock,
+	      oldval, CLOCK_REALTIME, abstime,
 	      PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
 	  /* The futex call timed out.  */
 	  if (err == -ETIMEDOUT)
diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
index 2560734..89ba21a 100644
--- a/nptl/pthread_rwlock_common.c
+++ b/nptl/pthread_rwlock_common.c
@@ -319,7 +319,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
 		{
 		  int private = __pthread_rwlock_get_private (rwlock);
 		  int err = futex_abstimed_wait (&rwlock->__data.__readers,
-						 r, abstime, private);
+						 r, CLOCK_REALTIME, abstime, private);
 		  /* We ignore EAGAIN and EINTR.  On time-outs, we can just
 		     return because we don't need to clean up anything.  */
 		  if (err == ETIMEDOUT)
@@ -447,7 +447,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
 	    continue;
 	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
 					 1 | PTHREAD_RWLOCK_FUTEX_USED,
-					 abstime, private);
+					 CLOCK_REALTIME, abstime, private);
 	  if (err == ETIMEDOUT)
 	    {
 	      /* If we timed out, we need to unregister.  If no read phase
@@ -707,7 +707,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
 	  may_share_futex_used_flag = true;
 	  int err = futex_abstimed_wait (&rwlock->__data.__writers_futex,
 					 1 | PTHREAD_RWLOCK_FUTEX_USED,
-					 abstime, private);
+					 CLOCK_REALTIME, abstime, private);
 	  if (err == ETIMEDOUT)
 	    {
 	      if (prefer_writer)
@@ -806,7 +806,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
 	    continue;
 	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
 					 PTHREAD_RWLOCK_FUTEX_USED,
-					 abstime, private);
+					 CLOCK_REALTIME, abstime, private);
 	  if (err == ETIMEDOUT)
 	    {
 	      if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP)
diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c
index 5646bea..425d040 100644
--- a/nptl/sem_waitcommon.c
+++ b/nptl/sem_waitcommon.c
@@ -109,11 +109,13 @@ do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
 
 #if __HAVE_64B_ATOMICS
   err = futex_abstimed_wait_cancelable (
-      (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, abstime,
+      (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0,
+      CLOCK_REALTIME, abstime,
       sem->private);
 #else
   err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK,
-					abstime, sem->private);
+					CLOCK_REALTIME, abstime,
+					sem->private);
 #endif
 
   return err;
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
index 86a0818..54b7319 100644
--- a/sysdeps/nptl/futex-internal.h
+++ b/sysdeps/nptl/futex-internal.h
@@ -159,16 +159,23 @@ futex_reltimed_wait_cancelable (unsigned int* futex_word,
 				unsigned int expected,
 			        const struct timespec* reltime, int private);
 
+/* Check whether the specified clockid is supported by
+   futex_abstimed_wait and futex_abstimed_wait_cancelable. */
+static __always_inline int
+futex_abstimed_supported_clockid (clockid_t clockid);
+
 /* Like futex_reltimed_wait, but the provided timeout (ABSTIME) is an
    absolute point in time; a call will time out after this point in time.  */
 static __always_inline int
 futex_abstimed_wait (unsigned int* futex_word, unsigned int expected,
+		     clockid_t clockid,
 		     const struct timespec* abstime, int private);
 
 /* Like futex_reltimed_wait but is a POSIX cancellation point.  */
 static __always_inline int
 futex_abstimed_wait_cancelable (unsigned int* futex_word,
 				unsigned int expected,
+				clockid_t clockid,
 			        const struct timespec* abstime, int private);
 
 /* Atomically wrt other futex operations on the same futex, this unblocks the
diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h
index bb8effe..35fcfbb 100644
--- a/sysdeps/nptl/lowlevellock-futex.h
+++ b/sysdeps/nptl/lowlevellock-futex.h
@@ -43,11 +43,15 @@
 #define lll_futex_timed_wait(futexp, val, timeout, private)             \
   -ENOSYS
 
-/* This macro should be defined only if FUTEX_CLOCK_REALTIME is also defined.
-   If CLOCKBIT is zero, this is identical to lll_futex_timed_wait.
-   If CLOCKBIT has FUTEX_CLOCK_REALTIME set, then it's the same but
-   TIMEOUT is counted by CLOCK_REALTIME rather than CLOCK_MONOTONIC.  */
-#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \
+/* Verify whether the supplied clockid is supported by
+   lll_futex_clock_wait_bitset */
+#define lll_futex_supported_clockid(clockid)				\
+  (0)
+
+/* Wait until a lll_futex_wake call on FUTEXP, or the absolute TIMEOUT
+   measured against CLOCKID elapses. CLOCKID may be CLOCK_REALTIME or
+   CLOCK_MONOTONIC. */
+#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \
   -ENOSYS
 
 /* Wake up up to NR waiters on FUTEXP.  */
diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h
index 55f0fab..68bfe7e 100644
--- a/sysdeps/unix/sysv/linux/futex-internal.h
+++ b/sysdeps/unix/sysv/linux/futex-internal.h
@@ -162,15 +162,24 @@ futex_reltimed_wait_cancelable (unsigned int *futex_word,
 
 /* See sysdeps/nptl/futex-internal.h for details.  */
 static __always_inline int
+futex_abstimed_supported_clockid (clockid_t clockid)
+{
+  return lll_futex_supported_clockid (clockid);
+}
+
+/* See sysdeps/nptl/futex-internal.h for details.  */
+static __always_inline int
 futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
+		     clockid_t clockid,
 		     const struct timespec *abstime, int private)
 {
   /* Work around the fact that the kernel rejects negative timeout values
      despite them being valid.  */
   if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
     return ETIMEDOUT;
-  int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
-					 FUTEX_CLOCK_REALTIME, private);
+  int err = lll_futex_clock_wait_bitset (futex_word, expected,
+					 clockid, abstime,
+					 private);
   switch (err)
     {
     case 0:
@@ -180,9 +189,10 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
       return -err;
 
     case -EFAULT: /* Must have been caused by a glibc or application bug.  */
-    case -EINVAL: /* Either due to wrong alignment or due to the timeout not
-		     being normalized.  Must have been caused by a glibc or
-		     application bug.  */
+    case -EINVAL: /* Either due to wrong alignment, unsupported
+		     clockid or due to the timeout not being
+		     normalized. Must have been caused by a glibc or
+		     application bug. */
     case -ENOSYS: /* Must have been caused by a glibc bug.  */
     /* No other errors are documented at this time.  */
     default:
@@ -194,6 +204,7 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
 static __always_inline int
 futex_abstimed_wait_cancelable (unsigned int *futex_word,
 				unsigned int expected,
+				clockid_t clockid,
 			        const struct timespec *abstime, int private)
 {
   /* Work around the fact that the kernel rejects negative timeout values
@@ -202,8 +213,9 @@ futex_abstimed_wait_cancelable (unsigned int *futex_word,
     return ETIMEDOUT;
   int oldtype;
   oldtype = __pthread_enable_asynccancel ();
-  int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
-					 FUTEX_CLOCK_REALTIME, private);
+  int err = lll_futex_clock_wait_bitset (futex_word, expected,
+					clockid, abstime,
+					private);
   __pthread_disable_asynccancel (oldtype);
   switch (err)
     {
diff --git a/sysdeps/unix/sysv/linux/lowlevellock-futex.h b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
index 6f060b1..c3e7152 100644
--- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h
+++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
@@ -82,12 +82,29 @@
 		     __lll_private_flag (FUTEX_WAIT, private),  \
 		     val, timeout)
 
-#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \
-  lll_futex_syscall (6, futexp,                                         \
-		     __lll_private_flag (FUTEX_WAIT_BITSET | (clockbit), \
-					 private),                      \
-		     val, timeout, NULL /* Unused.  */,                 \
-		     FUTEX_BITSET_MATCH_ANY)
+/* Verify whether the supplied clockid is supported by
+   lll_futex_clock_wait_bitset */
+#define lll_futex_supported_clockid(clockid)			\
+  (clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC)
+
+/* The kernel currently only supports CLOCK_MONOTONIC or
+ * CLOCK_REALTIME timeouts for FUTEX_WAIT_BITSET. We could attempt to
+ * convert others here but currently do not.
+ */
+#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \
+  ({									\
+    long int __ret;							\
+    if (lll_futex_supported_clockid (clockid)) {			\
+      const unsigned int clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; \
+      __ret = lll_futex_syscall (6, futexp,				\
+				 __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, \
+						     private),		\
+				 val, timeout, NULL /* Unused.  */,	\
+				 FUTEX_BITSET_MATCH_ANY);		\
+    } else								\
+      __ret = -EINVAL;							\
+    __ret;								\
+  })
 
 #define lll_futex_wake(futexp, nr, private)                             \
   lll_futex_syscall (4, futexp,                                         \
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
  2019-02-27 18:23 ` [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-02-27 18:35   ` Joseph Myers
                     ` (2 more replies)
  2019-02-27 18:23 ` [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait Mike Crowe
                   ` (6 subsequent siblings)
  8 siblings, 3 replies; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

Add:

 int sem_clockwait (sem_t *sem, clockid_t clock, const struct timespec *abstime)

which behaves just like sem_timedwait, but measures abstime against the
specified clock. Currently supports CLOCK_REALTIME and CLOCK_MONOTONIC and
sets errno == EINVAL if any other clock is specified.

* nptl/sem_waitcommon.c (do_futex_wait, __new_sem_wait_slow): Add clockid
  parameters to indicate the clock which abstime should be measured against.

* nptl/sem_timedwait.c (sem_timedwait), nptl/sem_wait.c (__new_sem_wait): Pass
  CLOCK_REALTIME as clockid to __new_sem_wait_slow.

* nptl/sem_clockwait.c: New file to implement sem_clockwait based on
  sem_timedwait.c.

* nptl/Makefile: Add sem_clockwait.c source file. Add CFLAGS for
  sem_clockwait.c to match those used for sem_timedwait.c.

* sysdeps/pthread/semaphore.h: Add sem_clockwait.

* nptl/Versions (GLIBC_2.30): Likewise.

* conform/data/semaphore.h-data: Likewise.

* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Likewise.

* nptl/tst-sem17.c: Add new test for passing invalid clock to
  sem_clockwait.

* nptl/tst-sem13.c, tst-sem5: Modify existing sem_timedwait tests to also
  test sem_clockwait.

* manual/threads.texi: Document sem_clockwait.
---
 conform/data/semaphore.h-data                        |  1 +-
 manual/threads.texi                                  | 10 ++-
 nptl/Makefile                                        |  5 +-
 nptl/Versions                                        |  4 +-
 nptl/sem_clockwait.c                                 | 45 ++++++++++-
 nptl/sem_timedwait.c                                 |  3 +-
 nptl/sem_wait.c                                      |  3 +-
 nptl/sem_waitcommon.c                                | 15 +--
 nptl/tst-sem13.c                                     | 50 +++++++++--
 nptl/tst-sem17.c                                     | 57 +++++++++++++-
 nptl/tst-sem5.c                                      | 30 ++++---
 sysdeps/pthread/semaphore.h                          |  4 +-
 sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |  1 +-
 13 files changed, 197 insertions(+), 31 deletions(-)
 create mode 100644 nptl/sem_clockwait.c
 create mode 100644 nptl/tst-sem17.c

diff --git a/conform/data/semaphore.h-data b/conform/data/semaphore.h-data
index 066c2f7..019aaa1 100644
--- a/conform/data/semaphore.h-data
+++ b/conform/data/semaphore.h-data
@@ -11,6 +11,7 @@ function {sem_t*} sem_open (const char*, int, ...)
 function int sem_post (sem_t*)
 # if !defined POSIX && !defined UNIX98
 function int sem_timedwait (sem_t*, const struct timespec*)
+function int sem_clockwait (sem_t*, clockid_t, const struct timespec*)
 # endif
 function int sem_trywait (sem_t*)
 function int sem_unlink (const char*)
diff --git a/manual/threads.texi b/manual/threads.texi
index 87fda7d..674267c 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -669,6 +669,16 @@ The system does not have sufficient memory.
 @end table
 @end deftypefun
 
+@comment semaphore.h
+@comment POSIX-proposed
+@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid},
+                               const struct timespec *@var{abstime})
+Behaves like @code{sem_timedwait} except the time @var{abstime} is measured
+against the clock specified by @var{clockid} rather than
+@code{CLOCK_REALTIME}. 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 5acfdcc..4c9f5d3 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -114,7 +114,7 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
 		      sem_init sem_destroy \
 		      sem_open sem_close sem_unlink \
 		      sem_getvalue \
-		      sem_wait sem_timedwait sem_post \
+		      sem_wait sem_timedwait sem_clockwait sem_post \
 		      cleanup cleanup_defer cleanup_compat \
 		      cleanup_defer_compat unwind \
 		      pt-longjmp pt-cleanup\
@@ -194,6 +194,7 @@ CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \
 CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sem_clockwait.c = -fexceptions -fasynchronous-unwind-tables
 
 # These are the function wrappers we have to duplicate here.
 CFLAGS-fcntl.c += -fexceptions -fasynchronous-unwind-tables
@@ -263,7 +264,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
 	tst-key1 tst-key2 tst-key3 tst-key4 \
 	tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
 	tst-sem8 tst-sem9 tst-sem10 tst-sem14 \
-	tst-sem15 tst-sem16 \
+	tst-sem15 tst-sem16 tst-sem17 \
 	tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
 	tst-align tst-align3 \
 	tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
diff --git a/nptl/Versions b/nptl/Versions
index e7f691d..cd1806c 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -277,6 +277,10 @@ libpthread {
     cnd_timedwait; cnd_wait; tss_create; tss_delete; tss_get; tss_set;
   }
 
+  GLIBC_2.30 {
+    sem_clockwait;
+  }
+
   GLIBC_PRIVATE {
     __pthread_initialize_minimal;
     __pthread_clock_gettime; __pthread_clock_settime;
diff --git a/nptl/sem_clockwait.c b/nptl/sem_clockwait.c
new file mode 100644
index 0000000..c0cd667
--- /dev/null
+++ b/nptl/sem_clockwait.c
@@ -0,0 +1,45 @@
+/* sem_clockwait -- wait on a semaphore with timeout using
+   the specified clock.
+
+   Copyright (C) 2003-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 "sem_waitcommon.c"
+
+int
+sem_clockwait (sem_t *sem, clockid_t clockid,
+	       const struct timespec *abstime)
+{
+  /* Check that supplied clockid is one we support, even if we don't
+     end up waiting. */
+  if (!futex_abstimed_supported_clockid (clockid))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
+    return 0;
+  else
+    return __new_sem_wait_slow ((struct new_sem *) sem, clockid, abstime);
+}
diff --git a/nptl/sem_timedwait.c b/nptl/sem_timedwait.c
index 3dd71ab..0918d8b 100644
--- a/nptl/sem_timedwait.c
+++ b/nptl/sem_timedwait.c
@@ -36,5 +36,6 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
   if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
     return 0;
   else
-    return __new_sem_wait_slow((struct new_sem *) sem, abstime);
+    return __new_sem_wait_slow ((struct new_sem *) sem,
+				CLOCK_REALTIME, abstime);
 }
diff --git a/nptl/sem_wait.c b/nptl/sem_wait.c
index 6a2d26b..20a8b9d 100644
--- a/nptl/sem_wait.c
+++ b/nptl/sem_wait.c
@@ -39,7 +39,8 @@ __new_sem_wait (sem_t *sem)
   if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
     return 0;
   else
-    return __new_sem_wait_slow((struct new_sem *) sem, NULL);
+    return __new_sem_wait_slow ((struct new_sem *) sem,
+				CLOCK_REALTIME, NULL);
 }
 versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
 
diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c
index 425d040..cad56e9 100644
--- a/nptl/sem_waitcommon.c
+++ b/nptl/sem_waitcommon.c
@@ -103,19 +103,19 @@ __sem_wait_cleanup (void *arg)
    users don't seem to need it.  */
 static int
 __attribute__ ((noinline))
-do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
+do_futex_wait (struct new_sem *sem, clockid_t clockid,
+	       const struct timespec *abstime)
 {
   int err;
 
 #if __HAVE_64B_ATOMICS
   err = futex_abstimed_wait_cancelable (
       (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0,
-      CLOCK_REALTIME, abstime,
+      clockid, abstime,
       sem->private);
 #else
   err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK,
-					CLOCK_REALTIME, abstime,
-					sem->private);
+					clockid, abstime, sem->private);
 #endif
 
   return err;
@@ -162,7 +162,8 @@ __new_sem_wait_fast (struct new_sem *sem, int definitive_result)
 /* Slow path that blocks.  */
 static int
 __attribute__ ((noinline))
-__new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
+__new_sem_wait_slow (struct new_sem *sem, clockid_t clockid,
+		     const struct timespec *abstime)
 {
   int err = 0;
 
@@ -180,7 +181,7 @@ __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
       /* If there is no token available, sleep until there is.  */
       if ((d & SEM_VALUE_MASK) == 0)
 	{
-	  err = do_futex_wait (sem, abstime);
+	  err = do_futex_wait (sem, clockid, abstime);
 	  /* A futex return value of 0 or EAGAIN is due to a real or spurious
 	     wake-up, or due to a change in the number of tokens.  We retry in
 	     these cases.
@@ -281,7 +282,7 @@ __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
 	  if ((v >> SEM_VALUE_SHIFT) == 0)
 	    {
 	      /* See __HAVE_64B_ATOMICS variant.  */
-	      err = do_futex_wait(sem, abstime);
+	      err = do_futex_wait (sem, clockid, abstime);
 	      if (err == ETIMEDOUT || err == EINTR)
 		{
 		  __set_errno (err);
diff --git a/nptl/tst-sem13.c b/nptl/tst-sem13.c
index 1560e91..0f76100 100644
--- a/nptl/tst-sem13.c
+++ b/nptl/tst-sem13.c
@@ -5,9 +5,14 @@
 #include <pthread.h>
 #include <internaltypes.h>
 
+/* A bogus clock value that tells run_test to use
+   sem_timedwait rather than sem_clockwait */
+#define	CLOCK_USE_TIMEDWAIT (-1)
+
+typedef int (*waitfn_t)(sem_t *, struct timespec *);
 
 static int
-do_test (void)
+do_test_wait (waitfn_t waitfn, const char *fnname)
 {
   union
   {
@@ -23,14 +28,14 @@ do_test (void)
 
   struct timespec ts = { 0, 1000000001 };	/* Invalid.  */
   errno = 0;
-  if (sem_timedwait (&u.s, &ts) >= 0)
+  if (waitfn (&u.s, &ts) >= 0)
     {
-      puts ("sem_timedwait did not fail");
+      printf ("%s did not fail\n", fnname);
       return 1;
     }
   if (errno != EINVAL)
     {
-      perror ("sem_timedwait did not fail with EINVAL");
+      printf ("%s did not fail with EINVAL: %m\n", fnname);
       return 1;
     }
 #if __HAVE_64B_ATOMICS
@@ -40,21 +45,21 @@ do_test (void)
 #endif
   if (nwaiters != 0)
     {
-      printf ("sem_timedwait modified nwaiters: %d\n", nwaiters);
+      printf ("%s modified nwaiters: %d\n", fnname, nwaiters);
       return 1;
     }
 
   ts.tv_sec = /* Invalid.  */ -2;
   ts.tv_nsec = 0;
   errno = 0;
-  if (sem_timedwait (&u.s, &ts) >= 0)
+  if (waitfn (&u.s, &ts) >= 0)
     {
-      puts ("2nd sem_timedwait did not fail");
+      printf ("2nd %s did not fail\n", fnname);
       return 1;
     }
   if (errno != ETIMEDOUT)
     {
-      perror ("2nd sem_timedwait did not fail with ETIMEDOUT");
+      printf ("2nd %s did not fail with ETIMEDOUT\n", fnname);
       return 1;
     }
 #if __HAVE_64B_ATOMICS
@@ -64,12 +69,39 @@ do_test (void)
 #endif
   if (nwaiters != 0)
     {
-      printf ("2nd sem_timedwait modified nwaiters: %d\n", nwaiters);
+      printf ("2nd %s modified nwaiters: %d\n", fnname, nwaiters);
       return 1;
     }
 
   return 0;
 }
 
+int test_sem_timedwait (sem_t *sem, struct timespec *ts)
+{
+  return sem_timedwait (sem, ts);
+}
+
+int test_sem_clockwait_monotonic (sem_t *sem, struct timespec *ts)
+{
+  return sem_clockwait (sem, CLOCK_MONOTONIC, ts);
+}
+
+int test_sem_clockwait_realtime (sem_t *sem, struct timespec *ts)
+{
+  return sem_clockwait (sem, CLOCK_REALTIME, ts);
+}
+
+static int do_test (void)
+{
+  int result = 0;
+  result |= do_test_wait (&test_sem_timedwait,
+			 "sem_timedwait");
+  result |= do_test_wait (&test_sem_clockwait_monotonic,
+			 "sem_clockwait(monotonic)");
+  result |= do_test_wait (&test_sem_clockwait_realtime,
+			 "sem_clockwait(realtime)");
+  return result;
+}
+
 #define TEST_FUNCTION do_test ()
 #include "../test-skeleton.c"
diff --git a/nptl/tst-sem17.c b/nptl/tst-sem17.c
new file mode 100644
index 0000000..a24ad0f
--- /dev/null
+++ b/nptl/tst-sem17.c
@@ -0,0 +1,57 @@
+/* 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 <semaphore.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define NOT_A_VALID_CLOCK 123456
+
+static int
+do_test (void)
+{
+  sem_t s;
+  struct timespec ts;
+
+  if (sem_init (&s, 0, 1) == -1)
+    {
+      puts ("sem_init failed");
+      return 1;
+    }
+
+  ts.tv_sec = 0;
+  ts.tv_nsec = 0;
+
+  if (sem_clockwait (&s, NOT_A_VALID_CLOCK, &ts) == 0)
+    {
+      puts ("sem_clockwait succeeded with an invalid clock");
+      return 1;
+    }
+  if (errno != EINVAL)
+    {
+      printf ("sem_clockwait yielded incorrect errno for invalid clock: %d\n",
+	      errno);
+      return 1;
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
index 2149ade..7f1031d 100644
--- a/nptl/tst-sem5.c
+++ b/nptl/tst-sem5.c
@@ -23,13 +23,15 @@
 #include <unistd.h>
 #include <sys/time.h>
 
+/* A bogus clock value that tells run_test to use
+   sem_timedwait rather than sem_clockwait */
+#define	CLOCK_USE_TIMEDWAIT (-1)
 
 static int
-do_test (void)
+do_test_clock (clockid_t clockid)
 {
   sem_t s;
   struct timespec ts;
-  struct timeval tv;
 
   if (sem_init (&s, 0, 1) == -1)
     {
@@ -43,13 +45,8 @@ do_test (void)
       return 1;
     }
 
-  if (gettimeofday (&tv, NULL) != 0)
-    {
-      puts ("gettimeofday failed");
-      return 1;
-    }
-
-  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+  (void) clock_gettime (clockid == CLOCK_USE_TIMEDWAIT
+			? CLOCK_REALTIME : clockid, &ts);
 
   /* We wait for half a second.  */
   ts.tv_nsec += 500000000;
@@ -60,7 +57,9 @@ do_test (void)
     }
 
   errno = 0;
-  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
+  if (TEMP_FAILURE_RETRY ((clockid == CLOCK_USE_TIMEDWAIT)
+			  ? sem_timedwait (&s, &ts)
+			  : sem_clockwait (&s, clockid, &ts)) != -1)
     {
       puts ("sem_timedwait succeeded");
       return 1;
@@ -73,7 +72,8 @@ do_test (void)
     }
 
   struct timespec ts2;
-  if (clock_gettime (CLOCK_REALTIME, &ts2) != 0)
+  if (clock_gettime (clockid == CLOCK_USE_TIMEDWAIT
+		     ? CLOCK_REALTIME : clockid, &ts2) != 0)
     {
       puts ("clock_gettime failed");
       return 1;
@@ -89,5 +89,13 @@ do_test (void)
   return 0;
 }
 
+static int do_test (void)
+{
+  do_test_clock (CLOCK_USE_TIMEDWAIT);
+  do_test_clock (CLOCK_REALTIME);
+  do_test_clock (CLOCK_MONOTONIC);
+  return 0;
+}
+
 #define TEST_FUNCTION do_test ()
 #include "../test-skeleton.c"
diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
index 41ff927..2e68b16 100644
--- a/sysdeps/pthread/semaphore.h
+++ b/sysdeps/pthread/semaphore.h
@@ -59,6 +59,10 @@ extern int sem_wait (sem_t *__sem);
    __THROW.  */
 extern int sem_timedwait (sem_t *__restrict __sem,
 			  const struct timespec *__restrict __abstime);
+
+extern int sem_clockwait (sem_t *__restrict __sem,
+			  clockid_t clock,
+			  const struct timespec *__restrict __abstime);
 #endif
 
 /* Test whether SEM is posted.  */
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
index 931c827..454d340 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
@@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
 GLIBC_2.3.4 pthread_getaffinity_np F
 GLIBC_2.3.4 pthread_setaffinity_np F
 GLIBC_2.3.4 pthread_setschedprio F
+GLIBC_2.30 sem_clockwait F
 GLIBC_2.4 pthread_mutex_consistent_np F
 GLIBC_2.4 pthread_mutex_getprioceiling F
 GLIBC_2.4 pthread_mutex_setprioceiling F
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
  2019-02-27 18:23 ` [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls Mike Crowe
  2019-02-27 18:23 ` [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-03-05 16:45   ` Adhemerval Zanella
  2019-02-27 18:23 ` [PATCH 4/7] nptl: pthread_rwlock: Move timeout validation into _full functions Mike Crowe
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

Add:

 int pthread_cond_clockwait (pthread_cond_t *cond,
                             pthread_mutex_t *mutex,
                             clockid_t clockid,
                             const struct timespec *abstime)

which behaves just like pthread_cond_timedwait except it always measures
abstime against the supplied clockid. Currently supports CLOCK_REALTIME and
CLOCK_MONOTONIC and returns EINVAL if any other clock is specified.

Includes feedback from many others. This function was originally
proposed[1] as pthread_cond_timedwaitonclock_np, but The Austin Group
preferred the new name.

* nptl/Makefile: Add tst-cond26 and tst-cond27

* nptl/Versions (GLIBC_2.30): Add pthread_cond_clockwait

* sysdeps/nptl/pthread.h: Likewise

* nptl/forward.c: Add __pthread_cond_clockwait (not sure if it should be
  __USE_GNU while it's still only proposed for POSIX.)

* nptl/forward.c: Likewise

* nptl/pthreadP.h: Likewise

* sysdeps/nptl/pthread-functions.h: Likewise.

* nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Add clockid
  parameter and comment describing why we don't need to check its value.
  Use that value 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.

* 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.

* sysdeps/unix/sysv/linux/arm/libpthread.abilist,
 sysdeps/unix/sysv/linux/i386/libpthread.abilist,
 sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Add
 pthread_cond_clockwait

* manual/threads.texi: Document pthread_cond_clockwait. The comment was
  provided by Carlos O'Donell.

[1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
---
 manual/threads.texi                                  |  20 ++-
 nptl/Makefile                                        |   1 +-
 nptl/Versions                                        |   2 +-
 nptl/forward.c                                       |   5 +-
 nptl/nptl-init.c                                     |   1 +-
 nptl/pthreadP.h                                      |   4 +-
 nptl/pthread_cond_wait.c                             |  43 ++++-
 nptl/tst-cond11.c                                    |  30 ++-
 nptl/tst-cond26.c                                    |  91 ++++++++++-
 nptl/tst-cond27.c                                    | 113 ++++++++++++-
 sysdeps/nptl/pthread-functions.h                     |   4 +-
 sysdeps/nptl/pthread.h                               |  13 +-
 sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   1 +-
 13 files changed, 314 insertions(+), 14 deletions(-)
 create mode 100644 nptl/tst-cond26.c
 create mode 100644 nptl/tst-cond27.c

diff --git a/manual/threads.texi b/manual/threads.texi
index 674267c..91462f5 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -679,6 +679,26 @@ against the clock specified by @var{clockid} rather than
 @code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}.
 @end deftypefun
 
+@comment pthread.h
+@comment POSIX-proposed
+@deftypefun int pthread_cond_clockwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex},
+                                        clockid_t @var{clockid}, const struct timespec *@var{abstime})
+@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
+@c If exactly the same function with arguments is called from a signal
+@c handler that interrupts between the mutex unlock and sleep then it
+@c will unlock the mutex twice resulting in undefined behaviour. Keep
+@c in mind that the unlock and sleep are only atomic with respect to other
+@c threads (really a happens-after relationship for pthread_cond_broadcast
+@c and pthread_cond_signal).
+@c In the AC case we would cancel the thread and the mutex would remain
+@c locked and we can't recover from that.
+Behaves like @code{pthread_cond_timedwait} except the time @var{abstime} is
+measured against the clock specified by @var{clockid} rather than the clock
+specified or defaulted when @code{pthread_cond_init} was called. Currently,
+@var{clockid} must be either @code{CLOCK_MONOTONIC} or
+@code{CLOCK_REALTIME}.
+@end deftypefun
+
 @c FIXME these are undocumented:
 @c pthread_atfork
 @c pthread_attr_destroy
diff --git a/nptl/Makefile b/nptl/Makefile
index 4c9f5d3..7de4d40 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -251,6 +251,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
 	tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
 	tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
 	tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond25 \
+	tst-cond26 tst-cond27 \
 	tst-cond-except \
 	tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
 	tst-robust6 tst-robust7 tst-robust8 tst-robust9 \
diff --git a/nptl/Versions b/nptl/Versions
index cd1806c..8c094d0 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -278,7 +278,7 @@ libpthread {
   }
 
   GLIBC_2.30 {
-    sem_clockwait;
+    sem_clockwait; pthread_cond_clockwait;
   }
 
   GLIBC_PRIVATE {
diff --git a/nptl/forward.c b/nptl/forward.c
index ed1e7d0..50f358f 100644
--- a/nptl/forward.c
+++ b/nptl/forward.c
@@ -164,6 +164,11 @@ FORWARD (__pthread_cond_timedwait,
 	  const struct timespec *abstime), (cond, mutex, abstime), 0)
 versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait,
 		  GLIBC_2_3_2);
+FORWARD (__pthread_cond_clockwait,
+	 (pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid,
+	  const struct timespec *abstime), (cond, mutex, clockid, abstime),
+	 0)
+weak_alias (__pthread_cond_clockwait, pthread_cond_clockwait);
 
 
 FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index b5895fa..c872b9f 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -104,6 +104,7 @@ static const struct pthread_functions pthread_functions =
     .ptr___pthread_cond_signal = __pthread_cond_signal,
     .ptr___pthread_cond_wait = __pthread_cond_wait,
     .ptr___pthread_cond_timedwait = __pthread_cond_timedwait,
+    .ptr___pthread_cond_clockwait = __pthread_cond_clockwait,
 # if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
     .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
     .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index 626bd4b..28c0ee5 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -487,6 +487,10 @@ 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);
 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 daa4e25..5deb54b 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
@@ -510,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
 	      if (__glibc_unlikely (abstime->tv_sec < 0))
 	        err = ETIMEDOUT;
 
-	      else if ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0)
+	      else if (clockid == CLOCK_MONOTONIC)
 		{
 		  /* CLOCK_MONOTONIC is requested.  */
 		  struct timespec rt;
@@ -652,7 +658,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.  */
@@ -664,10 +671,40 @@ __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;
+
+  /* We only support CLOCK_REALTIME and CLOCK_MONOTONIC */
+  if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
+    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 97a8bd0..4df6b15 100644
--- a/nptl/tst-cond11.c
+++ b/nptl/tst-cond11.c
@@ -22,17 +22,20 @@
 #include <time.h>
 #include <unistd.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)
     {
@@ -40,7 +43,7 @@ run_test (clockid_t cl)
       return 1;
     }
 
-  if (pthread_condattr_setclock (&condattr, cl) != 0)
+  if (pthread_condattr_setclock (&condattr, attr_clock) != 0)
     {
       puts ("condattr_setclock failed");
       return 1;
@@ -52,10 +55,10 @@ run_test (clockid_t cl)
       puts ("condattr_getclock failed");
       return 1;
     }
-  if (cl != cl2)
+  if (attr_clock != cl2)
     {
       printf ("condattr_getclock returned wrong value: %d, expected %d\n",
-	      (int) cl2, (int) cl);
+	      (int) cl2, (int) attr_clock);
       return 1;
     }
 
@@ -108,7 +111,7 @@ run_test (clockid_t cl)
     }
 
   struct timespec ts;
-  if (clock_gettime (cl, &ts) != 0)
+  if (clock_gettime ((wait_clock == CLOCK_USE_ATTR_CLOCK) ? attr_clock : wait_clock, &ts) != 0)
     {
       puts ("clock_gettime failed");
       return 1;
@@ -117,7 +120,9 @@ run_test (clockid_t cl)
   /* Wait one second.  */
   ++ts.tv_sec;
 
-  int e = pthread_cond_timedwait (&cond, &mut, &ts);
+  int e = (wait_clock == CLOCK_USE_ATTR_CLOCK)
+    ? pthread_cond_timedwait (&cond, &mut, &ts)
+    : pthread_cond_clockwait (&cond, &mut, wait_clock, &ts);
   if (e == 0)
     {
       puts ("cond_timedwait succeeded");
@@ -130,7 +135,7 @@ run_test (clockid_t cl)
     }
 
   struct timespec ts2;
-  if (clock_gettime (cl, &ts2) != 0)
+  if (clock_gettime ((wait_clock == CLOCK_USE_ATTR_CLOCK) ? attr_clock : wait_clock, &ts2) != 0)
     {
       puts ("second clock_gettime failed");
       return 1;
@@ -176,7 +181,7 @@ do_test (void)
 
 #else
 
-  int res = run_test (CLOCK_REALTIME);
+  int res = run_test (CLOCK_REALTIME, CLOCK_USE_ATTR_CLOCK);
 
 # if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
 #  if _POSIX_MONOTONIC_CLOCK == 0
@@ -189,8 +194,13 @@ do_test (void)
       res = 1;
     }
   else
+    {
 #  endif
-    res |= run_test (CLOCK_MONOTONIC);
+      res |= run_test (CLOCK_MONOTONIC, CLOCK_USE_ATTR_CLOCK);
+      res |= run_test (CLOCK_REALTIME, CLOCK_MONOTONIC);
+      res |= run_test (CLOCK_MONOTONIC, CLOCK_MONOTONIC);
+      res |= run_test (CLOCK_MONOTONIC, CLOCK_REALTIME);
+    }
 # else
   puts ("_POSIX_MONOTONIC_CLOCK not defined");
 # endif
diff --git a/nptl/tst-cond26.c b/nptl/tst-cond26.c
new file mode 100644
index 0000000..83b041d
--- /dev/null
+++ b/nptl/tst-cond26.c
@@ -0,0 +1,91 @@
+/* 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>
+
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+
+static int test_bad_clockid (clockid_t clockid)
+{
+  struct timespec ts = {0,0};
+  int rc = pthread_cond_clockwait (&cond, &mut, clockid, &ts);
+
+  if (rc == 0)
+    {
+      puts ("pthread_cond_clockwait on bad clock incorrectly succeeded\n");
+      return 1;
+    }
+  else if (rc != EINVAL)
+    {
+      printf ("pthread_cond_clockwait on bad clock incorrectly failed "
+	      "with %d\n", rc);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+#define NOT_A_VALID_CLOCK 123456
+
+static int
+do_test (void)
+{
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts("Failed to lock mutex\n");
+      return 1;
+    }
+
+  int rc = 0;
+
+  /* These clocks are meaningless to pthread_cond_clockwait. */
+#if defined(CLOCK_PROCESS_CPUTIME_ID)
+  rc |= test_bad_clockid (CLOCK_PROCESS_CPUTIME_ID);
+#endif
+#if defined(CLOCK_THREAD_CPUTIME_ID)
+  rc |= test_bad_clockid (CLOCK_PROCESS_CPUTIME_ID);
+#endif
+
+  /* These clocks might be meaningful, but are currently unsupported
+     by pthread_cond_clockwait. */
+#if defined(CLOCK_REALTIME_COARSE)
+  rc |= test_bad_clockid (CLOCK_REALTIME_COARSE);
+#endif
+#if defined(CLOCK_MONOTONIC_RAW)
+  rc |= test_bad_clockid (CLOCK_MONOTONIC_RAW);
+#endif
+#if defined(CLOCK_MONOTONIC_COARSE)
+  rc |= test_bad_clockid (CLOCK_MONOTONIC_COARSE);
+#endif
+#if defined(CLOCK_BOOTTIME)
+  rc |= test_bad_clockid (CLOCK_BOOTTIME);
+#endif
+
+  /* This is a completely invalid clock. */
+  rc |= test_bad_clockid (NOT_A_VALID_CLOCK);
+
+  return rc;
+}
+
+#include <support/test-driver.c>
diff --git a/nptl/tst-cond27.c b/nptl/tst-cond27.c
new file mode 100644
index 0000000..efca7fd
--- /dev/null
+++ b/nptl/tst-cond27.c
@@ -0,0 +1,113 @@
+/* Test pthread_cond_clockwait, based on tst-cond5.c
+
+   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>
+
+
+static pthread_mutex_t mut;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+
+
+static int
+do_test_clock (clockid_t clockid)
+{
+  pthread_mutexattr_t ma;
+  int err;
+  struct timespec ts;
+
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("mutexattr_init failed");
+      exit (1);
+    }
+
+  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
+    {
+      puts ("mutexattr_settype failed");
+      exit (1);
+    }
+
+  if (pthread_mutex_init (&mut, &ma) != 0)
+    {
+      puts ("mutex_init failed");
+      exit (1);
+    }
+
+  /* Get the mutex.  */
+  if (pthread_mutex_lock (&mut) != 0)
+    {
+      puts ("mutex_lock failed");
+      exit (1);
+    }
+
+  /* Waiting for the condition will fail.  But we want the timeout here.  */
+  if (clock_gettime (clockid, &ts) != 0)
+    {
+      puts ("clock_gettime failed");
+      exit (1);
+    }
+
+  ts.tv_nsec += 500000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ts.tv_nsec -= 1000000000;
+      ++ts.tv_sec;
+    }
+  err = pthread_cond_clockwait (&cond, &mut, clockid, &ts);
+  if (err == 0)
+    {
+      /* This could in theory happen but here without any signal and
+	 additional waiter it should not.  */
+      puts ("cond_timedwait succeeded");
+      exit (1);
+    }
+  else if (err != ETIMEDOUT)
+    {
+      printf ("cond_timedwait returned with %s\n", strerror (err));
+      exit (1);
+    }
+
+  err = pthread_mutex_unlock (&mut);
+  if (err != 0)
+    {
+      printf ("mutex_unlock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  int rc;
+  rc = do_test_clock (CLOCK_MONOTONIC);
+  if (rc == 0)
+    rc = do_test_clock (CLOCK_REALTIME);
+
+  return rc;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/nptl/pthread-functions.h b/sysdeps/nptl/pthread-functions.h
index cd5e94d..cfa9660 100644
--- a/sysdeps/nptl/pthread-functions.h
+++ b/sysdeps/nptl/pthread-functions.h
@@ -55,6 +55,10 @@ struct pthread_functions
   int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
   int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *,
 				       const struct timespec *);
+  int (*ptr___pthread_cond_clockwait) (pthread_cond_t *,
+				       pthread_mutex_t *,
+				       clockid_t,
+				       const struct timespec *);
   int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *);
   int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *);
   int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *,
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index 704a3c4..d4fe9d9 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -1003,6 +1003,19 @@ extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
 				   const struct timespec *__restrict __abstime)
      __nonnull ((1, 2, 3));
 
+/* 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));
+
 /* Functions for handling condition variable attributes.  */
 
 /* Initialize condition variable attribute ATTR.  */
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
index 454d340..aaa1c3b 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
@@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
 GLIBC_2.3.4 pthread_getaffinity_np F
 GLIBC_2.3.4 pthread_setaffinity_np F
 GLIBC_2.3.4 pthread_setschedprio F
+GLIBC_2.30 pthread_cond_clockwait F
 GLIBC_2.30 sem_clockwait F
 GLIBC_2.4 pthread_mutex_consistent_np F
 GLIBC_2.4 pthread_mutex_getprioceiling F
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 4/7] nptl: pthread_rwlock: Move timeout validation into _full functions
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
                   ` (2 preceding siblings ...)
  2019-02-27 18:23 ` [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-03-05 16:48   ` Adhemerval Zanella
  2019-02-27 18:23 ` [PATCH 5/7] nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly Mike Crowe
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

As recommended by the comments in the implementations of
pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock, let's move the
timeout validity checks into the corresponding pthread_rwlock_rdlock_full
and pthread_rwlock_wrlock_full functions. Since these functions may be
called with abstime == NULL, an extra check for that is necessary too.
---
 nptl/pthread_rwlock_common.c      | 20 ++++++++++++++++++++
 nptl/pthread_rwlock_timedrdlock.c | 10 ----------
 nptl/pthread_rwlock_timedwrlock.c | 10 ----------
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
index 89ba21a..120b880 100644
--- a/nptl/pthread_rwlock_common.c
+++ b/nptl/pthread_rwlock_common.c
@@ -282,6 +282,16 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
 {
   unsigned int r;
 
+  /* Make sure any passed in timeout value is valid.  Note that the previous
+     implementation assumed that this check *must* not be performed if there
+     would in fact be no blocking; however, POSIX only requires that "the
+     validity of the abstime parameter need not be checked if the lock can be
+     immediately acquired" (i.e., we need not but may check it).  */
+  if (abstime
+      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
+      || abstime->tv_nsec < 0))
+    return EINVAL;
+
   /* Make sure we are not holding the rwlock as a writer.  This is a deadlock
      situation we recognize and report.  */
   if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer)
@@ -576,6 +586,16 @@ static __always_inline int
 __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
     const struct timespec *abstime)
 {
+  /* Make sure any passed in timeout value is valid.  Note that the previous
+     implementation assumed that this check *must* not be performed if there
+     would in fact be no blocking; however, POSIX only requires that "the
+     validity of the abstime parameter need not be checked if the lock can be
+     immediately acquired" (i.e., we need not but may check it).  */
+  if (abstime
+      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
+      || abstime->tv_nsec < 0))
+    return EINVAL;
+
   /* Make sure we are not holding the rwlock as a writer.  This is a deadlock
      situation we recognize and report.  */
   if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer)
diff --git a/nptl/pthread_rwlock_timedrdlock.c b/nptl/pthread_rwlock_timedrdlock.c
index aa00530..84c1983 100644
--- a/nptl/pthread_rwlock_timedrdlock.c
+++ b/nptl/pthread_rwlock_timedrdlock.c
@@ -23,15 +23,5 @@ int
 pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
     const struct timespec *abstime)
 {
-  /* Make sure the passed in timeout value is valid.  Note that the previous
-     implementation assumed that this check *must* not be performed if there
-     would in fact be no blocking; however, POSIX only requires that "the
-     validity of the abstime parameter need not be checked if the lock can be
-     immediately acquired" (i.e., we need not but may check it).  */
-  /* ??? Just move this to __pthread_rwlock_rdlock_full?  */
-  if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
-      || abstime->tv_nsec < 0))
-    return EINVAL;
-
   return __pthread_rwlock_rdlock_full (rwlock, abstime);
 }
diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c
index 3c92e44..f0b745d 100644
--- a/nptl/pthread_rwlock_timedwrlock.c
+++ b/nptl/pthread_rwlock_timedwrlock.c
@@ -23,15 +23,5 @@ int
 pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
     const struct timespec *abstime)
 {
-  /* Make sure the passed in timeout value is valid.  Note that the previous
-     implementation assumed that this check *must* not be performed if there
-     would in fact be no blocking; however, POSIX only requires that "the
-     validity of the abstime parameter need not be checked if the lock can be
-     immediately acquired" (i.e., we need not but may check it).  */
-  /* ??? Just move this to __pthread_rwlock_wrlock_full?  */
-  if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
-      || abstime->tv_nsec < 0))
-    return EINVAL;
-
   return __pthread_rwlock_wrlock_full (rwlock, abstime);
 }
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 5/7] nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
                   ` (3 preceding siblings ...)
  2019-02-27 18:23 ` [PATCH 4/7] nptl: pthread_rwlock: Move timeout validation into _full functions Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-03-05 17:36   ` Adhemerval Zanella
  2019-02-27 18:23 ` [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval Mike Crowe
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

The tests for out-of-bounds timespecs first test pthread_rwlock_timedrdlock
and then pthread_rwlock_timedwrlock. It appears that the second and third
tests suffered from copy-and-paste errors and each test
pthread_rwlock_timedrdlock twice in a row. Let's correct that so that
pthread_rwlock_timedwrlock is tested too.
---
 nptl/tst-rwlock14.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c
index f8c2183..6f57169 100644
--- a/nptl/tst-rwlock14.c
+++ b/nptl/tst-rwlock14.c
@@ -117,15 +117,15 @@ do_test (void)
       result = 1;
     }
 
-  e = pthread_rwlock_timedrdlock (&r, &ts);
+  e = pthread_rwlock_timedwrlock (&r, &ts);
   if (e == 0)
     {
-      puts ("second rwlock_timedrdlock did not fail");
+      puts ("second rwlock_timedwrlock did not fail");
       result = 1;
     }
   else if (e != EINVAL)
     {
-      puts ("second rwlock_timedrdlock did not return EINVAL");
+      puts ("second rwlock_timedwrlock did not return EINVAL");
       result = 1;
     }
 
@@ -145,15 +145,15 @@ do_test (void)
       result = 1;
     }
 
-  e = pthread_rwlock_timedrdlock (&r, &ts);
+  e = pthread_rwlock_timedwrlock (&r, &ts);
   if (e == 0)
     {
-      puts ("third rwlock_timedrdlock did not fail");
+      puts ("third rwlock_timedwrlock did not fail");
       result = 1;
     }
   else if (e != EINVAL)
     {
-      puts ("third rwlock_timedrdlock did not return EINVAL");
+      puts ("third rwlock_timedwrlock did not return EINVAL");
       result = 1;
     }
 
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
                   ` (4 preceding siblings ...)
  2019-02-27 18:23 ` [PATCH 5/7] nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-03-05 18:02   ` Adhemerval Zanella
  2019-03-14 14:44   ` Yann Droneaud
  2019-02-27 18:23 ` [PATCH 7/7] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock Mike Crowe
                   ` (2 subsequent siblings)
  8 siblings, 2 replies; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

In preparation for adding pthread_rwlock_clockrdlock and
pthread_rwlock_clockwrlock, convert various tests to only use clock_gettime
and struct timespec.

* support/timespec.h: Create header to provide timespec helper functions
  from sysdeps/pthread/posix-timer.h for tests to use.

* nptl/tst-rwlock6.c: Fix small bug in timeout-checking code that could
  erroneously pass if the function incorrectly took more than a second.

* nptl/tst-rwlock6.c: Use clock_gettime(2) rather than gettimeofday(2) and
  then converting to timespec in preparation for testing
  pthread_rwlock_clockrdclock and pthread_rwlock_clockwrlock.

* nptl/tst-rwlock9.c, nptl/tst-rwlock7.c: Likewise.
---
 nptl/tst-rwlock6.c | 47 ++++++++++++++++++-----------------------------
 nptl/tst-rwlock7.c | 43 +++++++++++++++++--------------------------
 nptl/tst-rwlock9.c |  8 ++------
 support/timespec.h | 27 +++++++++++++++++++++++++++-
 4 files changed, 64 insertions(+), 61 deletions(-)
 create mode 100644 support/timespec.h

diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
index 8d6c3dc..67119fa 100644
--- a/nptl/tst-rwlock6.c
+++ b/nptl/tst-rwlock6.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
+#include <support/timespec.h>
 
 
 static int kind[] =
@@ -38,21 +39,15 @@ tf (void *arg)
   pthread_rwlock_t *r = arg;
 
   /* Timeout: 0.3 secs.  */
-  struct timeval tv;
-  (void) gettimeofday (&tv, NULL);
+  struct timespec ts_start;
+  (void) clock_gettime(CLOCK_REALTIME, &ts_start);
 
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC (&tv, &ts);
-  ts.tv_nsec += 300000000;
-  if (ts.tv_nsec >= 1000000000)
-    {
-      ts.tv_nsec -= 1000000000;
-      ++ts.tv_sec;
-    }
+  struct timespec ts_timeout = {0, 300000000};
+  timespec_add(&ts_timeout, &ts_start, &ts_timeout);
 
   puts ("child calling timedrdlock");
 
-  int err = pthread_rwlock_timedrdlock (r, &ts);
+  int err = pthread_rwlock_timedrdlock (r, &ts_timeout);
   if (err == 0)
     {
       puts ("rwlock_timedrdlock returned");
@@ -68,24 +63,24 @@ tf (void *arg)
 
   puts ("1st child timedrdlock done");
 
-  struct timeval tv2;
-  (void) gettimeofday (&tv2, NULL);
+  struct timespec ts_end;
+  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
 
-  timersub (&tv2, &tv, &tv);
+  struct timespec ts_duration;
+  timespec_sub(&ts_duration, &ts_end, &ts_start);
 
-  if (tv.tv_usec < 200000)
+  if (ts_duration.tv_sec !=0 || ts_duration.tv_nsec < 200000000)
     {
       puts ("timeout too short");
       pthread_exit ((void *) 1l);
     }
 
-  (void) gettimeofday (&tv, NULL);
-  TIMEVAL_TO_TIMESPEC (&tv, &ts);
-  ts.tv_sec += 10;
+  (void) clock_gettime (CLOCK_REALTIME, &ts_timeout);
+  ts_timeout.tv_sec += 10;
   /* Note that the following operation makes ts invalid.  */
-  ts.tv_nsec += 1000000000;
+  ts_timeout.tv_nsec += 1000000000;
 
-  err = pthread_rwlock_timedrdlock (r, &ts);
+  err = pthread_rwlock_timedrdlock (r, &ts_timeout);
   if (err == 0)
     {
       puts ("2nd timedrdlock succeeded");
@@ -136,12 +131,8 @@ do_test (void)
 	  exit (1);
 	}
 
-      struct timeval tv;
-      (void) gettimeofday (&tv, NULL);
-
       struct timespec ts;
-      TIMEVAL_TO_TIMESPEC (&tv, &ts);
-
+      (void) clock_gettime (CLOCK_REALTIME, &ts);
       ++ts.tv_sec;
 
       /* Get a write lock.  */
@@ -154,8 +145,7 @@ do_test (void)
 
       puts ("1st timedwrlock done");
 
-      (void) gettimeofday (&tv, NULL);
-      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      (void) clock_gettime (CLOCK_REALTIME, &ts);
       ++ts.tv_sec;
       e = pthread_rwlock_timedrdlock (&r, &ts);
       if (e == 0)
@@ -171,8 +161,7 @@ do_test (void)
 
       puts ("1st timedrdlock done");
 
-      (void) gettimeofday (&tv, NULL);
-      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      (void) clock_gettime (CLOCK_REALTIME, &ts);
       ++ts.tv_sec;
       e = pthread_rwlock_timedwrlock (&r, &ts);
       if (e == 0)
diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
index 4d6f561..812506c 100644
--- a/nptl/tst-rwlock7.c
+++ b/nptl/tst-rwlock7.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
+#include <support/timespec.h>
 
 
 static int kind[] =
@@ -38,19 +39,12 @@ tf (void *arg)
   pthread_rwlock_t *r = arg;
 
   /* Timeout: 0.3 secs.  */
-  struct timeval tv;
-  (void) gettimeofday (&tv, NULL);
+  struct timespec ts_start;
+  (void) clock_gettime (CLOCK_REALTIME, &ts_start);
+  struct timespec ts_timeout = {0, 300000000};
+  timespec_add(&ts_timeout, &ts_start, &ts_timeout);
 
-  struct timespec ts;
-  TIMEVAL_TO_TIMESPEC (&tv, &ts);
-  ts.tv_nsec += 300000000;
-  if (ts.tv_nsec >= 1000000000)
-    {
-      ts.tv_nsec -= 1000000000;
-      ++ts.tv_sec;
-    }
-
-  int err = pthread_rwlock_timedwrlock (r, &ts);
+  int err = pthread_rwlock_timedwrlock (r, &ts_timeout);
   if (err == 0)
     {
       puts ("rwlock_timedwrlock returned");
@@ -65,24 +59,24 @@ tf (void *arg)
     }
   puts ("child: timedwrlock failed with ETIMEDOUT");
 
-  struct timeval tv2;
-  (void) gettimeofday (&tv2, NULL);
-
-  timersub (&tv2, &tv, &tv);
+  struct timespec ts_end;
+  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
+  struct timespec ts_diff;
+  timespec_sub (&ts_diff, &ts_end, &ts_start);
 
-  if (tv.tv_usec < 200000)
+  if (ts_diff.tv_sec != 0 || ts_diff.tv_nsec < 200000000)
     {
       puts ("timeout too short");
       pthread_exit ((void *) 1l);
     }
 
-  (void) gettimeofday (&tv, NULL);
-  TIMEVAL_TO_TIMESPEC (&tv, &ts);
-  ts.tv_sec += 10;
+  struct timespec ts_invalid;
+  (void) clock_gettime (CLOCK_REALTIME, &ts_invalid);
+  ts_invalid.tv_sec += 10;
   /* Note that the following operation makes ts invalid.  */
-  ts.tv_nsec += 1000000000;
+  ts_invalid.tv_nsec += 1000000000000;
 
-  err = pthread_rwlock_timedwrlock (r, &ts);
+  err = pthread_rwlock_timedwrlock (r, &ts_invalid);
   if (err == 0)
     {
       puts ("2nd timedwrlock succeeded");
@@ -132,11 +126,8 @@ do_test (void)
 	  exit (1);
 	}
 
-      struct timeval tv;
-      (void) gettimeofday (&tv, NULL);
-
       struct timespec ts;
-      TIMEVAL_TO_TIMESPEC (&tv, &ts);
+      (void) clock_gettime (CLOCK_REALTIME, &ts);
 
       ++ts.tv_sec;
 
diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
index 34f2d04..ff15f90 100644
--- a/nptl/tst-rwlock9.c
+++ b/nptl/tst-rwlock9.c
@@ -56,9 +56,7 @@ writer_thread (void *nr)
       int e;
       do
 	{
-	  struct timeval tv;
-	  (void) gettimeofday (&tv, NULL);
-	  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+	  (void) clock_gettime (CLOCK_REALTIME, &ts);
 
 	  ts.tv_nsec += 2 * TIMEOUT;
 	  if (ts.tv_nsec >= 1000000000)
@@ -110,9 +108,7 @@ reader_thread (void *nr)
       int e;
       do
 	{
-	  struct timeval tv;
-	  (void) gettimeofday (&tv, NULL);
-	  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+	  (void) clock_gettime (CLOCK_REALTIME, &ts);
 
 	  ts.tv_nsec += TIMEOUT;
 	  if (ts.tv_nsec >= 1000000000)
diff --git a/support/timespec.h b/support/timespec.h
new file mode 100644
index 0000000..e5c89df
--- /dev/null
+++ b/support/timespec.h
@@ -0,0 +1,27 @@
+static inline void
+timespec_sub (struct timespec *diff, const struct timespec *left,
+	      const struct timespec *right)
+{
+  diff->tv_sec = left->tv_sec - right->tv_sec;
+  diff->tv_nsec = left->tv_nsec - right->tv_nsec;
+
+  if (diff->tv_nsec < 0)
+    {
+      --diff->tv_sec;
+      diff->tv_nsec += 1000000000;
+    }
+}
+
+static inline void
+timespec_add (struct timespec *sum, const struct timespec *left,
+	      const struct timespec *right)
+{
+  sum->tv_sec = left->tv_sec + right->tv_sec;
+  sum->tv_nsec = left->tv_nsec + right->tv_nsec;
+
+  if (sum->tv_nsec >= 1000000000)
+    {
+      ++sum->tv_sec;
+      sum->tv_nsec -= 1000000000;
+    }
+}
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH 7/7] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
                   ` (5 preceding siblings ...)
  2019-02-27 18:23 ` [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval Mike Crowe
@ 2019-02-27 18:23 ` Mike Crowe
  2019-03-07 12:59   ` Adhemerval Zanella
  2019-03-05 12:35 ` [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Adhemerval Zanella
  2019-03-15 13:25 ` Yann Droneaud
  8 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-02-27 18:23 UTC (permalink / raw)
  To: libc-alpha; +Cc: Mike Crowe

Add:
 int pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock,
                                 clockid_t clockid,
                                 const struct timespec *abstime)
and:
 int pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock,
                                 clockid_t clockid,
                                 const struct timespec *abstime)

which behave like pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock
respectively, except they always measure abstime against the supplied
clockid. The functions currently support CLOCK_REALTIME and CLOCK_MONOTONIC
and return EINVAL if any other clock is specified.

* sysdeps/nptl/pthread.h: Add pthread_rwlock_clockrdlock and
  pthread_wrlock_clockwrlock.

* nptl/Makefile: Build pthread_rwlock_clockrdlock.c and
  pthread_rwlock_clockwrlock.c.

* nptl/pthread_rwlock_clockrdlock.c: Implement pthread_rwlock_clockrdlock.

* nptl/pthread_rwlock_clockwrlock.c: Implement pthread_rwlock_clockwrlock.

* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Add clockid
  parameter and verify that it indicates a supported clock on entry so that
  we fail even if it doesn't end up being used. Pass that clock on to
  futex_abstimed_wait when necessary. (__pthread_rwlock_wrlock_full):
  Likewise.

* nptl/pthread_rwlock_rdlock.c: (__pthread_rwlock_rdlock): Pass
  CLOCK_REALTIME to __pthread_rwlock_rdlock_full even though it won't be
  used because there's no timeout.

* nptl/pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Pass
  CLOCK_REALTIME to __pthread_rwlock_wrlock_full even though it won't be
  used because there is no timeout.

* nptl/pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock): Pass
  CLOCK_REALTIME to __pthread_rwlock_rdlock_full since abstime uses that
  clock.

* nptl/pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock): Pass
  CLOCK_REALTIME to __pthread_rwlock_wrlock_full since abstime uses that
  clock.

* nptl/tst-abstime.c (th): Add pthread_rwlock_clockrdlock and
  pthread_rwlock_clockwrlock timeout tests to match the existing
  pthread_rwlock_timedrdloock and pthread_rwlock_timedwrlock tests.

* nptl/tst-rwlock14.c (do_test): Likewise.

* nptl/tst-rwlock6.c (tf): Accept thread_args structure so that both a
  rwlock and a clockid can be passed to the thread. (do_test_clock): Accept
  clockid parameter to specify test clock. Use the magic clockid value of
  CLOCK_USE_TIMEDLOCK to indicate that pthread_rwlock_timedrdlock and
  pthread_rwlock_timedwrlock should be tested, otherwise pass the specified
  clockid to pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock.
  (do_test): Call do_test_clock to test each clockid in turn.

* nptl/tst-rwlock7.c: Likewise, but also pass the name of the function being
  tested to improve error reporting.

* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept thread_args
  structure so that both the (now int) thread number and clockid can be
  passed to the thread. (do_test_clock): Pass the necessary thread_args
  when creating the reader and writer threads. (do_test): Call
  do_test_clock to test each clockid in turn.

* manual/threads.texi: Add documentation for pthread_rwlock_clockrdlock and
  pthread_rwlock_clockwrclock.
---
 manual/threads.texi                                  |  28 ++-
 nptl/Makefile                                        |   2 +-
 nptl/Versions                                        |   1 +-
 nptl/pthread_rwlock_clockrdlock.c                    |  27 ++-
 nptl/pthread_rwlock_clockwrlock.c                    |  27 ++-
 nptl/pthread_rwlock_common.c                         |  40 +--
 nptl/pthread_rwlock_rdlock.c                         |   2 +-
 nptl/pthread_rwlock_timedrdlock.c                    |   2 +-
 nptl/pthread_rwlock_timedwrlock.c                    |   2 +-
 nptl/pthread_rwlock_wrlock.c                         |   2 +-
 nptl/tst-abstime.c                                   |  28 ++-
 nptl/tst-rwlock14.c                                  | 147 ++++++++++++-
 nptl/tst-rwlock6.c                                   | 105 ++++++---
 nptl/tst-rwlock7.c                                   |  75 ++++--
 nptl/tst-rwlock9.c                                   |  86 +++++--
 sysdeps/nptl/pthread.h                               |   8 +-
 sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   2 +-
 17 files changed, 491 insertions(+), 93 deletions(-)
 create mode 100644 nptl/pthread_rwlock_clockrdlock.c
 create mode 100644 nptl/pthread_rwlock_clockwrlock.c

diff --git a/manual/threads.texi b/manual/threads.texi
index 91462f5..83b8bb6 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -699,6 +699,34 @@ specified or defaulted when @code{pthread_cond_init} was called. Currently,
 @code{CLOCK_REALTIME}.
 @end deftypefun
 
+@comment pthread.h
+@comment POSIX-proposed
+@deftypefun int pthread_rwlock_clockrdlock (pthread_rwlock_t *@var{rwlock},
+				       clockid_t @var{clockid},
+				       const struct timespec *@var{abstime})
+
+@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
+Behaves like @code{pthread_rwlock_timedrdlock} except the time
+@var{abstime} is measured against the clock specified by @var{clockid}
+rather than @code{CLOCK_REALTIME}. Currently, @var{clockid} must be either
+@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}, otherwise @code{EINVAL} is
+returned.
+@end deftypefun
+
+@comment pthread.h
+@comment POSIX-proposed
+@deftypefun int pthread_rwlock_clockwrlock (pthread_rwlock_t *@var{rwlock},
+				       clockid_t @var{clockid},
+				       const struct timespec *@var{abstime})
+
+@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
+Behaves like @code{pthread_rwlock_timedwrlock} except the time
+@var{abstime} is measured against the clock specified by @var{clockid}
+rather than @code{CLOCK_REALTIME}. Currently, @var{clockid} must be either
+@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}, otherwise @code{EINVAL} is
+returned.
+@end deftypefun
+
 @c FIXME these are undocumented:
 @c pthread_atfork
 @c pthread_attr_destroy
diff --git a/nptl/Makefile b/nptl/Makefile
index 7de4d40..f5e6d90 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -76,7 +76,9 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
 		      pthread_mutexattr_gettype pthread_mutexattr_settype \
 		      pthread_rwlock_init pthread_rwlock_destroy \
 		      pthread_rwlock_rdlock pthread_rwlock_timedrdlock \
+		      pthread_rwlock_clockrdlock \
 		      pthread_rwlock_wrlock pthread_rwlock_timedwrlock \
+		      pthread_rwlock_clockwrlock \
 		      pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \
 		      pthread_rwlock_unlock \
 		      pthread_rwlockattr_init pthread_rwlockattr_destroy \
diff --git a/nptl/Versions b/nptl/Versions
index 8c094d0..ce79959 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -279,6 +279,7 @@ libpthread {
 
   GLIBC_2.30 {
     sem_clockwait; pthread_cond_clockwait;
+    pthread_rwlock_clockrdlock; pthread_rwlock_clockwrlock;
   }
 
   GLIBC_PRIVATE {
diff --git a/nptl/pthread_rwlock_clockrdlock.c b/nptl/pthread_rwlock_clockrdlock.c
new file mode 100644
index 0000000..a6c7456
--- /dev/null
+++ b/nptl/pthread_rwlock_clockrdlock.c
@@ -0,0 +1,27 @@
+/* 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 "pthread_rwlock_common.c"
+
+/* See pthread_rwlock_common.c.  */
+int
+pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock,
+    clockid_t clockid,
+    const struct timespec *abstime)
+{
+  return __pthread_rwlock_rdlock_full (rwlock, clockid, abstime);
+}
diff --git a/nptl/pthread_rwlock_clockwrlock.c b/nptl/pthread_rwlock_clockwrlock.c
new file mode 100644
index 0000000..d248a2a
--- /dev/null
+++ b/nptl/pthread_rwlock_clockwrlock.c
@@ -0,0 +1,27 @@
+/* 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 "pthread_rwlock_common.c"
+
+/* See pthread_rwlock_common.c.  */
+int
+pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock,
+    clockid_t clockid,
+    const struct timespec *abstime)
+{
+  return __pthread_rwlock_wrlock_full (rwlock, clockid, abstime);
+}
diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
index 120b880..50a366e 100644
--- a/nptl/pthread_rwlock_common.c
+++ b/nptl/pthread_rwlock_common.c
@@ -278,17 +278,19 @@ __pthread_rwlock_rdunlock (pthread_rwlock_t *rwlock)
 
 static __always_inline int
 __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
+    clockid_t clockid,
     const struct timespec *abstime)
 {
   unsigned int r;
 
-  /* Make sure any passed in timeout value is valid.  Note that the previous
-     implementation assumed that this check *must* not be performed if there
-     would in fact be no blocking; however, POSIX only requires that "the
-     validity of the abstime parameter need not be checked if the lock can be
-     immediately acquired" (i.e., we need not but may check it).  */
-  if (abstime
-      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
+  /* Make sure any passed in clockid and timeout value are valid. Note
+     that the previous implementation assumed that this check *must*
+     not be performed if there would in fact be no blocking; however,
+     POSIX only requires that "the validity of the abstime parameter
+     need not be checked if the lock can be immediately acquired"
+     (i.e., we need not but may check it). */
+  if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid)
+      || abstime->tv_nsec >= 1000000000
       || abstime->tv_nsec < 0))
     return EINVAL;
 
@@ -329,7 +331,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, CLOCK_REALTIME, abstime, private);
+						 r, clockid, 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)
@@ -457,7 +459,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
 	    continue;
 	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
 					 1 | PTHREAD_RWLOCK_FUTEX_USED,
-					 CLOCK_REALTIME, abstime, private);
+					 clockid, abstime, private);
 	  if (err == ETIMEDOUT)
 	    {
 	      /* If we timed out, we need to unregister.  If no read phase
@@ -584,15 +586,17 @@ __pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock)
 
 static __always_inline int
 __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
+    clockid_t clockid,
     const struct timespec *abstime)
 {
-  /* Make sure any passed in timeout value is valid.  Note that the previous
-     implementation assumed that this check *must* not be performed if there
-     would in fact be no blocking; however, POSIX only requires that "the
-     validity of the abstime parameter need not be checked if the lock can be
-     immediately acquired" (i.e., we need not but may check it).  */
-  if (abstime
-      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
+  /* Make sure any passed in clockid and timeout value are valid. Note
+     that the previous implementation assumed that this check *must*
+     not be performed if there would in fact be no blocking; however,
+     POSIX only requires that "the validity of the abstime parameter
+     need not be checked if the lock can be immediately acquired"
+     (i.e., we need not but may check it). */
+  if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid)
+      || abstime->tv_nsec >= 1000000000
       || abstime->tv_nsec < 0))
     return EINVAL;
 
@@ -727,7 +731,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
 	  may_share_futex_used_flag = true;
 	  int err = futex_abstimed_wait (&rwlock->__data.__writers_futex,
 					 1 | PTHREAD_RWLOCK_FUTEX_USED,
-					 CLOCK_REALTIME, abstime, private);
+					 clockid, abstime, private);
 	  if (err == ETIMEDOUT)
 	    {
 	      if (prefer_writer)
@@ -826,7 +830,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
 	    continue;
 	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
 					 PTHREAD_RWLOCK_FUTEX_USED,
-					 CLOCK_REALTIME, abstime, private);
+					 clockid, abstime, private);
 	  if (err == ETIMEDOUT)
 	    {
 	      if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP)
diff --git a/nptl/pthread_rwlock_rdlock.c b/nptl/pthread_rwlock_rdlock.c
index 5fdc89e..387c824 100644
--- a/nptl/pthread_rwlock_rdlock.c
+++ b/nptl/pthread_rwlock_rdlock.c
@@ -24,7 +24,7 @@ __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
 {
   LIBC_PROBE (rdlock_entry, 1, rwlock);
 
-  int result = __pthread_rwlock_rdlock_full (rwlock, NULL);
+  int result = __pthread_rwlock_rdlock_full (rwlock, CLOCK_REALTIME, NULL);
   LIBC_PROBE (rdlock_acquire_read, 1, rwlock);
   return result;
 }
diff --git a/nptl/pthread_rwlock_timedrdlock.c b/nptl/pthread_rwlock_timedrdlock.c
index 84c1983..8f8e680 100644
--- a/nptl/pthread_rwlock_timedrdlock.c
+++ b/nptl/pthread_rwlock_timedrdlock.c
@@ -23,5 +23,5 @@ int
 pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
     const struct timespec *abstime)
 {
-  return __pthread_rwlock_rdlock_full (rwlock, abstime);
+  return __pthread_rwlock_rdlock_full (rwlock, CLOCK_REALTIME, abstime);
 }
diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c
index f0b745d..a5616de 100644
--- a/nptl/pthread_rwlock_timedwrlock.c
+++ b/nptl/pthread_rwlock_timedwrlock.c
@@ -23,5 +23,5 @@ int
 pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
     const struct timespec *abstime)
 {
-  return __pthread_rwlock_wrlock_full (rwlock, abstime);
+  return __pthread_rwlock_wrlock_full (rwlock, CLOCK_REALTIME, abstime);
 }
diff --git a/nptl/pthread_rwlock_wrlock.c b/nptl/pthread_rwlock_wrlock.c
index 194a14c..da246d8 100644
--- a/nptl/pthread_rwlock_wrlock.c
+++ b/nptl/pthread_rwlock_wrlock.c
@@ -24,7 +24,7 @@ __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
 {
   LIBC_PROBE (wrlock_entry, 1, rwlock);
 
-  int result = __pthread_rwlock_wrlock_full (rwlock, NULL);
+  int result = __pthread_rwlock_wrlock_full (rwlock, CLOCK_REALTIME, NULL);
   LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
   return result;
 }
diff --git a/nptl/tst-abstime.c b/nptl/tst-abstime.c
index 71610f8..f4c9f2d 100644
--- a/nptl/tst-abstime.c
+++ b/nptl/tst-abstime.c
@@ -47,12 +47,40 @@ th (void *arg)
       puts ("pthread_rwlock_timedrdlock did not return ETIMEDOUT");
       res = 1;
     }
+  r = pthread_rwlock_clockrdlock (&rw1, CLOCK_REALTIME, &t);
+  if (r != ETIMEDOUT)
+    {
+      puts ("pthread_rwlock_clockrdlock (CLOCK_REALTIME) "
+	    "did not return ETIMEDOUT");
+      res = 1;
+    }
+  r = pthread_rwlock_clockrdlock (&rw1, CLOCK_MONOTONIC, &t);
+  if (r != ETIMEDOUT)
+    {
+      puts ("pthread_rwlock_clockrdlock (CLOCK_MONOTONIC) "
+	    "did not return ETIMEDOUT");
+      res = 1;
+    }
   r = pthread_rwlock_timedwrlock (&rw2, &t);
   if (r != ETIMEDOUT)
     {
       puts ("pthread_rwlock_timedwrlock did not return ETIMEDOUT");
       res = 1;
     }
+  r = pthread_rwlock_clockwrlock (&rw2, CLOCK_REALTIME, &t);
+  if (r != ETIMEDOUT)
+    {
+      puts ("pthread_rwlock_clockwrlock(CLOCK_REALTIME) "
+	    "did not return ETIMEDOUT");
+      res = 1;
+    }
+  r = pthread_rwlock_clockwrlock (&rw2, CLOCK_MONOTONIC, &t);
+  if (r != ETIMEDOUT)
+    {
+      puts ("pthread_rwlock_clockwrlock(CLOCK_MONOTONIC) "
+	    "did not return ETIMEDOUT");
+      res = 1;
+    }
   return (void *) res;
 }
 
diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c
index 6f57169..525ceac 100644
--- a/nptl/tst-rwlock14.c
+++ b/nptl/tst-rwlock14.c
@@ -91,6 +91,30 @@ do_test (void)
       result = 1;
     }
 
+  e = pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts);
+  if (e == 0)
+    {
+      puts ("first rwlock_clockrdlock (CLOCK_REALTIME) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first rwlock_clockrdlock (CLOCK_REALTIME) did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts);
+  if (e == 0)
+    {
+      puts ("first rwlock_clockrdlock (CLOCK_MONOTONIC) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first rwlock_clockrdlock (CLOCK_MONOTONIC) did not return EINVAL");
+      result = 1;
+    }
+
   e = pthread_rwlock_timedwrlock (&r, &ts);
   if (e == 0)
     {
@@ -103,6 +127,30 @@ do_test (void)
       result = 1;
     }
 
+  e = pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts);
+  if (e == 0)
+    {
+      puts ("first rwlock_clockwrlock (CLOCK_REALTIME) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first rwlock_clockwrlock (CLOCK_REALTIME) did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts);
+  if (e == 0)
+    {
+      puts ("first rwlock_clockwrlock (CLOCK_MONOTONIC) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("first rwlock_clockwrlock (CLOCK_MONOTONIC) did not return EINVAL");
+      result = 1;
+    }
+
   ts.tv_nsec = 1000000000;
 
   e = pthread_rwlock_timedrdlock (&r, &ts);
@@ -117,6 +165,31 @@ do_test (void)
       result = 1;
     }
 
+  e = pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts);
+  if (e == 0)
+    {
+      puts ("second rwlock_clockrdlock (CLOCK_REALTIME) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second rwlock_clockrdlock (CLOCK_REALTIME) did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts);
+  if (e == 0)
+    {
+      puts ("second rwlock_clockrdlock (CLOCK_MONOTONIC) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second rwlock_clockrdlock (CLOCK_MONOTONIC) "
+	    "did not return EINVAL");
+      result = 1;
+    }
+
   e = pthread_rwlock_timedwrlock (&r, &ts);
   if (e == 0)
     {
@@ -129,6 +202,32 @@ do_test (void)
       result = 1;
     }
 
+  e = pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts);
+  if (e == 0)
+    {
+      puts ("second rwlock_clockwrlock (CLOCK_MONOTONIC) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second rwlock_clockwrlock (CLOCK_MONOTONIC) "
+	    "did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts);
+  if (e == 0)
+    {
+      puts ("second rwlock_clockwrlock (CLOCK_REALTIME) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("second rwlock_clockwrlock (CLOCK_REALTIME) "
+	    "did not return EINVAL");
+      result = 1;
+    }
+
   ts.tv_nsec = (__typeof (ts.tv_nsec)) 0x100001000LL;
   if ((__typeof (ts.tv_nsec)) 0x100001000LL != 0x100001000LL)
     ts.tv_nsec = 2000000000;
@@ -145,6 +244,30 @@ do_test (void)
       result = 1;
     }
 
+  e = pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts);
+  if (e == 0)
+    {
+      puts ("third rwlock_clockrdlock (CLOCK_REALTIME) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("third rwlock_clockrdlock (CLOCK_REALTIME) did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts);
+  if (e == 0)
+    {
+      puts ("third rwlock_clockrdlock(CLOCK_MONOTONIC) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("third rwlock_clockrdlock (CLOCK_MONOTONIC) did not return EINVAL");
+      result = 1;
+    }
+
   e = pthread_rwlock_timedwrlock (&r, &ts);
   if (e == 0)
     {
@@ -157,6 +280,30 @@ do_test (void)
       result = 1;
     }
 
+  e = pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts);
+  if (e == 0)
+    {
+      puts ("third rwlock_clockwrlock (CLOCK_REALTIME) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("third rwlock_clockwrlock (CLOCK_REALTIME) did not return EINVAL");
+      result = 1;
+    }
+
+  e = pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts);
+  if (e == 0)
+    {
+      puts ("third rwlock_clockwrlock (CLOCK_MONOTONIC) did not fail");
+      result = 1;
+    }
+  else if (e != EINVAL)
+    {
+      puts ("third rwlock_clockwrlock (CLOCK_MONOTONIC) did not return EINVAL");
+      result = 1;
+    }
+
   if (result == 0)
     puts ("no bugs");
 
diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
index 67119fa..708915e 100644
--- a/nptl/tst-rwlock6.c
+++ b/nptl/tst-rwlock6.c
@@ -25,6 +25,11 @@
 #include <support/timespec.h>
 
 
+/* A bogus clock value that tells run_test to use
+   pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock rather
+   than pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock. */
+#define CLOCK_USE_TIMEDLOCK (-1)
+
 static int kind[] =
   {
     PTHREAD_RWLOCK_PREFER_READER_NP,
@@ -32,75 +37,91 @@ static int kind[] =
     PTHREAD_RWLOCK_PREFER_WRITER_NP,
   };
 
+struct thread_args {
+  pthread_rwlock_t *rwlock;
+  clockid_t clockid;
+  const char *fnname;
+};
 
 static void *
 tf (void *arg)
 {
-  pthread_rwlock_t *r = arg;
+  struct thread_args *args = arg;
+  pthread_rwlock_t *r = args->rwlock;
+  const clockid_t clockid = args->clockid;
+  const clockid_t clockid_for_get =
+    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
+  const char *fnname = args->fnname;
 
   /* Timeout: 0.3 secs.  */
   struct timespec ts_start;
-  (void) clock_gettime(CLOCK_REALTIME, &ts_start);
+  (void) clock_gettime (clockid_for_get, &ts_start);
 
   struct timespec ts_timeout = {0, 300000000};
-  timespec_add(&ts_timeout, &ts_start, &ts_timeout);
+  timespec_add (&ts_timeout, &ts_start, &ts_timeout);
 
-  puts ("child calling timedrdlock");
+  printf ("child calling %srdlock\n", fnname);
 
-  int err = pthread_rwlock_timedrdlock (r, &ts_timeout);
+  int err = (clockid == CLOCK_USE_TIMEDLOCK)
+    ? pthread_rwlock_timedrdlock (r, &ts_timeout)
+    : pthread_rwlock_clockrdlock (r, clockid, &ts_timeout);
   if (err == 0)
     {
-      puts ("rwlock_timedrdlock returned");
+      printf ("%srdlock returned\n", fnname);
       pthread_exit ((void *) 1l);
     }
 
   if (err != ETIMEDOUT)
     {
-      printf ("err = %s (%d), expected %s (%d)\n",
-	      strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
+      printf ("%srdlock: err = %s (%d), expected %s (%d)\n",
+	      fnname, strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
       pthread_exit ((void *) 1l);
     }
 
-  puts ("1st child timedrdlock done");
+  printf ("1st child %srdlock done\n", fnname);
 
   struct timespec ts_end;
-  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
+  (void) clock_gettime (clockid_for_get, &ts_end);
 
   struct timespec ts_duration;
-  timespec_sub(&ts_duration, &ts_end, &ts_start);
+  timespec_sub (&ts_duration, &ts_end, &ts_start);
 
   if (ts_duration.tv_sec !=0 || ts_duration.tv_nsec < 200000000)
     {
-      puts ("timeout too short");
+      printf ("%srdlock: timeout too short\n", fnname);
       pthread_exit ((void *) 1l);
     }
 
-  (void) clock_gettime (CLOCK_REALTIME, &ts_timeout);
+  (void) clock_gettime (clockid_for_get, &ts_timeout);
   ts_timeout.tv_sec += 10;
   /* Note that the following operation makes ts invalid.  */
   ts_timeout.tv_nsec += 1000000000;
 
-  err = pthread_rwlock_timedrdlock (r, &ts_timeout);
+  err = (clockid == CLOCK_USE_TIMEDLOCK)
+    ? pthread_rwlock_timedrdlock (r, &ts_timeout)
+    : pthread_rwlock_clockrdlock (r, clockid, &ts_timeout);
   if (err == 0)
     {
-      puts ("2nd timedrdlock succeeded");
+      printf ("2nd %srdlock succeeded\n", fnname);
       pthread_exit ((void *) 1l);
     }
   if (err != EINVAL)
     {
-      puts ("2nd timedrdlock did not return EINVAL");
+      printf ("2nd %srdlock did not return EINVAL\n", fnname);
       pthread_exit ((void *) 1l);
     }
 
-  puts ("2nd child timedrdlock done");
+  printf ("2nd child %srdlock done\n", fnname);
 
   return NULL;
 }
 
 
 static int
-do_test (void)
+do_test_clock (clockid_t clockid, const char *fnname)
 {
+  const clockid_t clockid_for_get =
+    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
   size_t cnt;
   for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
     {
@@ -132,53 +153,63 @@ do_test (void)
 	}
 
       struct timespec ts;
-      (void) clock_gettime (CLOCK_REALTIME, &ts);
+      (void) clock_gettime (clockid_for_get, &ts);
       ++ts.tv_sec;
 
       /* Get a write lock.  */
-      int e = pthread_rwlock_timedwrlock (&r, &ts);
+      int e = (clockid == CLOCK_USE_TIMEDLOCK)
+	? pthread_rwlock_timedwrlock (&r, &ts)
+	: pthread_rwlock_clockwrlock (&r, clockid, &ts);
       if (e != 0)
 	{
-	  printf ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e);
+	  printf ("round %Zu: %swrlock failed (%d)\n", cnt, fnname, e);
 	  exit (1);
 	}
 
-      puts ("1st timedwrlock done");
+      printf ("1st %swrlock done\n", fnname);
 
-      (void) clock_gettime (CLOCK_REALTIME, &ts);
+      (void) clock_gettime (clockid, &ts);
       ++ts.tv_sec;
-      e = pthread_rwlock_timedrdlock (&r, &ts);
+      e = (clockid == CLOCK_USE_TIMEDLOCK)
+	? pthread_rwlock_timedrdlock (&r, &ts)
+	: pthread_rwlock_clockrdlock (&r, clockid, &ts);
       if (e == 0)
 	{
-	  puts ("timedrdlock succeeded");
+	  printf ("%srdlock succeeded\n", fnname);
 	  exit (1);
 	}
       if (e != EDEADLK)
 	{
-	  puts ("timedrdlock did not return EDEADLK");
+	  printf ("%srdlock did not return EDEADLK\n", fnname);
 	  exit (1);
 	}
 
-      puts ("1st timedrdlock done");
+      printf ("1st %srdlock done\n", fnname);
 
-      (void) clock_gettime (CLOCK_REALTIME, &ts);
+      (void) clock_gettime (clockid_for_get, &ts);
       ++ts.tv_sec;
-      e = pthread_rwlock_timedwrlock (&r, &ts);
+      e = (clockid == CLOCK_USE_TIMEDLOCK)
+	? pthread_rwlock_timedwrlock (&r, &ts)
+	: pthread_rwlock_clockwrlock (&r, clockid, &ts);
       if (e == 0)
 	{
-	  puts ("2nd timedwrlock succeeded");
+	  printf ("2nd %swrlock succeeded\n", fnname);
 	  exit (1);
 	}
       if (e != EDEADLK)
 	{
-	  puts ("2nd timedwrlock did not return EDEADLK");
+	  printf ("2nd %swrlock did not return EDEADLK\n", fnname);
 	  exit (1);
 	}
 
-      puts ("2nd timedwrlock done");
+      printf ("2nd %swrlock done\n", fnname);
 
       pthread_t th;
-      if (pthread_create (&th, NULL, tf, &r) != 0)
+      struct thread_args args;
+      args.rwlock = &r;
+      args.clockid = clockid;
+      args.fnname = fnname;
+      if (pthread_create (&th, NULL, tf, &args) != 0)
 	{
 	  printf ("round %Zu: create failed\n", cnt);
 	  exit (1);
@@ -210,5 +241,13 @@ do_test (void)
   return 0;
 }
 
+static int do_test (void)
+{
+  do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
+  do_test_clock (CLOCK_REALTIME, "clock(realtime)");
+  do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
+  return 0;
+}
+
 #define TEST_FUNCTION do_test ()
 #include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
index 812506c..0bccd18 100644
--- a/nptl/tst-rwlock7.c
+++ b/nptl/tst-rwlock7.c
@@ -25,6 +25,11 @@
 #include <support/timespec.h>
 
 
+/* A bogus clock value that tells run_test to use
+   pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock rather
+   than pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock. */
+#define CLOCK_USE_TIMEDLOCK (-1)
+
 static int kind[] =
   {
     PTHREAD_RWLOCK_PREFER_READER_NP,
@@ -32,22 +37,34 @@ static int kind[] =
     PTHREAD_RWLOCK_PREFER_WRITER_NP,
   };
 
+struct thread_args
+{
+  pthread_rwlock_t *rwlock;
+  clockid_t clockid;
+  const char *fnname;
+};
 
 static void *
 tf (void *arg)
 {
-  pthread_rwlock_t *r = arg;
+  struct thread_args *args = arg;
+  pthread_rwlock_t *r = args->rwlock;
+  clockid_t clockid = args->clockid;
+  const char *fnname = args->fnname;
 
   /* Timeout: 0.3 secs.  */
   struct timespec ts_start;
-  (void) clock_gettime (CLOCK_REALTIME, &ts_start);
+  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
+			? CLOCK_REALTIME : clockid, &ts_start);
   struct timespec ts_timeout = {0, 300000000};
   timespec_add(&ts_timeout, &ts_start, &ts_timeout);
 
-  int err = pthread_rwlock_timedwrlock (r, &ts_timeout);
+  int err = (clockid == CLOCK_USE_TIMEDLOCK)
+    ? pthread_rwlock_timedwrlock (r, &ts_timeout)
+    : pthread_rwlock_clockwrlock (r, clockid, &ts_timeout);
   if (err == 0)
     {
-      puts ("rwlock_timedwrlock returned");
+      printf ("pthread_rwlock_%swrlock returned\n", fnname);
       pthread_exit ((void *) 1l);
     }
 
@@ -57,44 +74,49 @@ tf (void *arg)
 	      strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
       pthread_exit ((void *) 1l);
     }
-  puts ("child: timedwrlock failed with ETIMEDOUT");
+  printf ("child: pthread_rwlock_%swrlock failed with ETIMEDOUT\n", fnname);
 
   struct timespec ts_end;
-  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
+  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
+			? CLOCK_REALTIME : clockid, &ts_end);
   struct timespec ts_diff;
   timespec_sub (&ts_diff, &ts_end, &ts_start);
 
   if (ts_diff.tv_sec != 0 || ts_diff.tv_nsec < 200000000)
     {
-      puts ("timeout too short");
+      printf ("pthread_rwlock_%srwlock timeout too short: %ld.%09ld\n",
+	      fnname, (long)ts_diff.tv_sec, (long)ts_diff.tv_nsec);
       pthread_exit ((void *) 1l);
     }
 
   struct timespec ts_invalid;
-  (void) clock_gettime (CLOCK_REALTIME, &ts_invalid);
+  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
+			? CLOCK_REALTIME : clockid, &ts_invalid);
   ts_invalid.tv_sec += 10;
   /* Note that the following operation makes ts invalid.  */
   ts_invalid.tv_nsec += 1000000000000;
 
-  err = pthread_rwlock_timedwrlock (r, &ts_invalid);
+  err = (clockid == CLOCK_USE_TIMEDLOCK)
+	 ? pthread_rwlock_timedwrlock (r, &ts_invalid)
+	 : pthread_rwlock_clockwrlock (r, clockid, &ts_invalid);
   if (err == 0)
     {
-      puts ("2nd timedwrlock succeeded");
+      printf ("2nd pthread_%srwlock succeeded\n", fnname);
       pthread_exit ((void *) 1l);
     }
   if (err != EINVAL)
     {
-      puts ("2nd timedwrlock did not return EINVAL");
+      printf ("2nd pthread_%srwlock did not return EINVAL\n", fnname);
       pthread_exit ((void *) 1l);
     }
-  puts ("child: timedwrlock failed with EINVAL");
+  printf ("child: %s failed with EINVAL\n", fnname);
 
   return NULL;
 }
 
 
 static int
-do_test (void)
+do_test_clock (clockid_t clockid, const char *fnname)
 {
   size_t cnt;
   for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
@@ -127,20 +149,27 @@ do_test (void)
 	}
 
       struct timespec ts;
-      (void) clock_gettime (CLOCK_REALTIME, &ts);
+      (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK) ?
+			    CLOCK_REALTIME: clockid, &ts);
 
       ++ts.tv_sec;
 
       /* Get a read lock.  */
-      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
+      if ((clockid == CLOCK_USE_TIMEDLOCK)
+	  ? pthread_rwlock_timedrdlock (&r, &ts)
+	  : pthread_rwlock_clockrdlock (&r, clockid, &ts) != 0)
 	{
-	  printf ("round %Zu: rwlock_timedrdlock failed\n", cnt);
+	  printf ("round %Zu: pthread_rwlock%srdlock failed\n", cnt, fnname);
 	  exit (1);
 	}
-      printf ("%zu: got timedrdlock\n", cnt);
+      printf ("%zu: got pthread_rwlock_%srdlock\n", cnt, fnname);
 
+      struct thread_args args;
+      args.rwlock = &r;
+      args.clockid = clockid;
+      args.fnname = fnname;
       pthread_t th;
-      if (pthread_create (&th, NULL, tf, &r) != 0)
+      if (pthread_create (&th, NULL, tf, &args) != 0)
 	{
 	  printf ("round %Zu: create failed\n", cnt);
 	  exit (1);
@@ -168,5 +197,15 @@ do_test (void)
   return 0;
 }
 
+static int
+do_test (void)
+{
+  do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
+  do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
+  do_test_clock (CLOCK_REALTIME, "clock(realtime)");
+
+  return 0;
+}
+
 #define TEST_FUNCTION do_test ()
 #include "../test-skeleton.c"
diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
index ff15f90..2691f6a 100644
--- a/nptl/tst-rwlock9.c
+++ b/nptl/tst-rwlock9.c
@@ -38,12 +38,28 @@
 # define KIND PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
 #endif
 
+/* A bogus clock value that tells the tests to use
+   pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock rather
+   than pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock. */
+#define CLOCK_USE_TIMEDLOCK (-1)
+
 static pthread_rwlock_t lock;
 
+struct thread_args
+{
+  int nr;
+  clockid_t clockid;
+  const char *fnname;
+};
 
 static void *
-writer_thread (void *nr)
+writer_thread (void *arg)
 {
+  struct thread_args *args = arg;
+  const int nr = args->nr;
+  const clockid_t clockid = args->clockid;
+  const char *fnname = args->fnname;
+
   struct timespec ts;
   struct timespec delay;
   int n;
@@ -56,7 +72,8 @@ writer_thread (void *nr)
       int e;
       do
 	{
-	  (void) clock_gettime (CLOCK_REALTIME, &ts);
+	  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
+				? CLOCK_REALTIME : clockid, &ts);
 
 	  ts.tv_nsec += 2 * TIMEOUT;
 	  if (ts.tv_nsec >= 1000000000)
@@ -65,18 +82,20 @@ writer_thread (void *nr)
 	      ++ts.tv_sec;
 	    }
 
-	  printf ("writer thread %ld tries again\n", (long int) nr);
+	  printf ("writer thread %d tries again\n", nr);
 
-	  e = pthread_rwlock_timedwrlock (&lock, &ts);
+	  e = (clockid == CLOCK_USE_TIMEDLOCK)
+	    ? pthread_rwlock_timedwrlock (&lock, &ts)
+	    : pthread_rwlock_clockwrlock (&lock, clockid, &ts);
 	  if (e != 0 && e != ETIMEDOUT)
 	    {
-	      puts ("timedwrlock failed");
+	      printf ("%swrlock failed", fnname);
 	      exit (1);
 	    }
 	}
       while (e == ETIMEDOUT);
 
-      printf ("writer thread %ld succeeded\n", (long int) nr);
+      printf ("writer thread %d succeeded\n", nr);
 
       nanosleep (&delay, NULL);
 
@@ -86,7 +105,7 @@ writer_thread (void *nr)
 	  exit (1);
 	}
 
-      printf ("writer thread %ld released\n", (long int) nr);
+      printf ("writer thread %d released\n", nr);
     }
 
   return NULL;
@@ -94,8 +113,13 @@ writer_thread (void *nr)
 
 
 static void *
-reader_thread (void *nr)
+reader_thread (void *arg)
 {
+  struct thread_args *args = arg;
+  const int nr = args->nr;
+  const clockid_t clockid = args->clockid;
+  const char *fnname = args->fnname;
+
   struct timespec ts;
   struct timespec delay;
   int n;
@@ -108,8 +132,8 @@ reader_thread (void *nr)
       int e;
       do
 	{
-	  (void) clock_gettime (CLOCK_REALTIME, &ts);
-
+	  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
+				? CLOCK_REALTIME : clockid, &ts);
 	  ts.tv_nsec += TIMEOUT;
 	  if (ts.tv_nsec >= 1000000000)
 	    {
@@ -117,18 +141,20 @@ reader_thread (void *nr)
 	      ++ts.tv_sec;
 	    }
 
-	  printf ("reader thread %ld tries again\n", (long int) nr);
+	  printf ("reader thread %d tries again\n", nr);
 
-	  e = pthread_rwlock_timedrdlock (&lock, &ts);
+	  e = (clockid == CLOCK_USE_TIMEDLOCK)
+	    ? pthread_rwlock_timedrdlock (&lock, &ts)
+	    : pthread_rwlock_clockrdlock (&lock, clockid, &ts);
 	  if (e != 0 && e != ETIMEDOUT)
 	    {
-	      puts ("timedrdlock failed");
+	      printf ("%srdlock failed\n", fnname);
 	      exit (1);
 	    }
 	}
       while (e == ETIMEDOUT);
 
-      printf ("reader thread %ld succeeded\n", (long int) nr);
+      printf ("reader thread %d succeeded\n", nr);
 
       nanosleep (&delay, NULL);
 
@@ -138,7 +164,7 @@ reader_thread (void *nr)
 	  exit (1);
 	}
 
-      printf ("reader thread %ld released\n", (long int) nr);
+      printf ("reader thread %d released\n", nr);
     }
 
   return NULL;
@@ -146,7 +172,7 @@ reader_thread (void *nr)
 
 
 static int
-do_test (void)
+do_test_clock (clockid_t clockid, const char *fnname)
 {
   pthread_t thwr[NWRITERS];
   pthread_t thrd[NREADERS];
@@ -178,21 +204,31 @@ do_test (void)
   /* Make sure we see all message, even those on stdout.  */
   setvbuf (stdout, NULL, _IONBF, 0);
 
-  for (n = 0; n < NWRITERS; ++n)
+  struct thread_args wargs[NWRITERS];
+  for (n = 0; n < NWRITERS; ++n) {
+    wargs[n].nr = n;
+    wargs[n].clockid = clockid;
+    wargs[n].fnname = fnname;
     if (pthread_create (&thwr[n], NULL, writer_thread,
-			(void *) (long int) n) != 0)
+			&wargs[n]) != 0)
       {
 	puts ("writer create failed");
 	exit (1);
       }
+  }
 
-  for (n = 0; n < NREADERS; ++n)
+  struct thread_args rargs[NREADERS];
+  for (n = 0; n < NREADERS; ++n) {
+    rargs[n].nr = n;
+    rargs[n].clockid = clockid;
+    rargs[n].fnname = fnname;
     if (pthread_create (&thrd[n], NULL, reader_thread,
-			(void *) (long int) n) != 0)
+			&rargs[n]) != 0)
       {
 	puts ("reader create failed");
 	exit (1);
       }
+  }
 
   /* Wait for all the threads.  */
   for (n = 0; n < NWRITERS; ++n)
@@ -211,6 +247,16 @@ do_test (void)
   return 0;
 }
 
+static int
+do_test (void)
+{
+  do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
+  do_test_clock (CLOCK_REALTIME, "clock(realtime)");
+  do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
+
+  return 0;
+}
+
 #undef TIMEOUT
 #define TIMEOUT 30
 #define TEST_FUNCTION do_test ()
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index d4fe9d9..3c06d77 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -907,6 +907,10 @@ extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
 extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
 				       const struct timespec *__restrict
 				       __abstime) __THROWNL __nonnull ((1, 2));
+extern int pthread_rwlock_clockrdlock (pthread_rwlock_t *__restrict __rwlock,
+				       clockid_t __clockid,
+				       const struct timespec *__restrict
+				       __abstime) __THROWNL __nonnull ((1, 3));
 # endif
 
 /* Acquire write lock for RWLOCK.  */
@@ -922,6 +926,10 @@ extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
 extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
 				       const struct timespec *__restrict
 				       __abstime) __THROWNL __nonnull ((1, 2));
+extern int pthread_rwlock_clockwrlock (pthread_rwlock_t *__restrict __rwlock,
+				       clockid_t __clockid,
+				       const struct timespec *__restrict
+				       __abstime) __THROWNL __nonnull ((1, 3));
 # endif
 
 /* Unlock RWLOCK.  */
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
index aaa1c3b..70f04cc 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
@@ -246,6 +246,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
 GLIBC_2.3.4 pthread_setaffinity_np F
 GLIBC_2.3.4 pthread_setschedprio F
 GLIBC_2.30 pthread_cond_clockwait F
+GLIBC_2.30 pthread_rwlock_clockrdlock F
+GLIBC_2.30 pthread_rwlock_clockwrlock F
 GLIBC_2.30 sem_clockwait F
 GLIBC_2.4 pthread_mutex_consistent_np F
 GLIBC_2.4 pthread_mutex_getprioceiling F
-- 
git-series 0.9.1

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-02-27 18:23 ` [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Mike Crowe
@ 2019-02-27 18:35   ` Joseph Myers
  2019-03-05 13:31   ` Adhemerval Zanella
  2019-03-14 14:09   ` Yann Droneaud
  2 siblings, 0 replies; 33+ messages in thread
From: Joseph Myers @ 2019-02-27 18:35 UTC (permalink / raw)
  To: Mike Crowe; +Cc: libc-alpha

On Wed, 27 Feb 2019, Mike Crowe wrote:

> * conform/data/semaphore.h-data: Likewise.

No, that's not appropriate; conform/ baselines are always for existing 
standards, not what might appear in a new standard version.  These 
functions are not part of any current version of POSIX.  If a future 
version of POSIX (issue 8) adds them, the conform/ expectations will need 
to be conditional so that the functions are only expected for POSIXyyyy || 
XOPENyyyy (where yyyy is the year of the new POSIX version in 
_POSIX_C_SOURCE), not for any previous standard version.

The same of course applies to declarations in installed headers - they 
should initially be conditional on __USE_GNU, potentially changing to a 
new __USE_* macro when there's a new verison of POSIX.  That applies to 
all the functions, in all the patches.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
                   ` (6 preceding siblings ...)
  2019-02-27 18:23 ` [PATCH 7/7] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock Mike Crowe
@ 2019-03-05 12:35 ` Adhemerval Zanella
  2019-03-06 21:15   ` Joseph Myers
  2019-03-13 21:42   ` Mike Crowe
  2019-03-15 13:25 ` Yann Droneaud
  8 siblings, 2 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 12:35 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> My attempts[1] to add a variant of pthread_cond_timedwait that would accept
> a clockid_t parameter led me to propose[2] to The Austin Group the addition
> of an entire family of functions that accept a clockid_t parameter to
> indicate the clock that the timespec absolute timeout parameter should be
> measured against. They responded positively to the request but an
> implementation is required before the proposal can proceed.

Thanks for the work on sorting this out and bring to Austin Group discussion.
The discussion links are quite elucidative and I agree with the rationale to 
add the new API.

> 
> This patch series is the first part of that implementation in glibc, it
> contains four new functions:
> 
> int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
>                            clockid_t clock, const struct timespec *abstime)
> 
> int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clock,
>                                const struct timespec *abstime)
> 
> int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clock,
>                                const struct timespec *abstime)
> 
> int sem_clockwait(sem_t *restrict, clockid_t clock_id, const struct
>                   timespec *restrict)
> 
> These are implemented by replacing the underlying equivalent _timed
> functions with ones that accept a clockid_t parameter, and then
> implementing the existing _timed functions by passing CLOCK_REALTIME to the
> new implementation. This requires clockid_t parameters to be added to the
> underlying futex-internal and lowlevellock-futex functions.

I am not sure about how to name a new API in this specific case where
the idea is to use as a reference one for POSIX inclusion.  MY understanding 
is we still should use a non-portable name scheme with _np suffix and whence
it is de factor accepted by POSIX we can just alias to the standard
names. Also if it is done before the release I think we can avoid exporting 
the _np naming scheme.

> 
> pthread_mutex_clocklock is not yet implemented because doing so requires a
> version of __lll_timedlock_wait that supports both CLOCK_MONOTONIC and
> CLOCK_REALTIME. This function is currently architecture specific. I plan to
> work on that next, if these changes are considered acceptable.

About that I think we can work towards once my lowlevellock.S cleanup
is accepted [4]. Once __lll_timedlock_wait is implemented in generic
way it would be much more easier to add such extension.

[1] https://sourceware.org/ml/libc-alpha/2019-02/msg00569.html

> 
> The mq_clockreceive and mq_clocksend functions corresponding to
> mq_timedreceive and mq_timedsend require kernel changes before they can be
> implemented in glibc.

Should we add them as ENOSYS as generic stubs in this version?
Because it seems the kernel work required would be just add a new
syscall on ipc/mqueue.c to receive a clock_id since 
schedule_hrtimeout_range_clock already handle CLOCK_MONOTONIC
(and it luckily fits on 6 argument syscall limit).

> 
> As implemented, passing an unsupported or invalid clock to these functions
> yields EINVAL. I considered returning ENOTSUP for valid-but-unsupported
> clocks, but I was worried that there was a risk that the list of valid
> clocks would not be updated when a new clock was added to glibc.

I think either error signalling will have the same outcome: without glibc
updating internally its supported clock ids when issuing futex syscalls 
internally programs won't be able to actually use new clocks in recent kernels.

The only possible way to avoid this issue is if we get a guarantee from kernel
that at N-bits on the futex_op argument will be used for clock identification
so we can just pass the clock_id directly on syscall.  It assumes we don't need
to actually change its representation when calling the syscall and that kernel
will fail for unsupported clocks.

> 
> A number of tests have been updated to use struct timespec rather than
> struct timeval so that they can call clock_gettime(CLOCK_MONOTONIC) rather
> then gettimeofday. To make this easier I created the support/timespec.h
> header file to contain functions to add and subtract timespec structures
> borrowed from sysdeps/pthread/posix-timer.h. There's probably a better
> place for these, but I don't know where that might be.

I think you forgot to update this part since you seemed to had chose
to use support/timespec.h instead.

> 
> Rather than duplicating tests, I've parameterised them so that the same
> tests can be run on the existing timedwait functions and the new clockwait
> functions.
> 
> The changes have been tested with "make check" on x86_64 and arm64. Earlier
> versions were tested on arm. I haven't updated the ChangeLog, NEWS or
> architecture abilists yet (so some tests fail on arm64), but will do so if
> the rest of the changes are acceptable.

Are arm64 failures related to the patchset itself?

> 
> Thanks to everyone that commented on previous versions of this patch (when
> the single new function was called pthread_cond_timedwaitonclock_np.) They
> have been a great help, and I hope that I have incorporated their feedback
> correctly.
> 
> [1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
> [2] http://austingroupbugs.net/view.php?id=1216> 
> Mike Crowe (7):
>   nptl: Add clockid parameter to futex timed wait calls
>   nptl: Add POSIX-proposed sem_clockwait
>   nptl: Add POSIX-proposed pthread_cond_clockwait
>   nptl: pthread_rwlock: Move timeout validation into _full functions
>   nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly
>   nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval
>   nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock
> 
>  conform/data/semaphore.h-data                        |   1 +-
>  manual/threads.texi                                  |  58 ++++-
>  nptl/Makefile                                        |   8 +-
>  nptl/Versions                                        |   5 +-
>  nptl/forward.c                                       |   5 +-
>  nptl/nptl-init.c                                     |   1 +-
>  nptl/pthreadP.h                                      |   4 +-
>  nptl/pthread_cond_wait.c                             |  45 ++-
>  nptl/pthread_mutex_timedlock.c                       |   8 +-
>  nptl/pthread_rwlock_clockrdlock.c                    |  27 ++-
>  nptl/pthread_rwlock_clockwrlock.c                    |  27 ++-
>  nptl/pthread_rwlock_common.c                         |  32 +-
>  nptl/pthread_rwlock_rdlock.c                         |   2 +-
>  nptl/pthread_rwlock_timedrdlock.c                    |  12 +-
>  nptl/pthread_rwlock_timedwrlock.c                    |  12 +-
>  nptl/pthread_rwlock_wrlock.c                         |   2 +-
>  nptl/sem_clockwait.c                                 |  45 +++-
>  nptl/sem_timedwait.c                                 |   3 +-
>  nptl/sem_wait.c                                      |   3 +-
>  nptl/sem_waitcommon.c                                |  15 +-
>  nptl/tst-abstime.c                                   |  28 ++-
>  nptl/tst-cond11.c                                    |  30 +-
>  nptl/tst-cond26.c                                    |  91 +++++++-
>  nptl/tst-cond27.c                                    | 113 +++++++++-
>  nptl/tst-rwlock14.c                                  | 159 +++++++++++-
>  nptl/tst-rwlock6.c                                   | 132 ++++++----
>  nptl/tst-rwlock7.c                                   | 108 +++++---
>  nptl/tst-rwlock9.c                                   |  90 +++++--
>  nptl/tst-sem13.c                                     |  50 +++-
>  nptl/tst-sem17.c                                     |  57 ++++-
>  nptl/tst-sem5.c                                      |  30 +-
>  support/timespec.h                                   |  27 ++-
>  sysdeps/nptl/futex-internal.h                        |   7 +-
>  sysdeps/nptl/lowlevellock-futex.h                    |  14 +-
>  sysdeps/nptl/pthread-functions.h                     |   4 +-
>  sysdeps/nptl/pthread.h                               |  21 ++-
>  sysdeps/pthread/semaphore.h                          |   4 +-
>  sysdeps/unix/sysv/linux/futex-internal.h             |  26 +-
>  sysdeps/unix/sysv/linux/lowlevellock-futex.h         |  29 +-
>  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   4 +-
>  40 files changed, 1124 insertions(+), 215 deletions(-)
>  create mode 100644 nptl/pthread_rwlock_clockrdlock.c
>  create mode 100644 nptl/pthread_rwlock_clockwrlock.c
>  create mode 100644 nptl/sem_clockwait.c
>  create mode 100644 nptl/tst-cond26.c
>  create mode 100644 nptl/tst-cond27.c
>  create mode 100644 nptl/tst-sem17.c
>  create mode 100644 support/timespec.h
> 
> base-commit: a04549c19407a29a271779598a9518f9baf959e0
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls
  2019-02-27 18:23 ` [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls Mike Crowe
@ 2019-03-05 12:39   ` Adhemerval Zanella
  2019-03-10  8:59     ` Mike Crowe
  0 siblings, 1 reply; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 12:39 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> In preparation for adding POSIX clockwait variants of timedwait functions,
> add a clockid_t parameter to futex_abstimed_wait functions and pass
> CLOCK_REALTIME from all callers for the time being.
> 
> Replace lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset which
> takes a clockid_t parameter rather than the magic clockbit.
> 
> * sysdeps/nptl/lowlevellock-futex.h,
>   sysdeps/unix/sysv/linux/lowlevellock-futex.h: Replace
>   lll_futex_timed_wait_bitset with lll_futex_clock_wait_bitset that takes a
>   clockid rather than a special clockbit.
> 
> * sysdeps/nptl/lowlevellock-futex.h: Add lll_futex_supported_clockid so
>   that client functions can check whether their clockid parameter is valid
>   even if they don't ultimately end up calling lll_futex_clock_wait_bitset.
> 
> * sysdeps/nptl/futex-internal.h, sysdeps/unix/sysv/linux/futex-internal.h
>   (futex_abstimed_wait, futex_abstimed_wait_cancelable): Add clockid_t
>   parameter to indicate which clock the absolute time passed should be
>   measured against. Pass that clockid onto lll_futex_clock_wait_bitset.
>   Add invalid clock as reason for returning -EINVAL.
> 
> * sysdeps/nptl/futex-internal.h, sysdeps/unix/sysv/linux/futex-internal.h:
>   Introduce futex_abstimed_supported_clockid so that client functions can
>   check whether their clockid parameter is valid even if they don't
>   ultimately end up calling futex_abstimed_wait.
> 
> * nptl/pthread_cond_wait.c (__pthread_cond_wait_common),
>   nptl/pthread_rwlock_common (__pthread_rwlock_rdlock_full,
>   __pthread_wrlock_full), nptl/sem_waitcommon (do_futex_wait): Pass
>   additional CLOCK_REALTIME to futex_abstimed_wait_cancelable.
> 
> * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Switch to
>   lll_futex_clock_wait_bitset and pass CLOCK_REALTIME
> ---
>  nptl/pthread_cond_wait.c                     |  2 +-
>  nptl/pthread_mutex_timedlock.c               |  8 +++---
>  nptl/pthread_rwlock_common.c                 |  8 +++---
>  nptl/sem_waitcommon.c                        |  6 ++--
>  sysdeps/nptl/futex-internal.h                |  7 +++++-
>  sysdeps/nptl/lowlevellock-futex.h            | 14 ++++++----
>  sysdeps/unix/sysv/linux/futex-internal.h     | 26 +++++++++++++------
>  sysdeps/unix/sysv/linux/lowlevellock-futex.h | 29 ++++++++++++++++-----
>  8 files changed, 71 insertions(+), 29 deletions(-)
> 
> diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
> index 9a0f29e..daa4e25 100644
> --- a/nptl/pthread_cond_wait.c
> +++ b/nptl/pthread_cond_wait.c
> @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>  		{
>  		  /* Use CLOCK_REALTIME.  */
>  		  err = futex_abstimed_wait_cancelable
> -		      (cond->__data.__g_signals + g, 0, abstime, private);
> +		      (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private);
>  		}
>  	    }
>  

Since we still assume that an architecture might not support futex
with CLOCK_REALTIME, this part should check for __ASSUME_FUTEX_CLOCK_REALTIME
as other parts.

I proposed recently to just assume __ASSUME_FUTEX_CLOCK_REALTIME
support [1], which simplifies this patch.

[1] https://sourceware.org/ml/libc-alpha/2019-02/msg00667.html

> diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
> index 2f61a7d..c145a65 100644
> --- a/nptl/pthread_mutex_timedlock.c
> +++ b/nptl/pthread_mutex_timedlock.c
> @@ -241,7 +241,7 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
>  	  if (__glibc_unlikely (abstime->tv_sec < 0))
>  	    return ETIMEDOUT;
>  #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
> -     || !defined lll_futex_timed_wait_bitset)
> +     || !defined lll_futex_clock_wait_bitset)
>  	  struct timeval tv;
>  	  struct timespec rt;
>  
> @@ -288,12 +288,12 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex,
>  
>  	  /* Block using the futex.  */
>  #if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
> -     || !defined lll_futex_timed_wait_bitset)
> +     || !defined lll_futex_clock_wait_bitset)
>  	  lll_futex_timed_wait (&mutex->__data.__lock, oldval,
>  				&rt, PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
>  #else
> -	  int err = lll_futex_timed_wait_bitset (&mutex->__data.__lock,
> -	      oldval, abstime, FUTEX_CLOCK_REALTIME,
> +	  int err = lll_futex_clock_wait_bitset (&mutex->__data.__lock,
> +	      oldval, CLOCK_REALTIME, abstime,
>  	      PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
>  	  /* The futex call timed out.  */
>  	  if (err == -ETIMEDOUT)
> diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
> index 2560734..89ba21a 100644
> --- a/nptl/pthread_rwlock_common.c
> +++ b/nptl/pthread_rwlock_common.c
> @@ -319,7 +319,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
>  		{
>  		  int private = __pthread_rwlock_get_private (rwlock);
>  		  int err = futex_abstimed_wait (&rwlock->__data.__readers,
> -						 r, abstime, private);
> +						 r, CLOCK_REALTIME, abstime, private);
>  		  /* We ignore EAGAIN and EINTR.  On time-outs, we can just
>  		     return because we don't need to clean up anything.  */
>  		  if (err == ETIMEDOUT)
> @@ -447,7 +447,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
>  	    continue;
>  	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
>  					 1 | PTHREAD_RWLOCK_FUTEX_USED,
> -					 abstime, private);
> +					 CLOCK_REALTIME, abstime, private);
>  	  if (err == ETIMEDOUT)
>  	    {
>  	      /* If we timed out, we need to unregister.  If no read phase
> @@ -707,7 +707,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
>  	  may_share_futex_used_flag = true;
>  	  int err = futex_abstimed_wait (&rwlock->__data.__writers_futex,
>  					 1 | PTHREAD_RWLOCK_FUTEX_USED,
> -					 abstime, private);
> +					 CLOCK_REALTIME, abstime, private);
>  	  if (err == ETIMEDOUT)
>  	    {
>  	      if (prefer_writer)
> @@ -806,7 +806,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
>  	    continue;
>  	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
>  					 PTHREAD_RWLOCK_FUTEX_USED,
> -					 abstime, private);
> +					 CLOCK_REALTIME, abstime, private);
>  	  if (err == ETIMEDOUT)
>  	    {
>  	      if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP)
> diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c
> index 5646bea..425d040 100644
> --- a/nptl/sem_waitcommon.c
> +++ b/nptl/sem_waitcommon.c
> @@ -109,11 +109,13 @@ do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
>  
>  #if __HAVE_64B_ATOMICS
>    err = futex_abstimed_wait_cancelable (
> -      (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, abstime,
> +      (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0,
> +      CLOCK_REALTIME, abstime,
>        sem->private);
>  #else
>    err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK,
> -					abstime, sem->private);
> +					CLOCK_REALTIME, abstime,
> +					sem->private);
>  #endif
>  
>    return err;
> diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
> index 86a0818..54b7319 100644
> --- a/sysdeps/nptl/futex-internal.h
> +++ b/sysdeps/nptl/futex-internal.h
> @@ -159,16 +159,23 @@ futex_reltimed_wait_cancelable (unsigned int* futex_word,
>  				unsigned int expected,
>  			        const struct timespec* reltime, int private);
>  
> +/* Check whether the specified clockid is supported by
> +   futex_abstimed_wait and futex_abstimed_wait_cancelable. */
> +static __always_inline int
> +futex_abstimed_supported_clockid (clockid_t clockid);
> +
>  /* Like futex_reltimed_wait, but the provided timeout (ABSTIME) is an
>     absolute point in time; a call will time out after this point in time.  */
>  static __always_inline int
>  futex_abstimed_wait (unsigned int* futex_word, unsigned int expected,
> +		     clockid_t clockid,
>  		     const struct timespec* abstime, int private);
>  
>  /* Like futex_reltimed_wait but is a POSIX cancellation point.  */
>  static __always_inline int
>  futex_abstimed_wait_cancelable (unsigned int* futex_word,
>  				unsigned int expected,
> +				clockid_t clockid,
>  			        const struct timespec* abstime, int private);
>  
>  /* Atomically wrt other futex operations on the same futex, this unblocks the
> diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h
> index bb8effe..35fcfbb 100644
> --- a/sysdeps/nptl/lowlevellock-futex.h
> +++ b/sysdeps/nptl/lowlevellock-futex.h
> @@ -43,11 +43,15 @@
>  #define lll_futex_timed_wait(futexp, val, timeout, private)             \
>    -ENOSYS
>  
> -/* This macro should be defined only if FUTEX_CLOCK_REALTIME is also defined.
> -   If CLOCKBIT is zero, this is identical to lll_futex_timed_wait.
> -   If CLOCKBIT has FUTEX_CLOCK_REALTIME set, then it's the same but
> -   TIMEOUT is counted by CLOCK_REALTIME rather than CLOCK_MONOTONIC.  */
> -#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \
> +/* Verify whether the supplied clockid is supported by
> +   lll_futex_clock_wait_bitset */
> +#define lll_futex_supported_clockid(clockid)				\
> +  (0)
> +
> +/* Wait until a lll_futex_wake call on FUTEXP, or the absolute TIMEOUT
> +   measured against CLOCKID elapses. CLOCKID may be CLOCK_REALTIME or
> +   CLOCK_MONOTONIC. */
> +#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \
>    -ENOSYS
>  
>  /* Wake up up to NR waiters on FUTEXP.  */
> diff --git a/sysdeps/unix/sysv/linux/futex-internal.h b/sysdeps/unix/sysv/linux/futex-internal.h
> index 55f0fab..68bfe7e 100644
> --- a/sysdeps/unix/sysv/linux/futex-internal.h
> +++ b/sysdeps/unix/sysv/linux/futex-internal.h
> @@ -162,15 +162,24 @@ futex_reltimed_wait_cancelable (unsigned int *futex_word,
>  
>  /* See sysdeps/nptl/futex-internal.h for details.  */
>  static __always_inline int
> +futex_abstimed_supported_clockid (clockid_t clockid)
> +{
> +  return lll_futex_supported_clockid (clockid);
> +}
> +
> +/* See sysdeps/nptl/futex-internal.h for details.  */
> +static __always_inline int
>  futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
> +		     clockid_t clockid,
>  		     const struct timespec *abstime, int private)
>  {
>    /* Work around the fact that the kernel rejects negative timeout values
>       despite them being valid.  */
>    if (__glibc_unlikely ((abstime != NULL) && (abstime->tv_sec < 0)))
>      return ETIMEDOUT;
> -  int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
> -					 FUTEX_CLOCK_REALTIME, private);
> +  int err = lll_futex_clock_wait_bitset (futex_word, expected,
> +					 clockid, abstime,
> +					 private);
>    switch (err)
>      {
>      case 0:
> @@ -180,9 +189,10 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
>        return -err;
>  
>      case -EFAULT: /* Must have been caused by a glibc or application bug.  */
> -    case -EINVAL: /* Either due to wrong alignment or due to the timeout not
> -		     being normalized.  Must have been caused by a glibc or
> -		     application bug.  */
> +    case -EINVAL: /* Either due to wrong alignment, unsupported
> +		     clockid or due to the timeout not being
> +		     normalized. Must have been caused by a glibc or
> +		     application bug. */
>      case -ENOSYS: /* Must have been caused by a glibc bug.  */
>      /* No other errors are documented at this time.  */
>      default:
> @@ -194,6 +204,7 @@ futex_abstimed_wait (unsigned int *futex_word, unsigned int expected,
>  static __always_inline int
>  futex_abstimed_wait_cancelable (unsigned int *futex_word,
>  				unsigned int expected,
> +				clockid_t clockid,
>  			        const struct timespec *abstime, int private)
>  {
>    /* Work around the fact that the kernel rejects negative timeout values
> @@ -202,8 +213,9 @@ futex_abstimed_wait_cancelable (unsigned int *futex_word,
>      return ETIMEDOUT;
>    int oldtype;
>    oldtype = __pthread_enable_asynccancel ();
> -  int err = lll_futex_timed_wait_bitset (futex_word, expected, abstime,
> -					 FUTEX_CLOCK_REALTIME, private);
> +  int err = lll_futex_clock_wait_bitset (futex_word, expected,
> +					clockid, abstime,
> +					private);
>    __pthread_disable_asynccancel (oldtype);
>    switch (err)
>      {
> diff --git a/sysdeps/unix/sysv/linux/lowlevellock-futex.h b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
> index 6f060b1..c3e7152 100644
> --- a/sysdeps/unix/sysv/linux/lowlevellock-futex.h
> +++ b/sysdeps/unix/sysv/linux/lowlevellock-futex.h
> @@ -82,12 +82,29 @@
>  		     __lll_private_flag (FUTEX_WAIT, private),  \
>  		     val, timeout)
>  
> -#define lll_futex_timed_wait_bitset(futexp, val, timeout, clockbit, private) \
> -  lll_futex_syscall (6, futexp,                                         \
> -		     __lll_private_flag (FUTEX_WAIT_BITSET | (clockbit), \
> -					 private),                      \
> -		     val, timeout, NULL /* Unused.  */,                 \
> -		     FUTEX_BITSET_MATCH_ANY)
> +/* Verify whether the supplied clockid is supported by
> +   lll_futex_clock_wait_bitset */
> +#define lll_futex_supported_clockid(clockid)			\
> +  (clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC)

I think we need evaluate clockid with parentesis to avoid some macro
evaluation issues.

> +
> +/* The kernel currently only supports CLOCK_MONOTONIC or
> + * CLOCK_REALTIME timeouts for FUTEX_WAIT_BITSET. We could attempt to
> + * convert others here but currently do not.
> + */
> +#define lll_futex_clock_wait_bitset(futexp, val, clockid, timeout, private) \
> +  ({									\
> +    long int __ret;							\
> +    if (lll_futex_supported_clockid (clockid)) {			\

I think even for macro definitions we need to use GNU style for brackets
(which means break in a subsequent line).

> +      const unsigned int clockbit = (clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; \
> +      __ret = lll_futex_syscall (6, futexp,				\
> +				 __lll_private_flag (FUTEX_WAIT_BITSET | clockbit, \
> +						     private),		\
> +				 val, timeout, NULL /* Unused.  */,	\
> +				 FUTEX_BITSET_MATCH_ANY);		\
> +    } else								\
> +      __ret = -EINVAL;							\
> +    __ret;								\
> +  })
>  
>  #define lll_futex_wake(futexp, nr, private)                             \
>    lll_futex_syscall (4, futexp,                                         \
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-02-27 18:23 ` [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Mike Crowe
  2019-02-27 18:35   ` Joseph Myers
@ 2019-03-05 13:31   ` Adhemerval Zanella
  2019-03-10 16:17     ` Mike Crowe
  2019-03-14 14:09   ` Yann Droneaud
  2 siblings, 1 reply; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 13:31 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> Add:
> 
>  int sem_clockwait (sem_t *sem, clockid_t clock, const struct timespec *abstime)
> 
> which behaves just like sem_timedwait, but measures abstime against the
> specified clock. Currently supports CLOCK_REALTIME and CLOCK_MONOTONIC and
> sets errno == EINVAL if any other clock is specified.
> 
> * nptl/sem_waitcommon.c (do_futex_wait, __new_sem_wait_slow): Add clockid
>   parameters to indicate the clock which abstime should be measured against.
> 
> * nptl/sem_timedwait.c (sem_timedwait), nptl/sem_wait.c (__new_sem_wait): Pass
>   CLOCK_REALTIME as clockid to __new_sem_wait_slow.
> 
> * nptl/sem_clockwait.c: New file to implement sem_clockwait based on
>   sem_timedwait.c.
> 
> * nptl/Makefile: Add sem_clockwait.c source file. Add CFLAGS for
>   sem_clockwait.c to match those used for sem_timedwait.c.
> 
> * sysdeps/pthread/semaphore.h: Add sem_clockwait.
> 
> * nptl/Versions (GLIBC_2.30): Likewise.
> 
> * conform/data/semaphore.h-data: Likewise.
> 
> * sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Likewise.
> 
> * nptl/tst-sem17.c: Add new test for passing invalid clock to
>   sem_clockwait.
> 
> * nptl/tst-sem13.c, tst-sem5: Modify existing sem_timedwait tests to also
>   test sem_clockwait.
> 
> * manual/threads.texi: Document sem_clockwait.
> ---
>  conform/data/semaphore.h-data                        |  1 +-
>  manual/threads.texi                                  | 10 ++-
>  nptl/Makefile                                        |  5 +-
>  nptl/Versions                                        |  4 +-
>  nptl/sem_clockwait.c                                 | 45 ++++++++++-
>  nptl/sem_timedwait.c                                 |  3 +-
>  nptl/sem_wait.c                                      |  3 +-
>  nptl/sem_waitcommon.c                                | 15 +--
>  nptl/tst-sem13.c                                     | 50 +++++++++--
>  nptl/tst-sem17.c                                     | 57 +++++++++++++-
>  nptl/tst-sem5.c                                      | 30 ++++---
>  sysdeps/pthread/semaphore.h                          |  4 +-
>  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |  1 +-
>  13 files changed, 197 insertions(+), 31 deletions(-)
>  create mode 100644 nptl/sem_clockwait.c
>  create mode 100644 nptl/tst-sem17.c
> 
> diff --git a/conform/data/semaphore.h-data b/conform/data/semaphore.h-data
> index 066c2f7..019aaa1 100644
> --- a/conform/data/semaphore.h-data
> +++ b/conform/data/semaphore.h-data
> @@ -11,6 +11,7 @@ function {sem_t*} sem_open (const char*, int, ...)
>  function int sem_post (sem_t*)
>  # if !defined POSIX && !defined UNIX98
>  function int sem_timedwait (sem_t*, const struct timespec*)
> +function int sem_clockwait (sem_t*, clockid_t, const struct timespec*)
>  # endif
>  function int sem_trywait (sem_t*)
>  function int sem_unlink (const char*)
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 87fda7d..674267c 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -669,6 +669,16 @@ The system does not have sufficient memory.
>  @end table
>  @end deftypefun
>  
> +@comment semaphore.h
> +@comment POSIX-proposed
> +@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid},
> +                               const struct timespec *@var{abstime})
> +Behaves like @code{sem_timedwait} except the time @var{abstime} is measured
> +against the clock specified by @var{clockid} rather than
> +@code{CLOCK_REALTIME}. 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 5acfdcc..4c9f5d3 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -114,7 +114,7 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
>  		      sem_init sem_destroy \
>  		      sem_open sem_close sem_unlink \
>  		      sem_getvalue \
> -		      sem_wait sem_timedwait sem_post \
> +		      sem_wait sem_timedwait sem_clockwait sem_post \
>  		      cleanup cleanup_defer cleanup_compat \
>  		      cleanup_defer_compat unwind \
>  		      pt-longjmp pt-cleanup\
> @@ -194,6 +194,7 @@ CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \
>  CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables
>  CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables
>  CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables
> +CFLAGS-sem_clockwait.c = -fexceptions -fasynchronous-unwind-tables
>  
>  # These are the function wrappers we have to duplicate here.
>  CFLAGS-fcntl.c += -fexceptions -fasynchronous-unwind-tables
> @@ -263,7 +264,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
>  	tst-key1 tst-key2 tst-key3 tst-key4 \
>  	tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
>  	tst-sem8 tst-sem9 tst-sem10 tst-sem14 \
> -	tst-sem15 tst-sem16 \
> +	tst-sem15 tst-sem16 tst-sem17 \
>  	tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
>  	tst-align tst-align3 \
>  	tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
> diff --git a/nptl/Versions b/nptl/Versions
> index e7f691d..cd1806c 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -277,6 +277,10 @@ libpthread {
>      cnd_timedwait; cnd_wait; tss_create; tss_delete; tss_get; tss_set;
>    }
>  
> +  GLIBC_2.30 {
> +    sem_clockwait;
> +  }
> +
>    GLIBC_PRIVATE {
>      __pthread_initialize_minimal;
>      __pthread_clock_gettime; __pthread_clock_settime;
> diff --git a/nptl/sem_clockwait.c b/nptl/sem_clockwait.c
> new file mode 100644
> index 0000000..c0cd667
> --- /dev/null
> +++ b/nptl/sem_clockwait.c
> @@ -0,0 +1,45 @@
> +/* sem_clockwait -- wait on a semaphore with timeout using
> +   the specified clock.
> +
> +   Copyright (C) 2003-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 "sem_waitcommon.c"
> +
> +int
> +sem_clockwait (sem_t *sem, clockid_t clockid,
> +	       const struct timespec *abstime)
> +{
> +  /* Check that supplied clockid is one we support, even if we don't
> +     end up waiting. */
> +  if (!futex_abstimed_supported_clockid (clockid))
> +    {
> +      __set_errno (EINVAL);
> +      return -1;
> +    }
> +
> +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
> +    {
> +      __set_errno (EINVAL);
> +      return -1;
> +    }
> +
> +  if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
> +    return 0;
> +  else
> +    return __new_sem_wait_slow ((struct new_sem *) sem, clockid, abstime);
> +}
> diff --git a/nptl/sem_timedwait.c b/nptl/sem_timedwait.c
> index 3dd71ab..0918d8b 100644
> --- a/nptl/sem_timedwait.c
> +++ b/nptl/sem_timedwait.c
> @@ -36,5 +36,6 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
>    if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
>      return 0;
>    else
> -    return __new_sem_wait_slow((struct new_sem *) sem, abstime);
> +    return __new_sem_wait_slow ((struct new_sem *) sem,
> +				CLOCK_REALTIME, abstime);
>  }
> diff --git a/nptl/sem_wait.c b/nptl/sem_wait.c
> index 6a2d26b..20a8b9d 100644
> --- a/nptl/sem_wait.c
> +++ b/nptl/sem_wait.c
> @@ -39,7 +39,8 @@ __new_sem_wait (sem_t *sem)
>    if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
>      return 0;
>    else
> -    return __new_sem_wait_slow((struct new_sem *) sem, NULL);
> +    return __new_sem_wait_slow ((struct new_sem *) sem,
> +				CLOCK_REALTIME, NULL);
>  }
>  versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
>  
> diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c
> index 425d040..cad56e9 100644
> --- a/nptl/sem_waitcommon.c
> +++ b/nptl/sem_waitcommon.c
> @@ -103,19 +103,19 @@ __sem_wait_cleanup (void *arg)
>     users don't seem to need it.  */
>  static int
>  __attribute__ ((noinline))
> -do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
> +do_futex_wait (struct new_sem *sem, clockid_t clockid,
> +	       const struct timespec *abstime)
>  {
>    int err;
>  
>  #if __HAVE_64B_ATOMICS
>    err = futex_abstimed_wait_cancelable (
>        (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0,
> -      CLOCK_REALTIME, abstime,
> +      clockid, abstime,
>        sem->private);
>  #else
>    err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK,
> -					CLOCK_REALTIME, abstime,
> -					sem->private);
> +					clockid, abstime, sem->private);
>  #endif
>  
>    return err;
> @@ -162,7 +162,8 @@ __new_sem_wait_fast (struct new_sem *sem, int definitive_result)
>  /* Slow path that blocks.  */
>  static int
>  __attribute__ ((noinline))
> -__new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
> +__new_sem_wait_slow (struct new_sem *sem, clockid_t clockid,
> +		     const struct timespec *abstime)
>  {
>    int err = 0;
>  
> @@ -180,7 +181,7 @@ __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
>        /* If there is no token available, sleep until there is.  */
>        if ((d & SEM_VALUE_MASK) == 0)
>  	{
> -	  err = do_futex_wait (sem, abstime);
> +	  err = do_futex_wait (sem, clockid, abstime);
>  	  /* A futex return value of 0 or EAGAIN is due to a real or spurious
>  	     wake-up, or due to a change in the number of tokens.  We retry in
>  	     these cases.
> @@ -281,7 +282,7 @@ __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
>  	  if ((v >> SEM_VALUE_SHIFT) == 0)
>  	    {
>  	      /* See __HAVE_64B_ATOMICS variant.  */
> -	      err = do_futex_wait(sem, abstime);
> +	      err = do_futex_wait (sem, clockid, abstime);
>  	      if (err == ETIMEDOUT || err == EINTR)
>  		{
>  		  __set_errno (err);
> diff --git a/nptl/tst-sem13.c b/nptl/tst-sem13.c
> index 1560e91..0f76100 100644
> --- a/nptl/tst-sem13.c
> +++ b/nptl/tst-sem13.c
> @@ -5,9 +5,14 @@
>  #include <pthread.h>
>  #include <internaltypes.h>

Not a requisite, but since you are touching the testcase it might a
good time to change it to use libsupport.

>  
> +/* A bogus clock value that tells run_test to use
> +   sem_timedwait rather than sem_clockwait */
> +#define	CLOCK_USE_TIMEDWAIT (-1)
> +
> +typedef int (*waitfn_t)(sem_t *, struct timespec *);
>  
>  static int
> -do_test (void)
> +do_test_wait (waitfn_t waitfn, const char *fnname)
>  {
>    union
>    {
> @@ -23,14 +28,14 @@ do_test (void)
>  
>    struct timespec ts = { 0, 1000000001 };	/* Invalid.  */
>    errno = 0;
> -  if (sem_timedwait (&u.s, &ts) >= 0)
> +  if (waitfn (&u.s, &ts) >= 0)
>      {
> -      puts ("sem_timedwait did not fail");
> +      printf ("%s did not fail\n", fnname);
>        return 1;
>      }

Use TEST_VERIFY_EXIT (waitfn (&u.s, &ts) >= 0).

>    if (errno != EINVAL)
>      {
> -      perror ("sem_timedwait did not fail with EINVAL");
> +      printf ("%s did not fail with EINVAL: %m\n", fnname);
>        return 1;
>      }

Use TEST_COMPARE (errno, EINVAL).

>  #if __HAVE_64B_ATOMICS
> @@ -40,21 +45,21 @@ do_test (void)
>  #endif
>    if (nwaiters != 0)
>      {
> -      printf ("sem_timedwait modified nwaiters: %d\n", nwaiters);
> +      printf ("%s modified nwaiters: %d\n", fnname, nwaiters);
>        return 1;
>      }

Use TEST_COMPARE (nwaiters, 0).

>  
>    ts.tv_sec = /* Invalid.  */ -2;
>    ts.tv_nsec = 0;
>    errno = 0;
> -  if (sem_timedwait (&u.s, &ts) >= 0)
> +  if (waitfn (&u.s, &ts) >= 0)
>      {
> -      puts ("2nd sem_timedwait did not fail");
> +      printf ("2nd %s did not fail\n", fnname);
>        return 1;
>      }

As before.

>    if (errno != ETIMEDOUT)
>      {
> -      perror ("2nd sem_timedwait did not fail with ETIMEDOUT");
> +      printf ("2nd %s did not fail with ETIMEDOUT\n", fnname);
>        return 1;
>      }

As before.

>  #if __HAVE_64B_ATOMICS
> @@ -64,12 +69,39 @@ do_test (void)
>  #endif
>    if (nwaiters != 0)
>      {
> -      printf ("2nd sem_timedwait modified nwaiters: %d\n", nwaiters);
> +      printf ("2nd %s modified nwaiters: %d\n", fnname, nwaiters);
>        return 1;
>      }
>  
>    return 0;
>  }

As before.
>  
> +int test_sem_timedwait (sem_t *sem, struct timespec *ts)
> +{
> +  return sem_timedwait (sem, ts);
> +}
> +
> +int test_sem_clockwait_monotonic (sem_t *sem, struct timespec *ts)
> +{
> +  return sem_clockwait (sem, CLOCK_MONOTONIC, ts);
> +}
> +
> +int test_sem_clockwait_realtime (sem_t *sem, struct timespec *ts)
> +{
> +  return sem_clockwait (sem, CLOCK_REALTIME, ts);
> +}
> +
> +static int do_test (void)
> +{
> +  int result = 0;
> +  result |= do_test_wait (&test_sem_timedwait,
> +			 "sem_timedwait");
> +  result |= do_test_wait (&test_sem_clockwait_monotonic,
> +			 "sem_clockwait(monotonic)");
> +  result |= do_test_wait (&test_sem_clockwait_realtime,
> +			 "sem_clockwait(realtime)");
> +  return result;
> +}
> +

Using libsupport there is no need to actually keep track of failure
statue. Just call each do_test_wait and return 0.

>  #define TEST_FUNCTION do_test ()
>  #include "../test-skeleton.c"
> diff --git a/nptl/tst-sem17.c b/nptl/tst-sem17.c
> new file mode 100644
> index 0000000..a24ad0f
> --- /dev/null
> +++ b/nptl/tst-sem17.c
> @@ -0,0 +1,57 @@

Missing first line description.

> +/* 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 <semaphore.h>
> +#include <stdio.h>
> +#include <time.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +
> +#define NOT_A_VALID_CLOCK 123456
> +
> +static int
> +do_test (void)
> +{
> +  sem_t s;
> +  struct timespec ts;
> +
> +  if (sem_init (&s, 0, 1) == -1)
> +    {
> +      puts ("sem_init failed");
> +      return 1;
> +    }

TEST_COMPARE (sem_init (&s, 0, 1), 0).

> +
> +  ts.tv_sec = 0;
> +  ts.tv_nsec = 0;
> +
> +  if (sem_clockwait (&s, NOT_A_VALID_CLOCK, &ts) == 0)
> +    {
> +      puts ("sem_clockwait succeeded with an invalid clock");
> +      return 1;
> +    }

TEST_VERIFY_EXIT (sem_clockwait (&s, NOT_A_VALID_CLOCK, &ts) != 0).

> +  if (errno != EINVAL)
> +    {
> +      printf ("sem_clockwait yielded incorrect errno for invalid clock: %d\n",
> +	      errno);
> +      return 1;
> +    }

TEST_COMPARE (errno, EINVAL)).

> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
> index 2149ade..7f1031d 100644
> --- a/nptl/tst-sem5.c
> +++ b/nptl/tst-sem5.c
> @@ -23,13 +23,15 @@
>  #include <unistd.h>
>  #include <sys/time.h>

As for tst-sem13.c, I think it would be good to adapt to libsupport.

>  
> +/* A bogus clock value that tells run_test to use
> +   sem_timedwait rather than sem_clockwait */
> +#define	CLOCK_USE_TIMEDWAIT (-1)
>  
>  static int
> -do_test (void)
> +do_test_clock (clockid_t clockid)
>  {
>    sem_t s;
>    struct timespec ts;
> -  struct timeval tv;
>  
>    if (sem_init (&s, 0, 1) == -1)
>      {
> @@ -43,13 +45,8 @@ do_test (void)
>        return 1;
>      }
>  
> -  if (gettimeofday (&tv, NULL) != 0)
> -    {
> -      puts ("gettimeofday failed");
> -      return 1;
> -    }
> -
> -  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +  (void) clock_gettime (clockid == CLOCK_USE_TIMEDWAIT
> +			? CLOCK_REALTIME : clockid, &ts);
>  
>    /* We wait for half a second.  */
>    ts.tv_nsec += 500000000;
> @@ -60,7 +57,9 @@ do_test (void)
>      }
>  
>    errno = 0;
> -  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
> +  if (TEMP_FAILURE_RETRY ((clockid == CLOCK_USE_TIMEDWAIT)
> +			  ? sem_timedwait (&s, &ts)
> +			  : sem_clockwait (&s, clockid, &ts)) != -1)
>      {
>        puts ("sem_timedwait succeeded");
>        return 1;
> @@ -73,7 +72,8 @@ do_test (void)
>      }
>  
>    struct timespec ts2;
> -  if (clock_gettime (CLOCK_REALTIME, &ts2) != 0)
> +  if (clock_gettime (clockid == CLOCK_USE_TIMEDWAIT
> +		     ? CLOCK_REALTIME : clockid, &ts2) != 0)
>      {
>        puts ("clock_gettime failed");
>        return 1;
> @@ -89,5 +89,13 @@ do_test (void)
>    return 0;
>  }
>  
> +static int do_test (void)
> +{
> +  do_test_clock (CLOCK_USE_TIMEDWAIT);
> +  do_test_clock (CLOCK_REALTIME);
> +  do_test_clock (CLOCK_MONOTONIC);
> +  return 0;
> +}
> +
>  #define TEST_FUNCTION do_test ()
>  #include "../test-skeleton.c"
> diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
> index 41ff927..2e68b16 100644
> --- a/sysdeps/pthread/semaphore.h
> +++ b/sysdeps/pthread/semaphore.h
> @@ -59,6 +59,10 @@ extern int sem_wait (sem_t *__sem);
>     __THROW.  */
>  extern int sem_timedwait (sem_t *__restrict __sem,
>  			  const struct timespec *__restrict __abstime);
> +
> +extern int sem_clockwait (sem_t *__restrict __sem,
> +			  clockid_t clock,
> +			  const struct timespec *__restrict __abstime);
>  #endif
>  
>  /* Test whether SEM is posted.  */
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 931c827..454d340 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
>  GLIBC_2.3.4 pthread_getaffinity_np F
>  GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
> +GLIBC_2.30 sem_clockwait F
>  GLIBC_2.4 pthread_mutex_consistent_np F
>  GLIBC_2.4 pthread_mutex_getprioceiling F
>  GLIBC_2.4 pthread_mutex_setprioceiling F
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait
  2019-02-27 18:23 ` [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait Mike Crowe
@ 2019-03-05 16:45   ` Adhemerval Zanella
  2019-05-04 20:22     ` Mike Crowe
  0 siblings, 1 reply; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 16:45 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> Add:
> 
>  int pthread_cond_clockwait (pthread_cond_t *cond,
>                              pthread_mutex_t *mutex,
>                              clockid_t clockid,
>                              const struct timespec *abstime)
> 
> which behaves just like pthread_cond_timedwait except it always measures
> abstime against the supplied clockid. Currently supports CLOCK_REALTIME and
> CLOCK_MONOTONIC and returns EINVAL if any other clock is specified.
> 
> Includes feedback from many others. This function was originally
> proposed[1] as pthread_cond_timedwaitonclock_np, but The Austin Group
> preferred the new name.
> 
> * nptl/Makefile: Add tst-cond26 and tst-cond27
> 
> * nptl/Versions (GLIBC_2.30): Add pthread_cond_clockwait
> 
> * sysdeps/nptl/pthread.h: Likewise
> 
> * nptl/forward.c: Add __pthread_cond_clockwait (not sure if it should be
>   __USE_GNU while it's still only proposed for POSIX.)
> 
> * nptl/forward.c: Likewise
> 
> * nptl/pthreadP.h: Likewise
> 
> * sysdeps/nptl/pthread-functions.h: Likewise.
> 
> * nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Add clockid
>   parameter and comment describing why we don't need to check its value.
>   Use that value 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.
> 
> * 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.
> 
> * sysdeps/unix/sysv/linux/arm/libpthread.abilist,
>  sysdeps/unix/sysv/linux/i386/libpthread.abilist,
>  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Add
>  pthread_cond_clockwait
> 
> * manual/threads.texi: Document pthread_cond_clockwait. The comment was
>   provided by Carlos O'Donell.
> 
> [1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
> ---
>  manual/threads.texi                                  |  20 ++-
>  nptl/Makefile                                        |   1 +-
>  nptl/Versions                                        |   2 +-
>  nptl/forward.c                                       |   5 +-
>  nptl/nptl-init.c                                     |   1 +-
>  nptl/pthreadP.h                                      |   4 +-
>  nptl/pthread_cond_wait.c                             |  43 ++++-
>  nptl/tst-cond11.c                                    |  30 ++-
>  nptl/tst-cond26.c                                    |  91 ++++++++++-
>  nptl/tst-cond27.c                                    | 113 ++++++++++++-
>  sysdeps/nptl/pthread-functions.h                     |   4 +-
>  sysdeps/nptl/pthread.h                               |  13 +-
>  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   1 +-
>  13 files changed, 314 insertions(+), 14 deletions(-)
>  create mode 100644 nptl/tst-cond26.c
>  create mode 100644 nptl/tst-cond27.c
> 
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 674267c..91462f5 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -679,6 +679,26 @@ against the clock specified by @var{clockid} rather than
>  @code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}.
>  @end deftypefun
>  
> +@comment pthread.h
> +@comment POSIX-proposed
> +@deftypefun int pthread_cond_clockwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex},
> +                                        clockid_t @var{clockid}, const struct timespec *@var{abstime})
> +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
> +@c If exactly the same function with arguments is called from a signal
> +@c handler that interrupts between the mutex unlock and sleep then it
> +@c will unlock the mutex twice resulting in undefined behaviour. Keep
> +@c in mind that the unlock and sleep are only atomic with respect to other
> +@c threads (really a happens-after relationship for pthread_cond_broadcast
> +@c and pthread_cond_signal).
> +@c In the AC case we would cancel the thread and the mutex would remain
> +@c locked and we can't recover from that.
> +Behaves like @code{pthread_cond_timedwait} except the time @var{abstime} is
> +measured against the clock specified by @var{clockid} rather than the clock
> +specified or defaulted when @code{pthread_cond_init} was called. Currently,
> +@var{clockid} must be either @code{CLOCK_MONOTONIC} or
> +@code{CLOCK_REALTIME}.
> +@end deftypefun
> +
>  @c FIXME these are undocumented:
>  @c pthread_atfork
>  @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 4c9f5d3..7de4d40 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -251,6 +251,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
>  	tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
>  	tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
>  	tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond25 \
> +	tst-cond26 tst-cond27 \
>  	tst-cond-except \
>  	tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
>  	tst-robust6 tst-robust7 tst-robust8 tst-robust9 \
> diff --git a/nptl/Versions b/nptl/Versions
> index cd1806c..8c094d0 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -278,7 +278,7 @@ libpthread {
>    }
>  
>    GLIBC_2.30 {
> -    sem_clockwait;
> +    sem_clockwait; pthread_cond_clockwait;
>    }
>  

This has the same issue brought by Joseph in previous patch.

>    GLIBC_PRIVATE {
> diff --git a/nptl/forward.c b/nptl/forward.c
> index ed1e7d0..50f358f 100644
> --- a/nptl/forward.c
> +++ b/nptl/forward.c
> @@ -164,6 +164,11 @@ FORWARD (__pthread_cond_timedwait,
>  	  const struct timespec *abstime), (cond, mutex, abstime), 0)
>  versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait,
>  		  GLIBC_2_3_2);
> +FORWARD (__pthread_cond_clockwait,
> +	 (pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid,
> +	  const struct timespec *abstime), (cond, mutex, clockid, abstime),
> +	 0)
> +weak_alias (__pthread_cond_clockwait, pthread_cond_clockwait);
>  
>  
>  FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
> diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
> index b5895fa..c872b9f 100644
> --- a/nptl/nptl-init.c
> +++ b/nptl/nptl-init.c
> @@ -104,6 +104,7 @@ static const struct pthread_functions pthread_functions =
>      .ptr___pthread_cond_signal = __pthread_cond_signal,
>      .ptr___pthread_cond_wait = __pthread_cond_wait,
>      .ptr___pthread_cond_timedwait = __pthread_cond_timedwait,
> +    .ptr___pthread_cond_clockwait = __pthread_cond_clockwait,
>  # if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
>      .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
>      .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
> diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
> index 626bd4b..28c0ee5 100644
> --- a/nptl/pthreadP.h
> +++ b/nptl/pthreadP.h
> @@ -487,6 +487,10 @@ 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);
>  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 daa4e25..5deb54b 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. */
> +

Ok.

>    /* 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
> @@ -510,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>  	      if (__glibc_unlikely (abstime->tv_sec < 0))
>  	        err = ETIMEDOUT;
>  
> -	      else if ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0)
> +	      else if (clockid == CLOCK_MONOTONIC)
>  		{
>  		  /* CLOCK_MONOTONIC is requested.  */
>  		  struct timespec rt;
> @@ -652,7 +658,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.  */

Ok.

> @@ -664,10 +671,40 @@ __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);
> +}
> +

Ok.

> +/* 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;

The timespec check is used in different parts internally, I wonder
if it would better to consolidate it somewhere.

> +
> +  /* We only support CLOCK_REALTIME and CLOCK_MONOTONIC */
> +  if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
> +    return EINVAL;

Why not use lll_futex_supported_clockid here?

> +
> +  /* If we do not support waiting using CLOCK_MONOTONIC, return an error.  */
> +  if (clockid == CLOCK_MONOTONIC
> +      && !futex_supports_exact_relative_timeouts ())
> +    return EINVAL;

Why exactly do we need futex_supports_exact_relative_timeouts if Linux
always set it to true?

> +
> +  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 97a8bd0..4df6b15 100644
> --- a/nptl/tst-cond11.c
> +++ b/nptl/tst-cond11.c
> @@ -22,17 +22,20 @@
>  #include <time.h>
>  #include <unistd.h>
Not a requisite, but since you are touching the testcase it might a
good time to change it to use libsupport.

>  
> +/* 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)
>      {
> @@ -40,7 +43,7 @@ run_test (clockid_t cl)
>        return 1;
>      }
>  
> -  if (pthread_condattr_setclock (&condattr, cl) != 0)
> +  if (pthread_condattr_setclock (&condattr, attr_clock) != 0)
>      {
>        puts ("condattr_setclock failed");
>        return 1;
> @@ -52,10 +55,10 @@ run_test (clockid_t cl)
>        puts ("condattr_getclock failed");
>        return 1;
>      }
> -  if (cl != cl2)
> +  if (attr_clock != cl2)
>      {
>        printf ("condattr_getclock returned wrong value: %d, expected %d\n",
> -	      (int) cl2, (int) cl);
> +	      (int) cl2, (int) attr_clock);
>        return 1;
>      }
>  
> @@ -108,7 +111,7 @@ run_test (clockid_t cl)
>      }
>  
>    struct timespec ts;
> -  if (clock_gettime (cl, &ts) != 0)
> +  if (clock_gettime ((wait_clock == CLOCK_USE_ATTR_CLOCK) ? attr_clock : wait_clock, &ts) != 0)

Line too long.

>      {
>        puts ("clock_gettime failed");
>        return 1;
> @@ -117,7 +120,9 @@ run_test (clockid_t cl)
>    /* Wait one second.  */
>    ++ts.tv_sec;
>  
> -  int e = pthread_cond_timedwait (&cond, &mut, &ts);
> +  int e = (wait_clock == CLOCK_USE_ATTR_CLOCK)
> +    ? pthread_cond_timedwait (&cond, &mut, &ts)
> +    : pthread_cond_clockwait (&cond, &mut, wait_clock, &ts);
>    if (e == 0)
>      {
>        puts ("cond_timedwait succeeded");
> @@ -130,7 +135,7 @@ run_test (clockid_t cl)
>      }
>  
>    struct timespec ts2;
> -  if (clock_gettime (cl, &ts2) != 0)
> +  if (clock_gettime ((wait_clock == CLOCK_USE_ATTR_CLOCK) ? attr_clock : wait_clock, &ts2) != 0)

Ditto.

>      {
>        puts ("second clock_gettime failed");
>        return 1;
> @@ -176,7 +181,7 @@ do_test (void)
>  
>  #else
>  
> -  int res = run_test (CLOCK_REALTIME);
> +  int res = run_test (CLOCK_REALTIME, CLOCK_USE_ATTR_CLOCK);
>  
>  # if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
>  #  if _POSIX_MONOTONIC_CLOCK == 0
> @@ -189,8 +194,13 @@ do_test (void)
>        res = 1;
>      }
>    else
> +    {
>  #  endif
> -    res |= run_test (CLOCK_MONOTONIC);
> +      res |= run_test (CLOCK_MONOTONIC, CLOCK_USE_ATTR_CLOCK);
> +      res |= run_test (CLOCK_REALTIME, CLOCK_MONOTONIC);
> +      res |= run_test (CLOCK_MONOTONIC, CLOCK_MONOTONIC);
> +      res |= run_test (CLOCK_MONOTONIC, CLOCK_REALTIME);
> +    }
>  # else
>    puts ("_POSIX_MONOTONIC_CLOCK not defined");
>  # endif
> diff --git a/nptl/tst-cond26.c b/nptl/tst-cond26.c
> new file mode 100644
> index 0000000..83b041d
> --- /dev/null
> +++ b/nptl/tst-cond26.c
> @@ -0,0 +1,91 @@
> +/* 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>
> +
> +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
> +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
> +
> +static int test_bad_clockid (clockid_t clockid)
> +{
> +  struct timespec ts = {0,0};
> +  int rc = pthread_cond_clockwait (&cond, &mut, clockid, &ts);

Use TEST_VERIFY (pthread_cond_clockwait (&cond, &mut, clockid, &ts) != 0).

> +
> +  if (rc == 0)
> +    {
> +      puts ("pthread_cond_clockwait on bad clock incorrectly succeeded\n");
> +      return 1;
> +    }

Use TEST_VERIFY (rc == 0);

> +  else if (rc != EINVAL)

Use TEST_COMPARE (rc, EINVAL).

> +    {
> +      printf ("pthread_cond_clockwait on bad clock incorrectly failed "
> +	      "with %d\n", rc);
> +      return 1;
> +    }
> +  else
> +    return 0;
> +}
> +
> +#define NOT_A_VALID_CLOCK 123456
> +
> +static int
> +do_test (void)
> +{
> +  if (pthread_mutex_lock (&mut) != 0)
> +    {
> +      puts("Failed to lock mutex\n");
> +      return 1;
> +    }

Use xpthread_mutex_lock.

> +
> +  int rc = 0;
> +
> +  /* These clocks are meaningless to pthread_cond_clockwait. */
> +#if defined(CLOCK_PROCESS_CPUTIME_ID)
> +  rc |= test_bad_clockid (CLOCK_PROCESS_CPUTIME_ID);
> +#endif
> +#if defined(CLOCK_THREAD_CPUTIME_ID)
> +  rc |= test_bad_clockid (CLOCK_PROCESS_CPUTIME_ID);
> +#endif
> +
> +  /* These clocks might be meaningful, but are currently unsupported
> +     by pthread_cond_clockwait. */
> +#if defined(CLOCK_REALTIME_COARSE)
> +  rc |= test_bad_clockid (CLOCK_REALTIME_COARSE);
> +#endif
> +#if defined(CLOCK_MONOTONIC_RAW)
> +  rc |= test_bad_clockid (CLOCK_MONOTONIC_RAW);
> +#endif
> +#if defined(CLOCK_MONOTONIC_COARSE)
> +  rc |= test_bad_clockid (CLOCK_MONOTONIC_COARSE);
> +#endif
> +#if defined(CLOCK_BOOTTIME)
> +  rc |= test_bad_clockid (CLOCK_BOOTTIME);
> +#endif
> +
> +  /* This is a completely invalid clock. */
> +  rc |= test_bad_clockid (NOT_A_VALID_CLOCK);
> +
> +  return rc;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-cond27.c b/nptl/tst-cond27.c
> new file mode 100644
> index 0000000..efca7fd
> --- /dev/null
> +++ b/nptl/tst-cond27.c
> @@ -0,0 +1,113 @@
> +/* Test pthread_cond_clockwait, based on tst-cond5.c
> +
> +   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>
> +
> +
> +static pthread_mutex_t mut;
> +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
> +
> +
> +static int
> +do_test_clock (clockid_t clockid)
> +{
> +  pthread_mutexattr_t ma;
> +  int err;
> +  struct timespec ts;
> +
> +  if (pthread_mutexattr_init (&ma) != 0)
> +    {
> +      puts ("mutexattr_init failed");
> +      exit (1);
> +    }

Use xpthread_mutexattr_init.

> +
> +  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
> +    {
> +      puts ("mutexattr_settype failed");
> +      exit (1);
> +    }
> +

Use xpthread_mutexattr_settype.

> +  if (pthread_mutex_init (&mut, &ma) != 0)
> +    {
> +      puts ("mutex_init failed");
> +      exit (1);
> +    }
> +

Use xpthread_mutex_init.

> +  /* Get the mutex.  */
> +  if (pthread_mutex_lock (&mut) != 0)
> +    {
> +      puts ("mutex_lock failed");
> +      exit (1);
> +    }

Use xpthread_mutex_lock.

> +
> +  /* Waiting for the condition will fail.  But we want the timeout here.  */
> +  if (clock_gettime (clockid, &ts) != 0)
> +    {
> +      puts ("clock_gettime failed");
> +      exit (1);
> +    }

Use TEST_COMPARE (clock_gettime (clockid, &ts), 0);

> +
> +  ts.tv_nsec += 500000000;
> +  if (ts.tv_nsec >= 1000000000)
> +    {
> +      ts.tv_nsec -= 1000000000;
> +      ++ts.tv_sec;
> +    }
> +  err = pthread_cond_clockwait (&cond, &mut, clockid, &ts);
> +  if (err == 0)

Use TEST_VERIFY_EXIT (pthread_cond_clockwait (&cond, &mut, clockid, &ts) != 0);

> +    {
> +      /* This could in theory happen but here without any signal and
> +	 additional waiter it should not.  */
> +      puts ("cond_timedwait succeeded");
> +      exit (1);
> +    }
> +  else if (err != ETIMEDOUT)

Use TEST_COMPARE (err, ETIMEDOUT).

> +    {
> +      printf ("cond_timedwait returned with %s\n", strerror (err));
> +      exit (1);
> +    }
> +
> +  err = pthread_mutex_unlock (&mut);

Use xpthread_mutex_unlock.

> +  if (err != 0)
> +    {
> +      printf ("mutex_unlock failed: %s\n", strerror (err));
> +      exit (1);
> +    }
> +
> +  return 0;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  int rc;
> +  rc = do_test_clock (CLOCK_MONOTONIC);
> +  if (rc == 0)
> +    rc = do_test_clock (CLOCK_REALTIME);
> +
> +  return rc;
> +}

Libsupport will handle the correct return, so there is no need to keep
track of current status.

> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/nptl/pthread-functions.h b/sysdeps/nptl/pthread-functions.h
> index cd5e94d..cfa9660 100644
> --- a/sysdeps/nptl/pthread-functions.h
> +++ b/sysdeps/nptl/pthread-functions.h
> @@ -55,6 +55,10 @@ struct pthread_functions
>    int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
>    int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *,
>  				       const struct timespec *);
> +  int (*ptr___pthread_cond_clockwait) (pthread_cond_t *,
> +				       pthread_mutex_t *,
> +				       clockid_t,
> +				       const struct timespec *);
>    int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *);
>    int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *);
>    int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *,
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 704a3c4..d4fe9d9 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -1003,6 +1003,19 @@ extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
>  				   const struct timespec *__restrict __abstime)
>       __nonnull ((1, 2, 3));
>  
> +/* 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));
> +
>  /* Functions for handling condition variable attributes.  */
>  
>  /* Initialize condition variable attribute ATTR.  */
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 454d340..aaa1c3b 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
>  GLIBC_2.3.4 pthread_getaffinity_np F
>  GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
> +GLIBC_2.30 pthread_cond_clockwait F
>  GLIBC_2.30 sem_clockwait F
>  GLIBC_2.4 pthread_mutex_consistent_np F
>  GLIBC_2.4 pthread_mutex_getprioceiling F
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 4/7] nptl: pthread_rwlock: Move timeout validation into _full functions
  2019-02-27 18:23 ` [PATCH 4/7] nptl: pthread_rwlock: Move timeout validation into _full functions Mike Crowe
@ 2019-03-05 16:48   ` Adhemerval Zanella
  0 siblings, 0 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 16:48 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> As recommended by the comments in the implementations of
> pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock, let's move the
> timeout validity checks into the corresponding pthread_rwlock_rdlock_full
> and pthread_rwlock_wrlock_full functions. Since these functions may be
> called with abstime == NULL, an extra check for that is necessary too.
> ---
>  nptl/pthread_rwlock_common.c      | 20 ++++++++++++++++++++
>  nptl/pthread_rwlock_timedrdlock.c | 10 ----------
>  nptl/pthread_rwlock_timedwrlock.c | 10 ----------
>  3 files changed, 20 insertions(+), 20 deletions(-)
> 
> diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
> index 89ba21a..120b880 100644
> --- a/nptl/pthread_rwlock_common.c
> +++ b/nptl/pthread_rwlock_common.c
> @@ -282,6 +282,16 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
>  {
>    unsigned int r;
>  
> +  /* Make sure any passed in timeout value is valid.  Note that the previous
> +     implementation assumed that this check *must* not be performed if there
> +     would in fact be no blocking; however, POSIX only requires that "the
> +     validity of the abstime parameter need not be checked if the lock can be
> +     immediately acquired" (i.e., we need not but may check it).  */
> +  if (abstime
> +      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
> +      || abstime->tv_nsec < 0))
> +    return EINVAL;
> +

Couldn't we create a consolidate implementation for this check instead of
duplicate it?

>    /* Make sure we are not holding the rwlock as a writer.  This is a deadlock
>       situation we recognize and report.  */
>    if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer)
> @@ -576,6 +586,16 @@ static __always_inline int
>  __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
>      const struct timespec *abstime)
>  {
> +  /* Make sure any passed in timeout value is valid.  Note that the previous
> +     implementation assumed that this check *must* not be performed if there
> +     would in fact be no blocking; however, POSIX only requires that "the
> +     validity of the abstime parameter need not be checked if the lock can be
> +     immediately acquired" (i.e., we need not but may check it).  */
> +  if (abstime
> +      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
> +      || abstime->tv_nsec < 0))
> +    return EINVAL;
> +
>    /* Make sure we are not holding the rwlock as a writer.  This is a deadlock
>       situation we recognize and report.  */
>    if (__glibc_unlikely (atomic_load_relaxed (&rwlock->__data.__cur_writer)
> diff --git a/nptl/pthread_rwlock_timedrdlock.c b/nptl/pthread_rwlock_timedrdlock.c
> index aa00530..84c1983 100644
> --- a/nptl/pthread_rwlock_timedrdlock.c
> +++ b/nptl/pthread_rwlock_timedrdlock.c
> @@ -23,15 +23,5 @@ int
>  pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
>      const struct timespec *abstime)
>  {
> -  /* Make sure the passed in timeout value is valid.  Note that the previous
> -     implementation assumed that this check *must* not be performed if there
> -     would in fact be no blocking; however, POSIX only requires that "the
> -     validity of the abstime parameter need not be checked if the lock can be
> -     immediately acquired" (i.e., we need not but may check it).  */
> -  /* ??? Just move this to __pthread_rwlock_rdlock_full?  */
> -  if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
> -      || abstime->tv_nsec < 0))
> -    return EINVAL;
> -
>    return __pthread_rwlock_rdlock_full (rwlock, abstime);
>  }
> diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c
> index 3c92e44..f0b745d 100644
> --- a/nptl/pthread_rwlock_timedwrlock.c
> +++ b/nptl/pthread_rwlock_timedwrlock.c
> @@ -23,15 +23,5 @@ int
>  pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
>      const struct timespec *abstime)
>  {
> -  /* Make sure the passed in timeout value is valid.  Note that the previous
> -     implementation assumed that this check *must* not be performed if there
> -     would in fact be no blocking; however, POSIX only requires that "the
> -     validity of the abstime parameter need not be checked if the lock can be
> -     immediately acquired" (i.e., we need not but may check it).  */
> -  /* ??? Just move this to __pthread_rwlock_wrlock_full?  */
> -  if (__glibc_unlikely (abstime->tv_nsec >= 1000000000
> -      || abstime->tv_nsec < 0))
> -    return EINVAL;
> -
>    return __pthread_rwlock_wrlock_full (rwlock, abstime);
>  }
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 5/7] nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly
  2019-02-27 18:23 ` [PATCH 5/7] nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly Mike Crowe
@ 2019-03-05 17:36   ` Adhemerval Zanella
  0 siblings, 0 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 17:36 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> The tests for out-of-bounds timespecs first test pthread_rwlock_timedrdlock
> and then pthread_rwlock_timedwrlock. It appears that the second and third
> tests suffered from copy-and-paste errors and each test
> pthread_rwlock_timedrdlock twice in a row. Let's correct that so that
> pthread_rwlock_timedwrlock is tested too.

This patch looks ok and it should be pushed upstream independently of the
patchset. It also requires a propor ChangeLog.

> ---
>  nptl/tst-rwlock14.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c
> index f8c2183..6f57169 100644
> --- a/nptl/tst-rwlock14.c
> +++ b/nptl/tst-rwlock14.c
> @@ -117,15 +117,15 @@ do_test (void)
>        result = 1;
>      }
>  
> -  e = pthread_rwlock_timedrdlock (&r, &ts);
> +  e = pthread_rwlock_timedwrlock (&r, &ts);
>    if (e == 0)
>      {
> -      puts ("second rwlock_timedrdlock did not fail");
> +      puts ("second rwlock_timedwrlock did not fail");
>        result = 1;
>      }
>    else if (e != EINVAL)
>      {
> -      puts ("second rwlock_timedrdlock did not return EINVAL");
> +      puts ("second rwlock_timedwrlock did not return EINVAL");
>        result = 1;
>      }
>  
> @@ -145,15 +145,15 @@ do_test (void)
>        result = 1;
>      }
>  
> -  e = pthread_rwlock_timedrdlock (&r, &ts);
> +  e = pthread_rwlock_timedwrlock (&r, &ts);
>    if (e == 0)
>      {
> -      puts ("third rwlock_timedrdlock did not fail");
> +      puts ("third rwlock_timedwrlock did not fail");
>        result = 1;
>      }
>    else if (e != EINVAL)
>      {
> -      puts ("third rwlock_timedrdlock did not return EINVAL");
> +      puts ("third rwlock_timedwrlock did not return EINVAL");
>        result = 1;
>      }
>  
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval
  2019-02-27 18:23 ` [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval Mike Crowe
@ 2019-03-05 18:02   ` Adhemerval Zanella
  2019-03-20 21:34     ` Mike Crowe
  2019-03-14 14:44   ` Yann Droneaud
  1 sibling, 1 reply; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-05 18:02 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> In preparation for adding pthread_rwlock_clockrdlock and
> pthread_rwlock_clockwrlock, convert various tests to only use clock_gettime
> and struct timespec.
> 
> * support/timespec.h: Create header to provide timespec helper functions
>   from sysdeps/pthread/posix-timer.h for tests to use.
> 
> * nptl/tst-rwlock6.c: Fix small bug in timeout-checking code that could
>   erroneously pass if the function incorrectly took more than a second.
> 
> * nptl/tst-rwlock6.c: Use clock_gettime(2) rather than gettimeofday(2) and
>   then converting to timespec in preparation for testing
>   pthread_rwlock_clockrdclock and pthread_rwlock_clockwrlock.
> 
> * nptl/tst-rwlock9.c, nptl/tst-rwlock7.c: Likewise.

I am seeing this issue sporadically on i686-linux-gnu with 6/7 patches
applied:

$ ./testrun.sh nptl/tst-rwlock7 --direct
0: got timedrdlock
child: timedwrlock failed with ETIMEDOUT
child: timedwrlock failed with EINVAL
1: got timedrdlock
child: timedwrlock failed with ETIMEDOUT
child: timedwrlock failed with EINVAL
2: got timedrdlock
child: timedwrlock failed with ETIMEDOUT
2nd timedwrlock did not return EINVAL
failure in round 2


> ---
>  nptl/tst-rwlock6.c | 47 ++++++++++++++++++-----------------------------
>  nptl/tst-rwlock7.c | 43 +++++++++++++++++--------------------------
>  nptl/tst-rwlock9.c |  8 ++------
>  support/timespec.h | 27 +++++++++++++++++++++++++++-
>  4 files changed, 64 insertions(+), 61 deletions(-)
>  create mode 100644 support/timespec.h
> 
> diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
> index 8d6c3dc..67119fa 100644
> --- a/nptl/tst-rwlock6.c
> +++ b/nptl/tst-rwlock6.c
> @@ -22,6 +22,7 @@
>  #include <stdio.h>
>  #include <string.h>
>  #include <sys/time.h>
> +#include <support/timespec.h>
>  
>  
>  static int kind[] =
> @@ -38,21 +39,15 @@ tf (void *arg)
>    pthread_rwlock_t *r = arg;
>  
>    /* Timeout: 0.3 secs.  */
> -  struct timeval tv;
> -  (void) gettimeofday (&tv, NULL);
> +  struct timespec ts_start;
> +  (void) clock_gettime(CLOCK_REALTIME, &ts_start);

Space after symbol. Also I think there is no need for (void) cast here.

>  
> -  struct timespec ts;
> -  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> -  ts.tv_nsec += 300000000;
> -  if (ts.tv_nsec >= 1000000000)
> -    {
> -      ts.tv_nsec -= 1000000000;
> -      ++ts.tv_sec;
> -    }
> +  struct timespec ts_timeout = {0, 300000000};
> +  timespec_add(&ts_timeout, &ts_start, &ts_timeout);

Ditto.

>  
>    puts ("child calling timedrdlock");
>  
> -  int err = pthread_rwlock_timedrdlock (r, &ts);
> +  int err = pthread_rwlock_timedrdlock (r, &ts_timeout);
>    if (err == 0)
>      {
>        puts ("rwlock_timedrdlock returned");
> @@ -68,24 +63,24 @@ tf (void *arg)
>  
>    puts ("1st child timedrdlock done");
>  
> -  struct timeval tv2;
> -  (void) gettimeofday (&tv2, NULL);
> +  struct timespec ts_end;
> +  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
>  
> -  timersub (&tv2, &tv, &tv);
> +  struct timespec ts_duration;
> +  timespec_sub(&ts_duration, &ts_end, &ts_start);

Ditto.

>  
> -  if (tv.tv_usec < 200000)
> +  if (ts_duration.tv_sec !=0 || ts_duration.tv_nsec < 200000000)

After before !=.

>      {
>        puts ("timeout too short");
>        pthread_exit ((void *) 1l);
>      }
>  
> -  (void) gettimeofday (&tv, NULL);
> -  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> -  ts.tv_sec += 10;
> +  (void) clock_gettime (CLOCK_REALTIME, &ts_timeout);
> +  ts_timeout.tv_sec += 10;
>    /* Note that the following operation makes ts invalid.  */
> -  ts.tv_nsec += 1000000000;
> +  ts_timeout.tv_nsec += 1000000000;
>  
> -  err = pthread_rwlock_timedrdlock (r, &ts);
> +  err = pthread_rwlock_timedrdlock (r, &ts_timeout);
>    if (err == 0)
>      {
>        puts ("2nd timedrdlock succeeded");
> @@ -136,12 +131,8 @@ do_test (void)
>  	  exit (1);
>  	}
>  
> -      struct timeval tv;
> -      (void) gettimeofday (&tv, NULL);
> -
>        struct timespec ts;
> -      TIMEVAL_TO_TIMESPEC (&tv, &ts);
> -
> +      (void) clock_gettime (CLOCK_REALTIME, &ts);
>        ++ts.tv_sec;
>  
>        /* Get a write lock.  */
> @@ -154,8 +145,7 @@ do_test (void)
>  
>        puts ("1st timedwrlock done");
>  
> -      (void) gettimeofday (&tv, NULL);
> -      TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +      (void) clock_gettime (CLOCK_REALTIME, &ts);
>        ++ts.tv_sec;
>        e = pthread_rwlock_timedrdlock (&r, &ts);
>        if (e == 0)
> @@ -171,8 +161,7 @@ do_test (void)
>  
>        puts ("1st timedrdlock done");
>  
> -      (void) gettimeofday (&tv, NULL);
> -      TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +      (void) clock_gettime (CLOCK_REALTIME, &ts);
>        ++ts.tv_sec;
>        e = pthread_rwlock_timedwrlock (&r, &ts);
>        if (e == 0)

Ok.

> diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
> index 4d6f561..812506c 100644
> --- a/nptl/tst-rwlock7.c
> +++ b/nptl/tst-rwlock7.c
> @@ -22,6 +22,7 @@
>  #include <stdio.h>
>  #include <string.h>
>  #include <sys/time.h>
> +#include <support/timespec.h>
>  
>  
>  static int kind[] =
> @@ -38,19 +39,12 @@ tf (void *arg)
>    pthread_rwlock_t *r = arg;
>  
>    /* Timeout: 0.3 secs.  */
> -  struct timeval tv;
> -  (void) gettimeofday (&tv, NULL);
> +  struct timespec ts_start;
> +  (void) clock_gettime (CLOCK_REALTIME, &ts_start);
> +  struct timespec ts_timeout = {0, 300000000};
> +  timespec_add(&ts_timeout, &ts_start, &ts_timeout);

Ditto.

>  
> -  struct timespec ts;
> -  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> -  ts.tv_nsec += 300000000;
> -  if (ts.tv_nsec >= 1000000000)
> -    {
> -      ts.tv_nsec -= 1000000000;
> -      ++ts.tv_sec;
> -    }
> -
> -  int err = pthread_rwlock_timedwrlock (r, &ts);
> +  int err = pthread_rwlock_timedwrlock (r, &ts_timeout);
>    if (err == 0)
>      {
>        puts ("rwlock_timedwrlock returned");
> @@ -65,24 +59,24 @@ tf (void *arg)
>      }
>    puts ("child: timedwrlock failed with ETIMEDOUT");
>  
> -  struct timeval tv2;
> -  (void) gettimeofday (&tv2, NULL);
> -
> -  timersub (&tv2, &tv, &tv);
> +  struct timespec ts_end;
> +  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
> +  struct timespec ts_diff;
> +  timespec_sub (&ts_diff, &ts_end, &ts_start);
>  
> -  if (tv.tv_usec < 200000)
> +  if (ts_diff.tv_sec != 0 || ts_diff.tv_nsec < 200000000)
>      {
>        puts ("timeout too short");
>        pthread_exit ((void *) 1l);
>      }
>  
> -  (void) gettimeofday (&tv, NULL);
> -  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> -  ts.tv_sec += 10;
> +  struct timespec ts_invalid;
> +  (void) clock_gettime (CLOCK_REALTIME, &ts_invalid);
> +  ts_invalid.tv_sec += 10;
>    /* Note that the following operation makes ts invalid.  */
> -  ts.tv_nsec += 1000000000;
> +  ts_invalid.tv_nsec += 1000000000000;
>  
> -  err = pthread_rwlock_timedwrlock (r, &ts);
> +  err = pthread_rwlock_timedwrlock (r, &ts_invalid);
>    if (err == 0)
>      {
>        puts ("2nd timedwrlock succeeded");
> @@ -132,11 +126,8 @@ do_test (void)
>  	  exit (1);
>  	}
>  
> -      struct timeval tv;
> -      (void) gettimeofday (&tv, NULL);
> -
>        struct timespec ts;
> -      TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +      (void) clock_gettime (CLOCK_REALTIME, &ts);
>  
>        ++ts.tv_sec;
>  

Ok.

> diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
> index 34f2d04..ff15f90 100644
> --- a/nptl/tst-rwlock9.c
> +++ b/nptl/tst-rwlock9.c
> @@ -56,9 +56,7 @@ writer_thread (void *nr)
>        int e;
>        do
>  	{
> -	  struct timeval tv;
> -	  (void) gettimeofday (&tv, NULL);
> -	  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +	  (void) clock_gettime (CLOCK_REALTIME, &ts);
>  
>  	  ts.tv_nsec += 2 * TIMEOUT;
>  	  if (ts.tv_nsec >= 1000000000)
> @@ -110,9 +108,7 @@ reader_thread (void *nr)
>        int e;
>        do
>  	{
> -	  struct timeval tv;
> -	  (void) gettimeofday (&tv, NULL);
> -	  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +	  (void) clock_gettime (CLOCK_REALTIME, &ts);
>  
>  	  ts.tv_nsec += TIMEOUT;
>  	  if (ts.tv_nsec >= 1000000000)

Ok.

> diff --git a/support/timespec.h b/support/timespec.h
> new file mode 100644
> index 0000000..e5c89df
> --- /dev/null
> +++ b/support/timespec.h
> @@ -0,0 +1,27 @@
> +static inline void
> +timespec_sub (struct timespec *diff, const struct timespec *left,
> +	      const struct timespec *right)
> +{
> +  diff->tv_sec = left->tv_sec - right->tv_sec;
> +  diff->tv_nsec = left->tv_nsec - right->tv_nsec;
> +
> +  if (diff->tv_nsec < 0)
> +    {
> +      --diff->tv_sec;
> +      diff->tv_nsec += 1000000000;
> +    }
> +}
> +
> +static inline void
> +timespec_add (struct timespec *sum, const struct timespec *left,
> +	      const struct timespec *right)
> +{
> +  sum->tv_sec = left->tv_sec + right->tv_sec;
> +  sum->tv_nsec = left->tv_nsec + right->tv_nsec;
> +
> +  if (sum->tv_nsec >= 1000000000)
> +    {
> +      ++sum->tv_sec;
> +      sum->tv_nsec -= 1000000000;
> +    }
> +}
> 

Ok.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-03-05 12:35 ` [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Adhemerval Zanella
@ 2019-03-06 21:15   ` Joseph Myers
  2019-03-10  9:12     ` Mike Crowe
  2019-03-13 21:42   ` Mike Crowe
  1 sibling, 1 reply; 33+ messages in thread
From: Joseph Myers @ 2019-03-06 21:15 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Tue, 5 Mar 2019, Adhemerval Zanella wrote:

> > The mq_clockreceive and mq_clocksend functions corresponding to
> > mq_timedreceive and mq_timedsend require kernel changes before they can be
> > implemented in glibc.
> 
> Should we add them as ENOSYS as generic stubs in this version?

I'd expect any generic stubs to work with CLOCK_REALTIME without returning 
ENOSYS errors in that case.

> > The changes have been tested with "make check" on x86_64 and arm64. Earlier
> > versions were tested on arm. I haven't updated the ChangeLog, NEWS or
> > architecture abilists yet (so some tests fail on arm64), but will do so if
> > the rest of the changes are acceptable.
> 
> Are arm64 failures related to the patchset itself?

My reading is that they result from missing ABI updates.  (Each patch 
ought to update all relevant ABI lists to avoid introducing failures.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 7/7] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock
  2019-02-27 18:23 ` [PATCH 7/7] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock Mike Crowe
@ 2019-03-07 12:59   ` Adhemerval Zanella
  0 siblings, 0 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-07 12:59 UTC (permalink / raw)
  To: libc-alpha



On 27/02/2019 15:23, Mike Crowe wrote:
> Add:
>  int pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock,
>                                  clockid_t clockid,
>                                  const struct timespec *abstime)
> and:
>  int pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock,
>                                  clockid_t clockid,
>                                  const struct timespec *abstime)
> 
> which behave like pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock
> respectively, except they always measure abstime against the supplied
> clockid. The functions currently support CLOCK_REALTIME and CLOCK_MONOTONIC
> and return EINVAL if any other clock is specified.
> 
> * sysdeps/nptl/pthread.h: Add pthread_rwlock_clockrdlock and
>   pthread_wrlock_clockwrlock.
> 
> * nptl/Makefile: Build pthread_rwlock_clockrdlock.c and
>   pthread_rwlock_clockwrlock.c.
> 
> * nptl/pthread_rwlock_clockrdlock.c: Implement pthread_rwlock_clockrdlock.
> 
> * nptl/pthread_rwlock_clockwrlock.c: Implement pthread_rwlock_clockwrlock.
> 
> * nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Add clockid
>   parameter and verify that it indicates a supported clock on entry so that
>   we fail even if it doesn't end up being used. Pass that clock on to
>   futex_abstimed_wait when necessary. (__pthread_rwlock_wrlock_full):
>   Likewise.
> 
> * nptl/pthread_rwlock_rdlock.c: (__pthread_rwlock_rdlock): Pass
>   CLOCK_REALTIME to __pthread_rwlock_rdlock_full even though it won't be
>   used because there's no timeout.
> 
> * nptl/pthread_rwlock_wrlock.c (__pthread_rwlock_wrlock): Pass
>   CLOCK_REALTIME to __pthread_rwlock_wrlock_full even though it won't be
>   used because there is no timeout.
> 
> * nptl/pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock): Pass
>   CLOCK_REALTIME to __pthread_rwlock_rdlock_full since abstime uses that
>   clock.
> 
> * nptl/pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock): Pass
>   CLOCK_REALTIME to __pthread_rwlock_wrlock_full since abstime uses that
>   clock.
> 
> * nptl/tst-abstime.c (th): Add pthread_rwlock_clockrdlock and
>   pthread_rwlock_clockwrlock timeout tests to match the existing
>   pthread_rwlock_timedrdloock and pthread_rwlock_timedwrlock tests.
> 
> * nptl/tst-rwlock14.c (do_test): Likewise.
> 
> * nptl/tst-rwlock6.c (tf): Accept thread_args structure so that both a
>   rwlock and a clockid can be passed to the thread. (do_test_clock): Accept
>   clockid parameter to specify test clock. Use the magic clockid value of
>   CLOCK_USE_TIMEDLOCK to indicate that pthread_rwlock_timedrdlock and
>   pthread_rwlock_timedwrlock should be tested, otherwise pass the specified
>   clockid to pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock.
>   (do_test): Call do_test_clock to test each clockid in turn.
> 
> * nptl/tst-rwlock7.c: Likewise, but also pass the name of the function being
>   tested to improve error reporting.
> 
> * nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept thread_args
>   structure so that both the (now int) thread number and clockid can be
>   passed to the thread. (do_test_clock): Pass the necessary thread_args
>   when creating the reader and writer threads. (do_test): Call
>   do_test_clock to test each clockid in turn.
> 
> * manual/threads.texi: Add documentation for pthread_rwlock_clockrdlock and
>   pthread_rwlock_clockwrclock.
> ---
>  manual/threads.texi                                  |  28 ++-
>  nptl/Makefile                                        |   2 +-
>  nptl/Versions                                        |   1 +-
>  nptl/pthread_rwlock_clockrdlock.c                    |  27 ++-
>  nptl/pthread_rwlock_clockwrlock.c                    |  27 ++-
>  nptl/pthread_rwlock_common.c                         |  40 +--
>  nptl/pthread_rwlock_rdlock.c                         |   2 +-
>  nptl/pthread_rwlock_timedrdlock.c                    |   2 +-
>  nptl/pthread_rwlock_timedwrlock.c                    |   2 +-
>  nptl/pthread_rwlock_wrlock.c                         |   2 +-
>  nptl/tst-abstime.c                                   |  28 ++-
>  nptl/tst-rwlock14.c                                  | 147 ++++++++++++-
>  nptl/tst-rwlock6.c                                   | 105 ++++++---
>  nptl/tst-rwlock7.c                                   |  75 ++++--
>  nptl/tst-rwlock9.c                                   |  86 +++++--
>  sysdeps/nptl/pthread.h                               |   8 +-
>  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   2 +-
>  17 files changed, 491 insertions(+), 93 deletions(-)
>  create mode 100644 nptl/pthread_rwlock_clockrdlock.c
>  create mode 100644 nptl/pthread_rwlock_clockwrlock.c
> 
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 91462f5..83b8bb6 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -699,6 +699,34 @@ specified or defaulted when @code{pthread_cond_init} was called. Currently,
>  @code{CLOCK_REALTIME}.
>  @end deftypefun
>  
> +@comment pthread.h
> +@comment POSIX-proposed
> +@deftypefun int pthread_rwlock_clockrdlock (pthread_rwlock_t *@var{rwlock},
> +				       clockid_t @var{clockid},
> +				       const struct timespec *@var{abstime})
> +
> +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
> +Behaves like @code{pthread_rwlock_timedrdlock} except the time
> +@var{abstime} is measured against the clock specified by @var{clockid}
> +rather than @code{CLOCK_REALTIME}. Currently, @var{clockid} must be either
> +@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}, otherwise @code{EINVAL} is
> +returned.
> +@end deftypefun
> +
> +@comment pthread.h
> +@comment POSIX-proposed
> +@deftypefun int pthread_rwlock_clockwrlock (pthread_rwlock_t *@var{rwlock},
> +				       clockid_t @var{clockid},
> +				       const struct timespec *@var{abstime})
> +
> +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}}
> +Behaves like @code{pthread_rwlock_timedwrlock} except the time
> +@var{abstime} is measured against the clock specified by @var{clockid}
> +rather than @code{CLOCK_REALTIME}. Currently, @var{clockid} must be either
> +@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}, otherwise @code{EINVAL} is
> +returned.
> +@end deftypefun
> +
>  @c FIXME these are undocumented:
>  @c pthread_atfork
>  @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 7de4d40..f5e6d90 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -76,7 +76,9 @@ libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
>  		      pthread_mutexattr_gettype pthread_mutexattr_settype \
>  		      pthread_rwlock_init pthread_rwlock_destroy \
>  		      pthread_rwlock_rdlock pthread_rwlock_timedrdlock \
> +		      pthread_rwlock_clockrdlock \
>  		      pthread_rwlock_wrlock pthread_rwlock_timedwrlock \
> +		      pthread_rwlock_clockwrlock \
>  		      pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \
>  		      pthread_rwlock_unlock \
>  		      pthread_rwlockattr_init pthread_rwlockattr_destroy \
> diff --git a/nptl/Versions b/nptl/Versions
> index 8c094d0..ce79959 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -279,6 +279,7 @@ libpthread {
>  
>    GLIBC_2.30 {
>      sem_clockwait; pthread_cond_clockwait;
> +    pthread_rwlock_clockrdlock; pthread_rwlock_clockwrlock;
>    }
>  
>    GLIBC_PRIVATE {

Same naming issue noted by Joseph in first patch reply.

> diff --git a/nptl/pthread_rwlock_clockrdlock.c b/nptl/pthread_rwlock_clockrdlock.c
> new file mode 100644
> index 0000000..a6c7456
> --- /dev/null
> +++ b/nptl/pthread_rwlock_clockrdlock.c
> @@ -0,0 +1,27 @@

Missing one-line description.

> +/* 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 "pthread_rwlock_common.c"
> +
> +/* See pthread_rwlock_common.c.  */
> +int
> +pthread_rwlock_clockrdlock (pthread_rwlock_t *rwlock,
> +    clockid_t clockid,
> +    const struct timespec *abstime)
> +{
> +  return __pthread_rwlock_rdlock_full (rwlock, clockid, abstime);
> +}
> diff --git a/nptl/pthread_rwlock_clockwrlock.c b/nptl/pthread_rwlock_clockwrlock.c
> new file mode 100644
> index 0000000..d248a2a
> --- /dev/null
> +++ b/nptl/pthread_rwlock_clockwrlock.c
> @@ -0,0 +1,27 @@

Missing one-line description.

> +/* 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 "pthread_rwlock_common.c"
> +
> +/* See pthread_rwlock_common.c.  */
> +int
> +pthread_rwlock_clockwrlock (pthread_rwlock_t *rwlock,
> +    clockid_t clockid,
> +    const struct timespec *abstime)
> +{
> +  return __pthread_rwlock_wrlock_full (rwlock, clockid, abstime);
> +}
> diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
> index 120b880..50a366e 100644
> --- a/nptl/pthread_rwlock_common.c
> +++ b/nptl/pthread_rwlock_common.c
> @@ -278,17 +278,19 @@ __pthread_rwlock_rdunlock (pthread_rwlock_t *rwlock)
>  
>  static __always_inline int
>  __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
> +    clockid_t clockid,
>      const struct timespec *abstime)
>  {
>    unsigned int r;
>  
> -  /* Make sure any passed in timeout value is valid.  Note that the previous
> -     implementation assumed that this check *must* not be performed if there
> -     would in fact be no blocking; however, POSIX only requires that "the
> -     validity of the abstime parameter need not be checked if the lock can be
> -     immediately acquired" (i.e., we need not but may check it).  */
> -  if (abstime
> -      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
> +  /* Make sure any passed in clockid and timeout value are valid. Note
> +     that the previous implementation assumed that this check *must*
> +     not be performed if there would in fact be no blocking; however,
> +     POSIX only requires that "the validity of the abstime parameter
> +     need not be checked if the lock can be immediately acquired"
> +     (i.e., we need not but may check it). */
> +  if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid)
> +      || abstime->tv_nsec >= 1000000000
>        || abstime->tv_nsec < 0))
>      return EINVAL;
>  
> @@ -329,7 +331,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, CLOCK_REALTIME, abstime, private);
> +						 r, clockid, 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)
> @@ -457,7 +459,7 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
>  	    continue;
>  	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
>  					 1 | PTHREAD_RWLOCK_FUTEX_USED,
> -					 CLOCK_REALTIME, abstime, private);
> +					 clockid, abstime, private);
>  	  if (err == ETIMEDOUT)
>  	    {
>  	      /* If we timed out, we need to unregister.  If no read phase
> @@ -584,15 +586,17 @@ __pthread_rwlock_wrunlock (pthread_rwlock_t *rwlock)
>  
>  static __always_inline int
>  __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
> +    clockid_t clockid,
>      const struct timespec *abstime)
>  {
> -  /* Make sure any passed in timeout value is valid.  Note that the previous
> -     implementation assumed that this check *must* not be performed if there
> -     would in fact be no blocking; however, POSIX only requires that "the
> -     validity of the abstime parameter need not be checked if the lock can be
> -     immediately acquired" (i.e., we need not but may check it).  */
> -  if (abstime
> -      && __glibc_unlikely (abstime->tv_nsec >= 1000000000
> +  /* Make sure any passed in clockid and timeout value are valid. Note
> +     that the previous implementation assumed that this check *must*
> +     not be performed if there would in fact be no blocking; however,
> +     POSIX only requires that "the validity of the abstime parameter
> +     need not be checked if the lock can be immediately acquired"
> +     (i.e., we need not but may check it). */
> +  if (abstime && __glibc_unlikely (!futex_abstimed_supported_clockid (clockid)
> +      || abstime->tv_nsec >= 1000000000
>        || abstime->tv_nsec < 0))
>      return EINVAL;
>  
> @@ -727,7 +731,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
>  	  may_share_futex_used_flag = true;
>  	  int err = futex_abstimed_wait (&rwlock->__data.__writers_futex,
>  					 1 | PTHREAD_RWLOCK_FUTEX_USED,
> -					 CLOCK_REALTIME, abstime, private);
> +					 clockid, abstime, private);
>  	  if (err == ETIMEDOUT)
>  	    {
>  	      if (prefer_writer)
> @@ -826,7 +830,7 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
>  	    continue;
>  	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
>  					 PTHREAD_RWLOCK_FUTEX_USED,
> -					 CLOCK_REALTIME, abstime, private);
> +					 clockid, abstime, private);
>  	  if (err == ETIMEDOUT)
>  	    {
>  	      if (rwlock->__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP)

Ok.

> diff --git a/nptl/pthread_rwlock_rdlock.c b/nptl/pthread_rwlock_rdlock.c
> index 5fdc89e..387c824 100644
> --- a/nptl/pthread_rwlock_rdlock.c
> +++ b/nptl/pthread_rwlock_rdlock.c
> @@ -24,7 +24,7 @@ __pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
>  {
>    LIBC_PROBE (rdlock_entry, 1, rwlock);
>  
> -  int result = __pthread_rwlock_rdlock_full (rwlock, NULL);
> +  int result = __pthread_rwlock_rdlock_full (rwlock, CLOCK_REALTIME, NULL);
>    LIBC_PROBE (rdlock_acquire_read, 1, rwlock);
>    return result;
>  }

Ok.

> diff --git a/nptl/pthread_rwlock_timedrdlock.c b/nptl/pthread_rwlock_timedrdlock.c
> index 84c1983..8f8e680 100644
> --- a/nptl/pthread_rwlock_timedrdlock.c
> +++ b/nptl/pthread_rwlock_timedrdlock.c
> @@ -23,5 +23,5 @@ int
>  pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
>      const struct timespec *abstime)
>  {
> -  return __pthread_rwlock_rdlock_full (rwlock, abstime);
> +  return __pthread_rwlock_rdlock_full (rwlock, CLOCK_REALTIME, abstime);
>  }

Ok.

> diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c
> index f0b745d..a5616de 100644
> --- a/nptl/pthread_rwlock_timedwrlock.c
> +++ b/nptl/pthread_rwlock_timedwrlock.c
> @@ -23,5 +23,5 @@ int
>  pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
>      const struct timespec *abstime)
>  {
> -  return __pthread_rwlock_wrlock_full (rwlock, abstime);
> +  return __pthread_rwlock_wrlock_full (rwlock, CLOCK_REALTIME, abstime);
>  }

Ok.

> diff --git a/nptl/pthread_rwlock_wrlock.c b/nptl/pthread_rwlock_wrlock.c
> index 194a14c..da246d8 100644
> --- a/nptl/pthread_rwlock_wrlock.c
> +++ b/nptl/pthread_rwlock_wrlock.c
> @@ -24,7 +24,7 @@ __pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
>  {
>    LIBC_PROBE (wrlock_entry, 1, rwlock);
>  
> -  int result = __pthread_rwlock_wrlock_full (rwlock, NULL);
> +  int result = __pthread_rwlock_wrlock_full (rwlock, CLOCK_REALTIME, NULL);
>    LIBC_PROBE (wrlock_acquire_write, 1, rwlock);
>    return result;
>  }

Ok.

> diff --git a/nptl/tst-abstime.c b/nptl/tst-abstime.c
> index 71610f8..f4c9f2d 100644
> --- a/nptl/tst-abstime.c
> +++ b/nptl/tst-abstime.c
> @@ -47,12 +47,40 @@ th (void *arg)
>        puts ("pthread_rwlock_timedrdlock did not return ETIMEDOUT");
>        res = 1;
>      }
> +  r = pthread_rwlock_clockrdlock (&rw1, CLOCK_REALTIME, &t);
> +  if (r != ETIMEDOUT)
> +    {
> +      puts ("pthread_rwlock_clockrdlock (CLOCK_REALTIME) "
> +	    "did not return ETIMEDOUT");
> +      res = 1;
> +    }
> +  r = pthread_rwlock_clockrdlock (&rw1, CLOCK_MONOTONIC, &t);
> +  if (r != ETIMEDOUT)
> +    {
> +      puts ("pthread_rwlock_clockrdlock (CLOCK_MONOTONIC) "
> +	    "did not return ETIMEDOUT");
> +      res = 1;
> +    }

I prefer even new additions to old tests should use libsupport (it would
be preferable also to adapt old tests to libsupport in such cases).

Use 

TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_REALTIME, &t),
	      ETIMEOUT);

and

TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_MONOTONIC, &t),
	      ETIMEOUT);

>    r = pthread_rwlock_timedwrlock (&rw2, &t);
>    if (r != ETIMEDOUT)
>      {
>        puts ("pthread_rwlock_timedwrlock did not return ETIMEDOUT");
>        res = 1;
>      }
> +  r = pthread_rwlock_clockwrlock (&rw2, CLOCK_REALTIME, &t);
> +  if (r != ETIMEDOUT)
> +    {
> +      puts ("pthread_rwlock_clockwrlock(CLOCK_REALTIME) "
> +	    "did not return ETIMEDOUT");
> +      res = 1;
> +    }
> +  r = pthread_rwlock_clockwrlock (&rw2, CLOCK_MONOTONIC, &t);
> +  if (r != ETIMEDOUT)
> +    {
> +      puts ("pthread_rwlock_clockwrlock(CLOCK_MONOTONIC) "
> +	    "did not return ETIMEDOUT");
> +      res = 1;
> +    }
>    return (void *) res;
>  }
>  

Ditto.

> diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c
> index 6f57169..525ceac 100644
> --- a/nptl/tst-rwlock14.c
> +++ b/nptl/tst-rwlock14.c
> @@ -91,6 +91,30 @@ do_test (void)
>        result = 1;
>      }
>  
> +  e = pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts);
> +  if (e == 0)
> +    {
> +      puts ("first rwlock_clockrdlock (CLOCK_REALTIME) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("first rwlock_clockrdlock (CLOCK_REALTIME) did not return EINVAL");
> +      result = 1;
> +    }
> +
> +  e = pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts);
> +  if (e == 0)
> +    {
> +      puts ("first rwlock_clockrdlock (CLOCK_MONOTONIC) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("first rwlock_clockrdlock (CLOCK_MONOTONIC) did not return EINVAL");
> +      result = 1;
> +    }
> +

Ditto.

>    e = pthread_rwlock_timedwrlock (&r, &ts);
>    if (e == 0)
>      {
> @@ -103,6 +127,30 @@ do_test (void)
>        result = 1;
>      }
>  
> +  e = pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts);
> +  if (e == 0)
> +    {
> +      puts ("first rwlock_clockwrlock (CLOCK_REALTIME) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("first rwlock_clockwrlock (CLOCK_REALTIME) did not return EINVAL");
> +      result = 1;
> +    }
> +
> +  e = pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts);
> +  if (e == 0)
> +    {
> +      puts ("first rwlock_clockwrlock (CLOCK_MONOTONIC) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("first rwlock_clockwrlock (CLOCK_MONOTONIC) did not return EINVAL");
> +      result = 1;
> +    }
> +

Ditto.

>    ts.tv_nsec = 1000000000;
>  
>    e = pthread_rwlock_timedrdlock (&r, &ts);
> @@ -117,6 +165,31 @@ do_test (void)
>        result = 1;
>      }
>  
> +  e = pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts);
> +  if (e == 0)
> +    {
> +      puts ("second rwlock_clockrdlock (CLOCK_REALTIME) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("second rwlock_clockrdlock (CLOCK_REALTIME) did not return EINVAL");
> +      result = 1;
> +    }
> +
> +  e = pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts);
> +  if (e == 0)
> +    {
> +      puts ("second rwlock_clockrdlock (CLOCK_MONOTONIC) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("second rwlock_clockrdlock (CLOCK_MONOTONIC) "
> +	    "did not return EINVAL");
> +      result = 1;
> +    }
> +

Ditto.

>    e = pthread_rwlock_timedwrlock (&r, &ts);
>    if (e == 0)
>      {
> @@ -129,6 +202,32 @@ do_test (void)
>        result = 1;
>      }
>  
> +  e = pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts);
> +  if (e == 0)
> +    {
> +      puts ("second rwlock_clockwrlock (CLOCK_MONOTONIC) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("second rwlock_clockwrlock (CLOCK_MONOTONIC) "
> +	    "did not return EINVAL");
> +      result = 1;
> +    }
> +
> +  e = pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts);
> +  if (e == 0)
> +    {
> +      puts ("second rwlock_clockwrlock (CLOCK_REALTIME) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("second rwlock_clockwrlock (CLOCK_REALTIME) "
> +	    "did not return EINVAL");
> +      result = 1;
> +    }
> +

Ditto.

>    ts.tv_nsec = (__typeof (ts.tv_nsec)) 0x100001000LL;
>    if ((__typeof (ts.tv_nsec)) 0x100001000LL != 0x100001000LL)
>      ts.tv_nsec = 2000000000;
> @@ -145,6 +244,30 @@ do_test (void)
>        result = 1;
>      }
>  
> +  e = pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts);
> +  if (e == 0)
> +    {
> +      puts ("third rwlock_clockrdlock (CLOCK_REALTIME) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("third rwlock_clockrdlock (CLOCK_REALTIME) did not return EINVAL");
> +      result = 1;
> +    }
> +
> +  e = pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts);
> +  if (e == 0)
> +    {
> +      puts ("third rwlock_clockrdlock(CLOCK_MONOTONIC) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("third rwlock_clockrdlock (CLOCK_MONOTONIC) did not return EINVAL");
> +      result = 1;
> +    }
> +
>    e = pthread_rwlock_timedwrlock (&r, &ts);
>    if (e == 0)
>      {
> @@ -157,6 +280,30 @@ do_test (void)
>        result = 1;
>      }
>  


Ditto.

> +  e = pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts);
> +  if (e == 0)
> +    {
> +      puts ("third rwlock_clockwrlock (CLOCK_REALTIME) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("third rwlock_clockwrlock (CLOCK_REALTIME) did not return EINVAL");
> +      result = 1;
> +    }
> +
> +  e = pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts);
> +  if (e == 0)
> +    {
> +      puts ("third rwlock_clockwrlock (CLOCK_MONOTONIC) did not fail");
> +      result = 1;
> +    }
> +  else if (e != EINVAL)
> +    {
> +      puts ("third rwlock_clockwrlock (CLOCK_MONOTONIC) did not return EINVAL");
> +      result = 1;
> +    }
> +

Ditto.

>    if (result == 0)
>      puts ("no bugs");
>  
> diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
> index 67119fa..708915e 100644
> --- a/nptl/tst-rwlock6.c
> +++ b/nptl/tst-rwlock6.c
> @@ -25,6 +25,11 @@
>  #include <support/timespec.h>
>  
>  
> +/* A bogus clock value that tells run_test to use
> +   pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock rather
> +   than pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock. */
> +#define CLOCK_USE_TIMEDLOCK (-1)
> +
>  static int kind[] =
>    {
>      PTHREAD_RWLOCK_PREFER_READER_NP,
> @@ -32,75 +37,91 @@ static int kind[] =
>      PTHREAD_RWLOCK_PREFER_WRITER_NP,
>    };
>  
> +struct thread_args {
> +  pthread_rwlock_t *rwlock;
> +  clockid_t clockid;
> +  const char *fnname;
> +};

Line-feed before open bracket.

>  
>  static void *
>  tf (void *arg)
>  {
> -  pthread_rwlock_t *r = arg;
> +  struct thread_args *args = arg;
> +  pthread_rwlock_t *r = args->rwlock;
> +  const clockid_t clockid = args->clockid;
> +  const clockid_t clockid_for_get =
> +    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
> +  const char *fnname = args->fnname;
>  
>    /* Timeout: 0.3 secs.  */
>    struct timespec ts_start;
> -  (void) clock_gettime(CLOCK_REALTIME, &ts_start);
> +  (void) clock_gettime (clockid_for_get, &ts_start);
>  
>    struct timespec ts_timeout = {0, 300000000};
> -  timespec_add(&ts_timeout, &ts_start, &ts_timeout);
> +  timespec_add (&ts_timeout, &ts_start, &ts_timeout);
>  
> -  puts ("child calling timedrdlock");
> +  printf ("child calling %srdlock\n", fnname);
>  
> -  int err = pthread_rwlock_timedrdlock (r, &ts_timeout);
> +  int err = (clockid == CLOCK_USE_TIMEDLOCK)
> +    ? pthread_rwlock_timedrdlock (r, &ts_timeout)
> +    : pthread_rwlock_clockrdlock (r, clockid, &ts_timeout);
>    if (err == 0)
>      {
> -      puts ("rwlock_timedrdlock returned");
> +      printf ("%srdlock returned\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
>  
>    if (err != ETIMEDOUT)
>      {
> -      printf ("err = %s (%d), expected %s (%d)\n",
> -	      strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
> +      printf ("%srdlock: err = %s (%d), expected %s (%d)\n",
> +	      fnname, strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
>        pthread_exit ((void *) 1l);
>      }
>  
> -  puts ("1st child timedrdlock done");
> +  printf ("1st child %srdlock done\n", fnname);
>  
>    struct timespec ts_end;
> -  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
> +  (void) clock_gettime (clockid_for_get, &ts_end);
>  
>    struct timespec ts_duration;
> -  timespec_sub(&ts_duration, &ts_end, &ts_start);
> +  timespec_sub (&ts_duration, &ts_end, &ts_start);
>  
>    if (ts_duration.tv_sec !=0 || ts_duration.tv_nsec < 200000000)
>      {
> -      puts ("timeout too short");
> +      printf ("%srdlock: timeout too short\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
>  
> -  (void) clock_gettime (CLOCK_REALTIME, &ts_timeout);
> +  (void) clock_gettime (clockid_for_get, &ts_timeout);
>    ts_timeout.tv_sec += 10;
>    /* Note that the following operation makes ts invalid.  */
>    ts_timeout.tv_nsec += 1000000000;
>  
> -  err = pthread_rwlock_timedrdlock (r, &ts_timeout);
> +  err = (clockid == CLOCK_USE_TIMEDLOCK)
> +    ? pthread_rwlock_timedrdlock (r, &ts_timeout)
> +    : pthread_rwlock_clockrdlock (r, clockid, &ts_timeout);
>    if (err == 0)
>      {
> -      puts ("2nd timedrdlock succeeded");
> +      printf ("2nd %srdlock succeeded\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
>    if (err != EINVAL)
>      {
> -      puts ("2nd timedrdlock did not return EINVAL");
> +      printf ("2nd %srdlock did not return EINVAL\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
>  
> -  puts ("2nd child timedrdlock done");
> +  printf ("2nd child %srdlock done\n", fnname);
>  
>    return NULL;
>  }
>  
>  
>  static int
> -do_test (void)
> +do_test_clock (clockid_t clockid, const char *fnname)
>  {
> +  const clockid_t clockid_for_get =
> +    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
>    size_t cnt;
>    for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
>      {
> @@ -132,53 +153,63 @@ do_test (void)
>  	}
>  
>        struct timespec ts;
> -      (void) clock_gettime (CLOCK_REALTIME, &ts);
> +      (void) clock_gettime (clockid_for_get, &ts);
>        ++ts.tv_sec;
>  
>        /* Get a write lock.  */
> -      int e = pthread_rwlock_timedwrlock (&r, &ts);
> +      int e = (clockid == CLOCK_USE_TIMEDLOCK)
> +	? pthread_rwlock_timedwrlock (&r, &ts)
> +	: pthread_rwlock_clockwrlock (&r, clockid, &ts);
>        if (e != 0)
>  	{
> -	  printf ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e);
> +	  printf ("round %Zu: %swrlock failed (%d)\n", cnt, fnname, e);
>  	  exit (1);
>  	}
>  
> -      puts ("1st timedwrlock done");
> +      printf ("1st %swrlock done\n", fnname);
>  
> -      (void) clock_gettime (CLOCK_REALTIME, &ts);
> +      (void) clock_gettime (clockid, &ts);
>        ++ts.tv_sec;
> -      e = pthread_rwlock_timedrdlock (&r, &ts);
> +      e = (clockid == CLOCK_USE_TIMEDLOCK)
> +	? pthread_rwlock_timedrdlock (&r, &ts)
> +	: pthread_rwlock_clockrdlock (&r, clockid, &ts);
>        if (e == 0)
>  	{
> -	  puts ("timedrdlock succeeded");
> +	  printf ("%srdlock succeeded\n", fnname);
>  	  exit (1);
>  	}
>        if (e != EDEADLK)
>  	{
> -	  puts ("timedrdlock did not return EDEADLK");
> +	  printf ("%srdlock did not return EDEADLK\n", fnname);
>  	  exit (1);
>  	}
>  
> -      puts ("1st timedrdlock done");
> +      printf ("1st %srdlock done\n", fnname);
>  
> -      (void) clock_gettime (CLOCK_REALTIME, &ts);
> +      (void) clock_gettime (clockid_for_get, &ts);
>        ++ts.tv_sec;
> -      e = pthread_rwlock_timedwrlock (&r, &ts);
> +      e = (clockid == CLOCK_USE_TIMEDLOCK)
> +	? pthread_rwlock_timedwrlock (&r, &ts)
> +	: pthread_rwlock_clockwrlock (&r, clockid, &ts);
>        if (e == 0)
>  	{
> -	  puts ("2nd timedwrlock succeeded");
> +	  printf ("2nd %swrlock succeeded\n", fnname);
>  	  exit (1);
>  	}
>        if (e != EDEADLK)
>  	{
> -	  puts ("2nd timedwrlock did not return EDEADLK");
> +	  printf ("2nd %swrlock did not return EDEADLK\n", fnname);
>  	  exit (1);
>  	}
>  
> -      puts ("2nd timedwrlock done");
> +      printf ("2nd %swrlock done\n", fnname);
>  
>        pthread_t th;
> -      if (pthread_create (&th, NULL, tf, &r) != 0)
> +      struct thread_args args;
> +      args.rwlock = &r;
> +      args.clockid = clockid;
> +      args.fnname = fnname;
> +      if (pthread_create (&th, NULL, tf, &args) != 0)
>  	{
>  	  printf ("round %Zu: create failed\n", cnt);
>  	  exit (1);
> @@ -210,5 +241,13 @@ do_test (void)
>    return 0;
>  }
>  
> +static int do_test (void)
> +{
> +  do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
> +  do_test_clock (CLOCK_REALTIME, "clock(realtime)");
> +  do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
> +  return 0;
> +}
> +
>  #define TEST_FUNCTION do_test ()
>  #include "../test-skeleton.c"
> diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
> index 812506c..0bccd18 100644
> --- a/nptl/tst-rwlock7.c
> +++ b/nptl/tst-rwlock7.c
> @@ -25,6 +25,11 @@
>  #include <support/timespec.h>
>  
>  
> +/* A bogus clock value that tells run_test to use
> +   pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock rather
> +   than pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock. */
> +#define CLOCK_USE_TIMEDLOCK (-1)
> +
>  static int kind[] =
>    {
>      PTHREAD_RWLOCK_PREFER_READER_NP,
> @@ -32,22 +37,34 @@ static int kind[] =
>      PTHREAD_RWLOCK_PREFER_WRITER_NP,
>    };
>  
> +struct thread_args
> +{
> +  pthread_rwlock_t *rwlock;
> +  clockid_t clockid;
> +  const char *fnname;
> +};
>  
>  static void *
>  tf (void *arg)
>  {
> -  pthread_rwlock_t *r = arg;
> +  struct thread_args *args = arg;
> +  pthread_rwlock_t *r = args->rwlock;
> +  clockid_t clockid = args->clockid;
> +  const char *fnname = args->fnname;
>  
>    /* Timeout: 0.3 secs.  */
>    struct timespec ts_start;
> -  (void) clock_gettime (CLOCK_REALTIME, &ts_start);
> +  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
> +			? CLOCK_REALTIME : clockid, &ts_start);
>    struct timespec ts_timeout = {0, 300000000};
>    timespec_add(&ts_timeout, &ts_start, &ts_timeout);
>  
> -  int err = pthread_rwlock_timedwrlock (r, &ts_timeout);
> +  int err = (clockid == CLOCK_USE_TIMEDLOCK)
> +    ? pthread_rwlock_timedwrlock (r, &ts_timeout)
> +    : pthread_rwlock_clockwrlock (r, clockid, &ts_timeout);
>    if (err == 0)
>      {
> -      puts ("rwlock_timedwrlock returned");
> +      printf ("pthread_rwlock_%swrlock returned\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
>  
> @@ -57,44 +74,49 @@ tf (void *arg)
>  	      strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT);
>        pthread_exit ((void *) 1l);
>      }
> -  puts ("child: timedwrlock failed with ETIMEDOUT");
> +  printf ("child: pthread_rwlock_%swrlock failed with ETIMEDOUT\n", fnname);
>  
>    struct timespec ts_end;
> -  (void) clock_gettime (CLOCK_REALTIME, &ts_end);
> +  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
> +			? CLOCK_REALTIME : clockid, &ts_end);
>    struct timespec ts_diff;
>    timespec_sub (&ts_diff, &ts_end, &ts_start);
>  
>    if (ts_diff.tv_sec != 0 || ts_diff.tv_nsec < 200000000)
>      {
> -      puts ("timeout too short");
> +      printf ("pthread_rwlock_%srwlock timeout too short: %ld.%09ld\n",
> +	      fnname, (long)ts_diff.tv_sec, (long)ts_diff.tv_nsec);
>        pthread_exit ((void *) 1l);
>      }
>  
>    struct timespec ts_invalid;
> -  (void) clock_gettime (CLOCK_REALTIME, &ts_invalid);
> +  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
> +			? CLOCK_REALTIME : clockid, &ts_invalid);
>    ts_invalid.tv_sec += 10;
>    /* Note that the following operation makes ts invalid.  */
>    ts_invalid.tv_nsec += 1000000000000;
>  
> -  err = pthread_rwlock_timedwrlock (r, &ts_invalid);
> +  err = (clockid == CLOCK_USE_TIMEDLOCK)
> +	 ? pthread_rwlock_timedwrlock (r, &ts_invalid)
> +	 : pthread_rwlock_clockwrlock (r, clockid, &ts_invalid);
>    if (err == 0)
>      {
> -      puts ("2nd timedwrlock succeeded");
> +      printf ("2nd pthread_%srwlock succeeded\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
>    if (err != EINVAL)
>      {
> -      puts ("2nd timedwrlock did not return EINVAL");
> +      printf ("2nd pthread_%srwlock did not return EINVAL\n", fnname);
>        pthread_exit ((void *) 1l);
>      }
> -  puts ("child: timedwrlock failed with EINVAL");
> +  printf ("child: %s failed with EINVAL\n", fnname);
>  
>    return NULL;
>  }
>  
>  
>  static int
> -do_test (void)
> +do_test_clock (clockid_t clockid, const char *fnname)
>  {
>    size_t cnt;
>    for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt)
> @@ -127,20 +149,27 @@ do_test (void)
>  	}
>  
>        struct timespec ts;
> -      (void) clock_gettime (CLOCK_REALTIME, &ts);
> +      (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK) ?
> +			    CLOCK_REALTIME: clockid, &ts);
>  
>        ++ts.tv_sec;
>  
>        /* Get a read lock.  */
> -      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
> +      if ((clockid == CLOCK_USE_TIMEDLOCK)
> +	  ? pthread_rwlock_timedrdlock (&r, &ts)
> +	  : pthread_rwlock_clockrdlock (&r, clockid, &ts) != 0)
>  	{
> -	  printf ("round %Zu: rwlock_timedrdlock failed\n", cnt);
> +	  printf ("round %Zu: pthread_rwlock%srdlock failed\n", cnt, fnname);
>  	  exit (1);
>  	}
> -      printf ("%zu: got timedrdlock\n", cnt);
> +      printf ("%zu: got pthread_rwlock_%srdlock\n", cnt, fnname);
>  
> +      struct thread_args args;
> +      args.rwlock = &r;
> +      args.clockid = clockid;
> +      args.fnname = fnname;
>        pthread_t th;
> -      if (pthread_create (&th, NULL, tf, &r) != 0)
> +      if (pthread_create (&th, NULL, tf, &args) != 0)
>  	{
>  	  printf ("round %Zu: create failed\n", cnt);
>  	  exit (1);
> @@ -168,5 +197,15 @@ do_test (void)
>    return 0;
>  }
>  
> +static int
> +do_test (void)
> +{
> +  do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
> +  do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
> +  do_test_clock (CLOCK_REALTIME, "clock(realtime)");
> +
> +  return 0;
> +}
> +
>  #define TEST_FUNCTION do_test ()
>  #include "../test-skeleton.c"
> diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
> index ff15f90..2691f6a 100644
> --- a/nptl/tst-rwlock9.c
> +++ b/nptl/tst-rwlock9.c
> @@ -38,12 +38,28 @@
>  # define KIND PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
>  #endif
>  
> +/* A bogus clock value that tells the tests to use
> +   pthread_rwlock_timedrdlock and pthread_rwlock_timedwrlock rather
> +   than pthread_rwlock_clockrdlock and pthread_rwlock_clockwrlock. */
> +#define CLOCK_USE_TIMEDLOCK (-1)
> +
>  static pthread_rwlock_t lock;
>  
> +struct thread_args
> +{
> +  int nr;
> +  clockid_t clockid;
> +  const char *fnname;
> +};
>  
>  static void *
> -writer_thread (void *nr)
> +writer_thread (void *arg)
>  {
> +  struct thread_args *args = arg;
> +  const int nr = args->nr;
> +  const clockid_t clockid = args->clockid;
> +  const char *fnname = args->fnname;
> +
>    struct timespec ts;
>    struct timespec delay;
>    int n;
> @@ -56,7 +72,8 @@ writer_thread (void *nr)
>        int e;
>        do
>  	{
> -	  (void) clock_gettime (CLOCK_REALTIME, &ts);
> +	  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
> +				? CLOCK_REALTIME : clockid, &ts);
>  
>  	  ts.tv_nsec += 2 * TIMEOUT;
>  	  if (ts.tv_nsec >= 1000000000)
> @@ -65,18 +82,20 @@ writer_thread (void *nr)
>  	      ++ts.tv_sec;
>  	    }
>  
> -	  printf ("writer thread %ld tries again\n", (long int) nr);
> +	  printf ("writer thread %d tries again\n", nr);
>  
> -	  e = pthread_rwlock_timedwrlock (&lock, &ts);
> +	  e = (clockid == CLOCK_USE_TIMEDLOCK)
> +	    ? pthread_rwlock_timedwrlock (&lock, &ts)
> +	    : pthread_rwlock_clockwrlock (&lock, clockid, &ts);
>  	  if (e != 0 && e != ETIMEDOUT)
>  	    {
> -	      puts ("timedwrlock failed");
> +	      printf ("%swrlock failed", fnname);
>  	      exit (1);
>  	    }
>  	}
>        while (e == ETIMEDOUT);
>  
> -      printf ("writer thread %ld succeeded\n", (long int) nr);
> +      printf ("writer thread %d succeeded\n", nr);
>  
>        nanosleep (&delay, NULL);
>  
> @@ -86,7 +105,7 @@ writer_thread (void *nr)
>  	  exit (1);
>  	}
>  
> -      printf ("writer thread %ld released\n", (long int) nr);
> +      printf ("writer thread %d released\n", nr);
>      }
>  
>    return NULL;
> @@ -94,8 +113,13 @@ writer_thread (void *nr)
>  
>  
>  static void *
> -reader_thread (void *nr)
> +reader_thread (void *arg)
>  {
> +  struct thread_args *args = arg;
> +  const int nr = args->nr;
> +  const clockid_t clockid = args->clockid;
> +  const char *fnname = args->fnname;
> +
>    struct timespec ts;
>    struct timespec delay;
>    int n;
> @@ -108,8 +132,8 @@ reader_thread (void *nr)
>        int e;
>        do
>  	{
> -	  (void) clock_gettime (CLOCK_REALTIME, &ts);
> -
> +	  (void) clock_gettime ((clockid == CLOCK_USE_TIMEDLOCK)
> +				? CLOCK_REALTIME : clockid, &ts);
>  	  ts.tv_nsec += TIMEOUT;
>  	  if (ts.tv_nsec >= 1000000000)
>  	    {
> @@ -117,18 +141,20 @@ reader_thread (void *nr)
>  	      ++ts.tv_sec;
>  	    }
>  
> -	  printf ("reader thread %ld tries again\n", (long int) nr);
> +	  printf ("reader thread %d tries again\n", nr);
>  
> -	  e = pthread_rwlock_timedrdlock (&lock, &ts);
> +	  e = (clockid == CLOCK_USE_TIMEDLOCK)
> +	    ? pthread_rwlock_timedrdlock (&lock, &ts)
> +	    : pthread_rwlock_clockrdlock (&lock, clockid, &ts);
>  	  if (e != 0 && e != ETIMEDOUT)
>  	    {
> -	      puts ("timedrdlock failed");
> +	      printf ("%srdlock failed\n", fnname);
>  	      exit (1);
>  	    }
>  	}
>        while (e == ETIMEDOUT);
>  
> -      printf ("reader thread %ld succeeded\n", (long int) nr);
> +      printf ("reader thread %d succeeded\n", nr);
>  
>        nanosleep (&delay, NULL);
>  
> @@ -138,7 +164,7 @@ reader_thread (void *nr)
>  	  exit (1);
>  	}
>  
> -      printf ("reader thread %ld released\n", (long int) nr);
> +      printf ("reader thread %d released\n", nr);
>      }
>  
>    return NULL;
> @@ -146,7 +172,7 @@ reader_thread (void *nr)
>  
>  
>  static int
> -do_test (void)
> +do_test_clock (clockid_t clockid, const char *fnname)
>  {
>    pthread_t thwr[NWRITERS];
>    pthread_t thrd[NREADERS];
> @@ -178,21 +204,31 @@ do_test (void)
>    /* Make sure we see all message, even those on stdout.  */
>    setvbuf (stdout, NULL, _IONBF, 0);
>  
> -  for (n = 0; n < NWRITERS; ++n)
> +  struct thread_args wargs[NWRITERS];
> +  for (n = 0; n < NWRITERS; ++n) {
> +    wargs[n].nr = n;
> +    wargs[n].clockid = clockid;
> +    wargs[n].fnname = fnname;
>      if (pthread_create (&thwr[n], NULL, writer_thread,
> -			(void *) (long int) n) != 0)
> +			&wargs[n]) != 0)
>        {
>  	puts ("writer create failed");
>  	exit (1);
>        }
> +  }
>  
> -  for (n = 0; n < NREADERS; ++n)
> +  struct thread_args rargs[NREADERS];
> +  for (n = 0; n < NREADERS; ++n) {
> +    rargs[n].nr = n;
> +    rargs[n].clockid = clockid;
> +    rargs[n].fnname = fnname;
>      if (pthread_create (&thrd[n], NULL, reader_thread,
> -			(void *) (long int) n) != 0)
> +			&rargs[n]) != 0)
>        {
>  	puts ("reader create failed");
>  	exit (1);
>        }
> +  }
>  
>    /* Wait for all the threads.  */
>    for (n = 0; n < NWRITERS; ++n)
> @@ -211,6 +247,16 @@ do_test (void)
>    return 0;
>  }
>  
> +static int
> +do_test (void)
> +{
> +  do_test_clock (CLOCK_USE_TIMEDLOCK, "timed");
> +  do_test_clock (CLOCK_REALTIME, "clock(realtime)");
> +  do_test_clock (CLOCK_MONOTONIC, "clock(monotonic)");
> +
> +  return 0;
> +}
> +
>  #undef TIMEOUT
>  #define TIMEOUT 30
>  #define TEST_FUNCTION do_test ()
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index d4fe9d9..3c06d77 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -907,6 +907,10 @@ extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
>  extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
>  				       const struct timespec *__restrict
>  				       __abstime) __THROWNL __nonnull ((1, 2));
> +extern int pthread_rwlock_clockrdlock (pthread_rwlock_t *__restrict __rwlock,
> +				       clockid_t __clockid,
> +				       const struct timespec *__restrict
> +				       __abstime) __THROWNL __nonnull ((1, 3));
>  # endif
>  
>  /* Acquire write lock for RWLOCK.  */
> @@ -922,6 +926,10 @@ extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
>  extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
>  				       const struct timespec *__restrict
>  				       __abstime) __THROWNL __nonnull ((1, 2));
> +extern int pthread_rwlock_clockwrlock (pthread_rwlock_t *__restrict __rwlock,
> +				       clockid_t __clockid,
> +				       const struct timespec *__restrict
> +				       __abstime) __THROWNL __nonnull ((1, 3));
>  # endif
>  
>  /* Unlock RWLOCK.  */
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index aaa1c3b..70f04cc 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -246,6 +246,8 @@ GLIBC_2.3.4 pthread_getaffinity_np F
>  GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
>  GLIBC_2.30 pthread_cond_clockwait F
> +GLIBC_2.30 pthread_rwlock_clockrdlock F
> +GLIBC_2.30 pthread_rwlock_clockwrlock F
>  GLIBC_2.30 sem_clockwait F
>  GLIBC_2.4 pthread_mutex_consistent_np F
>  GLIBC_2.4 pthread_mutex_getprioceiling F
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls
  2019-03-05 12:39   ` Adhemerval Zanella
@ 2019-03-10  8:59     ` Mike Crowe
  2019-03-11 11:50       ` Adhemerval Zanella
  0 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-03-10  8:59 UTC (permalink / raw)
  To: libc-alpha

On Tuesday 05 March 2019 at 09:39:58 -0300, Adhemerval Zanella wrote:
> > diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
> > index 9a0f29e..daa4e25 100644
> > --- a/nptl/pthread_cond_wait.c
> > +++ b/nptl/pthread_cond_wait.c
> > @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
> >  		{
> >  		  /* Use CLOCK_REALTIME.  */
> >  		  err = futex_abstimed_wait_cancelable
> > -		      (cond->__data.__g_signals + g, 0, abstime, private);
> > +		      (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private);
> >  		}
> >  	    }
> >  
> 
> Since we still assume that an architecture might not support futex
> with CLOCK_REALTIME, this part should check for __ASSUME_FUTEX_CLOCK_REALTIME
> as other parts.
> 
> I proposed recently to just assume __ASSUME_FUTEX_CLOCK_REALTIME
> support [1], which simplifies this patch.

Whilst trying to implement pthread_mutex_clockclock offline yesterday, I
decided to propose the same thing. It looks like I don't need to. :)

> [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00667.html

It would certainly make my life easier if that patch was merged.

Thanks.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-03-06 21:15   ` Joseph Myers
@ 2019-03-10  9:12     ` Mike Crowe
  2019-03-11 23:13       ` Joseph Myers
  0 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-03-10  9:12 UTC (permalink / raw)
  To: libc-alpha

On Wednesday 06 March 2019 at 21:15:18 +0000, Joseph Myers wrote:
> On Tue, 5 Mar 2019, Adhemerval Zanella wrote:
> 
> > > The mq_clockreceive and mq_clocksend functions corresponding to
> > > mq_timedreceive and mq_timedsend require kernel changes before they can be
> > > implemented in glibc.
> > 
> > Should we add them as ENOSYS as generic stubs in this version?
> 
> I'd expect any generic stubs to work with CLOCK_REALTIME without returning 
> ENOSYS errors in that case.

Yes. However, I wasn't planning to implement mq_clockreceive and
mq_clocksend or propose them for POSIX now. Apparently they can be
described as being "future direction". I'd rather get the other functions
completed first.

It would be straightforward to add them with support for CLOCK_REALTIME
only, but I'm not sure that it really brings much value. Adding
CLOCK_MONOTONIC support at the same time as the new functions would mean
that autoconf scripts would know that CLOCK_MONOTONIC was supported if the
functions were found, rather than having to fall back at runtime.

> > > The changes have been tested with "make check" on x86_64 and arm64. Earlier
> > > versions were tested on arm. I haven't updated the ChangeLog, NEWS or
> > > architecture abilists yet (so some tests fail on arm64), but will do so if
> > > the rest of the changes are acceptable.
> > 
> > Are arm64 failures related to the patchset itself?
> 
> My reading is that they result from missing ABI updates.  (Each patch 
> ought to update all relevant ABI lists to avoid introducing failures.)

Yes. I did spend a while updating various ABI lists, but I kept having to
change them each time there was a glibc release, so I decided that I'd wait
until the rest of the changes were acceptable. Similarly for NEWS and
ChangeLog.

Thanks, and thanks for all the other comments. I'll update the patches
accordingly.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-03-05 13:31   ` Adhemerval Zanella
@ 2019-03-10 16:17     ` Mike Crowe
  2019-03-19 17:07       ` Adhemerval Zanella
  0 siblings, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-03-10 16:17 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha

On Tuesday 05 March 2019 at 10:31:33 -0300, Adhemerval Zanella wrote:
> On 27/02/2019 15:23, Mike Crowe wrote:
> > diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
> > index 2149ade..7f1031d 100644
> > --- a/nptl/tst-sem5.c
> > +++ b/nptl/tst-sem5.c
> > @@ -23,13 +23,15 @@
> >  #include <unistd.h>
> >  #include <sys/time.h>
> 
> As for tst-sem13.c, I think it would be good to adapt to libsupport.

Something like this (before I make the same mistakes on the others):

Subject: [PATCH] nptl: Convert tst-sem5 to use libsupport

* nptl/tst-sem5.c: Remove unused headers. Add <support/check.h>. (do_test)
  Use libsupport test macros rather than hand-coded conditionals and error
  messages. Ensure that sem_init returns zero rather than not -1. Use
  <support/test-driver.c> rather than test-skeleton.c.
---
 nptl/tst-sem5.c | 53 ++++++++++-------------------------------------------
 1 file changed, 10 insertions(+), 43 deletions(-)

diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
index 2149adeb12..846813243b 100644
--- a/nptl/tst-sem5.c
+++ b/nptl/tst-sem5.c
@@ -18,11 +18,10 @@

 #include <errno.h>
 #include <semaphore.h>
-#include <stdio.h>
 #include <time.h>
 #include <unistd.h>
 #include <sys/time.h>
-
+#include <support/check.h>

 static int
 do_test (void)
@@ -31,23 +30,9 @@ do_test (void)
   struct timespec ts;
   struct timeval tv;

-  if (sem_init (&s, 0, 1) == -1)
-    {
-      puts ("sem_init failed");
-      return 1;
-    }
-
-  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
-    {
-      puts ("sem_wait failed");
-      return 1;
-    }
-
-  if (gettimeofday (&tv, NULL) != 0)
-    {
-      puts ("gettimeofday failed");
-      return 1;
-    }
+  TEST_COMPARE (sem_init (&s, 0, 1), 0);
+  TEST_COMPARE (TEMP_FAILURE_RETRY (sem_wait (&s)), 0);
+  TEST_COMPARE (gettimeofday (&tv, NULL), 0);

   TIMEVAL_TO_TIMESPEC (&tv, &ts);

@@ -60,34 +45,16 @@ do_test (void)
     }

   errno = 0;
-  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
-    {
-      puts ("sem_timedwait succeeded");
-      return 1;
-    }
-  if (errno != ETIMEDOUT)
-    {
-      printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n",
-	      errno);
-      return 1;
-    }
+  TEST_COMPARE (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)), -1);
+  TEST_COMPARE (errno, ETIMEDOUT);

   struct timespec ts2;
-  if (clock_gettime (CLOCK_REALTIME, &ts2) != 0)
-    {
-      puts ("clock_gettime failed");
-      return 1;
-    }
+  TEST_COMPARE (clock_gettime (CLOCK_REALTIME, &ts2), 0);

-  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;
-    }
+  TEST_VERIFY (ts2.tv_sec > ts.tv_sec
+               || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec > ts.tv_nsec));

   return 0;
 }

-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
--
2.11.0

Thanks.

Mike.

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls
  2019-03-10  8:59     ` Mike Crowe
@ 2019-03-11 11:50       ` Adhemerval Zanella
  0 siblings, 0 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-11 11:50 UTC (permalink / raw)
  To: libc-alpha



On 10/03/2019 05:59, Mike Crowe wrote:
> On Tuesday 05 March 2019 at 09:39:58 -0300, Adhemerval Zanella wrote:
>>> diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
>>> index 9a0f29e..daa4e25 100644
>>> --- a/nptl/pthread_cond_wait.c
>>> +++ b/nptl/pthread_cond_wait.c
>>> @@ -537,7 +537,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>>>  		{
>>>  		  /* Use CLOCK_REALTIME.  */
>>>  		  err = futex_abstimed_wait_cancelable
>>> -		      (cond->__data.__g_signals + g, 0, abstime, private);
>>> +		      (cond->__data.__g_signals + g, 0, CLOCK_REALTIME, abstime, private);
>>>  		}
>>>  	    }
>>>  
>>
>> Since we still assume that an architecture might not support futex
>> with CLOCK_REALTIME, this part should check for __ASSUME_FUTEX_CLOCK_REALTIME
>> as other parts.
>>
>> I proposed recently to just assume __ASSUME_FUTEX_CLOCK_REALTIME
>> support [1], which simplifies this patch.
> 
> Whilst trying to implement pthread_mutex_clockclock offline yesterday, I
> decided to propose the same thing. It looks like I don't need to. :)
> 
>> [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00667.html
> 
> It would certainly make my life easier if that patch was merged.
> 
> Thanks.

It is already merged.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-03-10  9:12     ` Mike Crowe
@ 2019-03-11 23:13       ` Joseph Myers
  0 siblings, 0 replies; 33+ messages in thread
From: Joseph Myers @ 2019-03-11 23:13 UTC (permalink / raw)
  To: Mike Crowe; +Cc: libc-alpha

On Sun, 10 Mar 2019, Mike Crowe wrote:

> It would be straightforward to add them with support for CLOCK_REALTIME
> only, but I'm not sure that it really brings much value. Adding
> CLOCK_MONOTONIC support at the same time as the new functions would mean
> that autoconf scripts would know that CLOCK_MONOTONIC was supported if the
> functions were found, rather than having to fall back at runtime.

No, they wouldn't know that, if kernel support is needed for 
CLOCK_MONOTONIC support, because the kernel at runtime might be too old 
(glibc generally supports at least the oldest active LTS kernel series).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-03-05 12:35 ` [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Adhemerval Zanella
  2019-03-06 21:15   ` Joseph Myers
@ 2019-03-13 21:42   ` Mike Crowe
  2019-03-14 11:30     ` Adhemerval Zanella
  1 sibling, 1 reply; 33+ messages in thread
From: Mike Crowe @ 2019-03-13 21:42 UTC (permalink / raw)
  To: libc-alpha

On Tuesday 05 March 2019 at 09:35:01 -0300, Adhemerval Zanella wrote:
> On 27/02/2019 15:23, Mike Crowe wrote:
> > My attempts[1] to add a variant of pthread_cond_timedwait that would accept
> > a clockid_t parameter led me to propose[2] to The Austin Group the addition
> > of an entire family of functions that accept a clockid_t parameter to
> > indicate the clock that the timespec absolute timeout parameter should be
> > measured against. They responded positively to the request but an
> > implementation is required before the proposal can proceed.
> >
> > This patch series is the first part of that implementation in glibc, it
> > contains four new functions:
> > 
> > int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
> >                            clockid_t clock, const struct timespec *abstime)
> > 
> > int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clock,
> >                                const struct timespec *abstime)
> > 
> > int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clock,
> >                                const struct timespec *abstime)
> > 
> > int sem_clockwait(sem_t *restrict, clockid_t clock_id, const struct
> >                   timespec *restrict)
> > 
> > These are implemented by replacing the underlying equivalent _timed
> > functions with ones that accept a clockid_t parameter, and then
> > implementing the existing _timed functions by passing CLOCK_REALTIME to the
> > new implementation. This requires clockid_t parameters to be added to the
> > underlying futex-internal and lowlevellock-futex functions.
> 
> I am not sure about how to name a new API in this specific case where
> the idea is to use as a reference one for POSIX inclusion.  MY understanding 
> is we still should use a non-portable name scheme with _np suffix and whence
> it is de factor accepted by POSIX we can just alias to the standard
> names. Also if it is done before the release I think we can avoid exporting 
> the _np naming scheme.

Well, non-POSIX functions are added all over glibc without _np extensions.
:) It seems that the convention is used only for pthreads. I can rework the
patches to use the _np extension if required, but I'd hoped that __USE_GNU
was sufficient protection. Perhaps we should see what Joseph and others
think.

> > pthread_mutex_clocklock is not yet implemented because doing so requires a
> > version of __lll_timedlock_wait that supports both CLOCK_MONOTONIC and
> > CLOCK_REALTIME. This function is currently architecture specific. I plan to
> > work on that next, if these changes are considered acceptable.
> 
> About that I think we can work towards once my lowlevellock.S cleanup
> is accepted [4]. Once __lll_timedlock_wait is implemented in generic
> way it would be much more easier to add such extension.
> 
> [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00569.html

That's great. I'll rebase my changes on top of that one before tackling
pthread_mutex_clocklock.

> > The mq_clockreceive and mq_clocksend functions corresponding to
> > mq_timedreceive and mq_timedsend require kernel changes before they can be
> > implemented in glibc.
> 
> Should we add them as ENOSYS as generic stubs in this version?
> Because it seems the kernel work required would be just add a new
> syscall on ipc/mqueue.c to receive a clock_id since 
> schedule_hrtimeout_range_clock already handle CLOCK_MONOTONIC
> (and it luckily fits on 6 argument syscall limit).

If the six argument limit is universal then that will be very helpful. I'd
previously (apparently incorrectly) scared myself into believing that the
functions were already at the limit. I shall dig some more, but these
functions are currently at the bottom of the list.

[snip stuff about errors for clocks that I have no strong feelings about]

> > A number of tests have been updated to use struct timespec rather than
> > struct timeval so that they can call clock_gettime(CLOCK_MONOTONIC) rather
> > then gettimeofday. To make this easier I created the support/timespec.h
> > header file to contain functions to add and subtract timespec structures
> > borrowed from sysdeps/pthread/posix-timer.h. There's probably a better
> > place for these, but I don't know where that might be.
> 
> I think you forgot to update this part since you seemed to had chose
> to use support/timespec.h instead.

Indeed.

Thanks for all your comments.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-03-13 21:42   ` Mike Crowe
@ 2019-03-14 11:30     ` Adhemerval Zanella
  0 siblings, 0 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-14 11:30 UTC (permalink / raw)
  To: libc-alpha



On 13/03/2019 18:42, Mike Crowe wrote:
> On Tuesday 05 March 2019 at 09:35:01 -0300, Adhemerval Zanella wrote:
>> On 27/02/2019 15:23, Mike Crowe wrote:
>>> My attempts[1] to add a variant of pthread_cond_timedwait that would accept
>>> a clockid_t parameter led me to propose[2] to The Austin Group the addition
>>> of an entire family of functions that accept a clockid_t parameter to
>>> indicate the clock that the timespec absolute timeout parameter should be
>>> measured against. They responded positively to the request but an
>>> implementation is required before the proposal can proceed.
>>>
>>> This patch series is the first part of that implementation in glibc, it
>>> contains four new functions:
>>>
>>> int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
>>>                            clockid_t clock, const struct timespec *abstime)
>>>
>>> int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clock,
>>>                                const struct timespec *abstime)
>>>
>>> int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clock,
>>>                                const struct timespec *abstime)
>>>
>>> int sem_clockwait(sem_t *restrict, clockid_t clock_id, const struct
>>>                   timespec *restrict)
>>>
>>> These are implemented by replacing the underlying equivalent _timed
>>> functions with ones that accept a clockid_t parameter, and then
>>> implementing the existing _timed functions by passing CLOCK_REALTIME to the
>>> new implementation. This requires clockid_t parameters to be added to the
>>> underlying futex-internal and lowlevellock-futex functions.
>>
>> I am not sure about how to name a new API in this specific case where
>> the idea is to use as a reference one for POSIX inclusion.  MY understanding 
>> is we still should use a non-portable name scheme with _np suffix and whence
>> it is de factor accepted by POSIX we can just alias to the standard
>> names. Also if it is done before the release I think we can avoid exporting 
>> the _np naming scheme.
> 
> Well, non-POSIX functions are added all over glibc without _np extensions.
> :) It seems that the convention is used only for pthreads. I can rework the
> patches to use the _np extension if required, but I'd hoped that __USE_GNU
> was sufficient protection. Perhaps we should see what Joseph and others
> think.

Indeed I was using the current practice for pthreads extension, but I if 
the idea is to use the same naming for a future POSIX inclusion I think
that guarding with __USE_GNU should be suffice.

> 
>>> pthread_mutex_clocklock is not yet implemented because doing so requires a
>>> version of __lll_timedlock_wait that supports both CLOCK_MONOTONIC and
>>> CLOCK_REALTIME. This function is currently architecture specific. I plan to
>>> work on that next, if these changes are considered acceptable.
>>
>> About that I think we can work towards once my lowlevellock.S cleanup
>> is accepted [4]. Once __lll_timedlock_wait is implemented in generic
>> way it would be much more easier to add such extension.
>>
>> [1] https://sourceware.org/ml/libc-alpha/2019-02/msg00569.html
> 
> That's great. I'll rebase my changes on top of that one before tackling
> pthread_mutex_clocklock.

I will try to get this upstream as well.

> 
>>> The mq_clockreceive and mq_clocksend functions corresponding to
>>> mq_timedreceive and mq_timedsend require kernel changes before they can be
>>> implemented in glibc.
>>
>> Should we add them as ENOSYS as generic stubs in this version?
>> Because it seems the kernel work required would be just add a new
>> syscall on ipc/mqueue.c to receive a clock_id since 
>> schedule_hrtimeout_range_clock already handle CLOCK_MONOTONIC
>> (and it luckily fits on 6 argument syscall limit).
> 
> If the six argument limit is universal then that will be very helpful. I'd
> previously (apparently incorrectly) scared myself into believing that the
> functions were already at the limit. I shall dig some more, but these
> functions are currently at the bottom of the list.

Strictly speaking it depends of the kABI, but afaik from the support ones
only MIPS-n32 actually uses 7 arguments syscalls. I think we can safely
assume all current ABIs support 6 arguments syscalls.

> 
> [snip stuff about errors for clocks that I have no strong feelings about]
> 
>>> A number of tests have been updated to use struct timespec rather than
>>> struct timeval so that they can call clock_gettime(CLOCK_MONOTONIC) rather
>>> then gettimeofday. To make this easier I created the support/timespec.h
>>> header file to contain functions to add and subtract timespec structures
>>> borrowed from sysdeps/pthread/posix-timer.h. There's probably a better
>>> place for these, but I don't know where that might be.
>>
>> I think you forgot to update this part since you seemed to had chose
>> to use support/timespec.h instead.
> 
> Indeed.
> 
> Thanks for all your comments.
> 
> Mike.
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-02-27 18:23 ` [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Mike Crowe
  2019-02-27 18:35   ` Joseph Myers
  2019-03-05 13:31   ` Adhemerval Zanella
@ 2019-03-14 14:09   ` Yann Droneaud
  2019-03-14 14:39     ` Mike Crowe
  2 siblings, 1 reply; 33+ messages in thread
From: Yann Droneaud @ 2019-03-14 14:09 UTC (permalink / raw)
  To: Mike Crowe, libc-alpha

Hi,

Le mercredi 27 février 2019 à 18:23 +0000, Mike Crowe a écrit :
> 
> diff --git a/sysdeps/pthread/semaphore.h
> b/sysdeps/pthread/semaphore.h
> index 41ff927..2e68b16 100644
> --- a/sysdeps/pthread/semaphore.h
> +++ b/sysdeps/pthread/semaphore.h
> @@ -59,6 +59,10 @@ extern int sem_wait (sem_t *__sem);
>     __THROW.  */
>  extern int sem_timedwait (sem_t *__restrict __sem,
>  			  const struct timespec *__restrict __abstime);
> +
> +extern int sem_clockwait (sem_t *__restrict __sem,
> +			  clockid_t clock,
> +			  const struct timespec *__restrict __abstime);

Maybe it can be added with __nonnull ((3)) attribute ?

>  #endif
>  
>  /* Test whether SEM is posted.  */
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 931c827..454d340 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
>  GLIBC_2.3.4 pthread_getaffinity_np F
>  GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
> +GLIBC_2.30 sem_clockwait F

Why is it only added to linux x86_64 ?

Regards

-- 
Yann Droneaud
OPTEYA



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-03-14 14:09   ` Yann Droneaud
@ 2019-03-14 14:39     ` Mike Crowe
  0 siblings, 0 replies; 33+ messages in thread
From: Mike Crowe @ 2019-03-14 14:39 UTC (permalink / raw)
  To: Yann Droneaud; +Cc: libc-alpha

On Thursday 14 March 2019 at 15:09:35 +0100, Yann Droneaud wrote:
> Hi,
> 
> Le mercredi 27 février 2019 à 18:23 +0000, Mike Crowe a écrit :
> > 
> > diff --git a/sysdeps/pthread/semaphore.h
> > b/sysdeps/pthread/semaphore.h
> > index 41ff927..2e68b16 100644
> > --- a/sysdeps/pthread/semaphore.h
> > +++ b/sysdeps/pthread/semaphore.h
> > @@ -59,6 +59,10 @@ extern int sem_wait (sem_t *__sem);
> >     __THROW.  */
> >  extern int sem_timedwait (sem_t *__restrict __sem,
> >  			  const struct timespec *__restrict __abstime);
> > +
> > +extern int sem_clockwait (sem_t *__restrict __sem,
> > +			  clockid_t clock,
> > +			  const struct timespec *__restrict __abstime);
> 
> Maybe it can be added with __nonnull ((3)) attribute ?

I was just copying sem_timedwait, but I don't believe there's a reason why
I can't add that.

> >  #endif
> >  
> >  /* Test whether SEM is posted.  */
> > diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > index 931c827..454d340 100644
> > --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
> >  GLIBC_2.3.4 pthread_getaffinity_np F
> >  GLIBC_2.3.4 pthread_setaffinity_np F
> >  GLIBC_2.3.4 pthread_setschedprio F
> > +GLIBC_2.30 sem_clockwait F
> 
> Why is it only added to linux x86_64 ?

Because I wanted to wait to see if the patches were acceptable before
updating all the abilist files.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval
  2019-02-27 18:23 ` [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval Mike Crowe
  2019-03-05 18:02   ` Adhemerval Zanella
@ 2019-03-14 14:44   ` Yann Droneaud
  1 sibling, 0 replies; 33+ messages in thread
From: Yann Droneaud @ 2019-03-14 14:44 UTC (permalink / raw)
  To: Mike Crowe, libc-alpha

Hi,

Le mercredi 27 février 2019 à 18:23 +0000, Mike Crowe a écrit :
> diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
> index 34f2d04..ff15f90 100644
> --- a/nptl/tst-rwlock9.c
> +++ b/nptl/tst-rwlock9.c
> @@ -56,9 +56,7 @@ writer_thread (void *nr)
>        int e;
>        do
>  	{
> -	  struct timeval tv;
> -	  (void) gettimeofday (&tv, NULL);
> -	  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +	  (void) clock_gettime (CLOCK_REALTIME, &ts);
>  
>  	  ts.tv_nsec += 2 * TIMEOUT;
>  	  if (ts.tv_nsec >= 1000000000)

Should timespec_add() be used here too ?

> @@ -110,9 +108,7 @@ reader_thread (void *nr)
>        int e;
>        do
>  	{
> -	  struct timeval tv;
> -	  (void) gettimeofday (&tv, NULL);
> -	  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +	  (void) clock_gettime (CLOCK_REALTIME, &ts);
>  
>  	  ts.tv_nsec += TIMEOUT;
>  	  if (ts.tv_nsec >= 1000000000)

Same here

Regards.

-- 
Yann Droneaud
OPTEYA



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
                   ` (7 preceding siblings ...)
  2019-03-05 12:35 ` [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Adhemerval Zanella
@ 2019-03-15 13:25 ` Yann Droneaud
  2019-03-15 13:36   ` Mike Crowe
  8 siblings, 1 reply; 33+ messages in thread
From: Yann Droneaud @ 2019-03-15 13:25 UTC (permalink / raw)
  To: Mike Crowe, libc-alpha

Hi,

Le mercredi 27 février 2019 à 18:23 +0000, Mike Crowe a écrit :
> My attempts[1] to add a variant of pthread_cond_timedwait that would accept
> a clockid_t parameter led me to propose[2] to The Austin Group the addition
> of an entire family of functions that accept a clockid_t parameter to
> indicate the clock that the timespec absolute timeout parameter should be
> measured against. They responded positively to the request but an
> implementation is required before the proposal can proceed.
> 
> This patch series is the first part of that implementation in glibc, it
> contains four new functions:
> 
> int pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
>                            clockid_t clock, const struct timespec *abstime)
> 
> int pthread_rwlock_clockrdlock(pthread_rwlock_t *rwlock, clockid_t clock,
>                                const struct timespec *abstime)
> 
> int pthread_rwlock_clockwrlock(pthread_rwlock_t *rwlock, clockid_t clock,
>                                const struct timespec *abstime)
> 
> int sem_clockwait(sem_t *restrict, clockid_t clock_id, const struct
>                   timespec *restrict)
> 

There's also a pthread_timedjoin_np() that could benefit from having
"pthread_clockjoin_np()" sibling.

Regards.

-- 
Yann Droneaud
OPTEYA



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions
  2019-03-15 13:25 ` Yann Droneaud
@ 2019-03-15 13:36   ` Mike Crowe
  0 siblings, 0 replies; 33+ messages in thread
From: Mike Crowe @ 2019-03-15 13:36 UTC (permalink / raw)
  To: Yann Droneaud, libc-alpha

On Friday 15 March 2019 at 14:25:43 +0100, Yann Droneaud wrote:
> There's also a pthread_timedjoin_np() that could benefit from having
> "pthread_clockjoin_np()" sibling.

Yes. That's on my list to get to, but since it's not a POSIX function I
thought it best to get the others done first.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait
  2019-03-10 16:17     ` Mike Crowe
@ 2019-03-19 17:07       ` Adhemerval Zanella
  0 siblings, 0 replies; 33+ messages in thread
From: Adhemerval Zanella @ 2019-03-19 17:07 UTC (permalink / raw)
  To: Mike Crowe, libc-alpha



On 10/03/2019 13:17, Mike Crowe wrote:
> On Tuesday 05 March 2019 at 10:31:33 -0300, Adhemerval Zanella wrote:
>> On 27/02/2019 15:23, Mike Crowe wrote:
>>> diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
>>> index 2149ade..7f1031d 100644
>>> --- a/nptl/tst-sem5.c
>>> +++ b/nptl/tst-sem5.c
>>> @@ -23,13 +23,15 @@
>>>  #include <unistd.h>
>>>  #include <sys/time.h>
>>
>> As for tst-sem13.c, I think it would be good to adapt to libsupport.
> 
> Something like this (before I make the same mistakes on the others):
> 
> Subject: [PATCH] nptl: Convert tst-sem5 to use libsupport
> 
> * nptl/tst-sem5.c: Remove unused headers. Add <support/check.h>. (do_test)
>   Use libsupport test macros rather than hand-coded conditionals and error
>   messages. Ensure that sem_init returns zero rather than not -1. Use
>   <support/test-driver.c> rather than test-skeleton.c.

I think you can just simplify to:

   * nptl/tst-sem5.c: Use libsupport.

LGTM, thanks.


> ---
>  nptl/tst-sem5.c | 53 ++++++++++-------------------------------------------
>  1 file changed, 10 insertions(+), 43 deletions(-)
> 
> diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
> index 2149adeb12..846813243b 100644
> --- a/nptl/tst-sem5.c
> +++ b/nptl/tst-sem5.c
> @@ -18,11 +18,10 @@
> 
>  #include <errno.h>
>  #include <semaphore.h>
> -#include <stdio.h>
>  #include <time.h>
>  #include <unistd.h>
>  #include <sys/time.h>
> -
> +#include <support/check.h>
> 
>  static int
>  do_test (void)
> @@ -31,23 +30,9 @@ do_test (void)
>    struct timespec ts;
>    struct timeval tv;
> 
> -  if (sem_init (&s, 0, 1) == -1)
> -    {
> -      puts ("sem_init failed");
> -      return 1;
> -    }
> -
> -  if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1)
> -    {
> -      puts ("sem_wait failed");
> -      return 1;
> -    }
> -
> -  if (gettimeofday (&tv, NULL) != 0)
> -    {
> -      puts ("gettimeofday failed");
> -      return 1;
> -    }
> +  TEST_COMPARE (sem_init (&s, 0, 1), 0);
> +  TEST_COMPARE (TEMP_FAILURE_RETRY (sem_wait (&s)), 0);
> +  TEST_COMPARE (gettimeofday (&tv, NULL), 0);
> 
>    TIMEVAL_TO_TIMESPEC (&tv, &ts);
> 
> @@ -60,34 +45,16 @@ do_test (void)
>      }
> 
>    errno = 0;
> -  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
> -    {
> -      puts ("sem_timedwait succeeded");
> -      return 1;
> -    }
> -  if (errno != ETIMEDOUT)
> -    {
> -      printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n",
> -	      errno);
> -      return 1;
> -    }
> +  TEST_COMPARE (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)), -1);
> +  TEST_COMPARE (errno, ETIMEDOUT);
> 
>    struct timespec ts2;
> -  if (clock_gettime (CLOCK_REALTIME, &ts2) != 0)
> -    {
> -      puts ("clock_gettime failed");
> -      return 1;
> -    }
> +  TEST_COMPARE (clock_gettime (CLOCK_REALTIME, &ts2), 0);
> 
> -  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;
> -    }
> +  TEST_VERIFY (ts2.tv_sec > ts.tv_sec
> +               || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec > ts.tv_nsec));
> 
>    return 0;
>  }
> 
> -#define TEST_FUNCTION do_test ()
> -#include "../test-skeleton.c"
> +#include <support/test-driver.c>
> --
> 2.11.0
> 
> Thanks.
> 
> Mike.
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval
  2019-03-05 18:02   ` Adhemerval Zanella
@ 2019-03-20 21:34     ` Mike Crowe
  0 siblings, 0 replies; 33+ messages in thread
From: Mike Crowe @ 2019-03-20 21:34 UTC (permalink / raw)
  To: libc-alpha

On Tuesday 05 March 2019 at 15:02:21 -0300, Adhemerval Zanella wrote:
> On 27/02/2019 15:23, Mike Crowe wrote:
> > In preparation for adding pthread_rwlock_clockrdlock and
> > pthread_rwlock_clockwrlock, convert various tests to only use clock_gettime
> > and struct timespec.
> > 
> > * support/timespec.h: Create header to provide timespec helper functions
> >   from sysdeps/pthread/posix-timer.h for tests to use.
> > 
> > * nptl/tst-rwlock6.c: Fix small bug in timeout-checking code that could
> >   erroneously pass if the function incorrectly took more than a second.
> > 
> > * nptl/tst-rwlock6.c: Use clock_gettime(2) rather than gettimeofday(2) and
> >   then converting to timespec in preparation for testing
> >   pthread_rwlock_clockrdclock and pthread_rwlock_clockwrlock.
> > 
> > * nptl/tst-rwlock9.c, nptl/tst-rwlock7.c: Likewise.
> 
> I am seeing this issue sporadically on i686-linux-gnu with 6/7 patches
> applied:
> 
> $ ./testrun.sh nptl/tst-rwlock7 --direct
> 0: got timedrdlock
> child: timedwrlock failed with ETIMEDOUT
> child: timedwrlock failed with EINVAL
> 1: got timedrdlock
> child: timedwrlock failed with ETIMEDOUT
> child: timedwrlock failed with EINVAL
> 2: got timedrdlock
> child: timedwrlock failed with ETIMEDOUT
> 2nd timedwrlock did not return EINVAL
> failure in round 2

Sorry, I hadn't spotted this part of your email until today. Luckily it's
clear what I got wrong and why I didn't see it on AArch64 and x86_64:

> > +  struct timespec ts_invalid;
> > +  (void) clock_gettime (CLOCK_REALTIME, &ts_invalid);
> > +  ts_invalid.tv_sec += 10;
> >    /* Note that the following operation makes ts invalid.  */
> > -  ts.tv_nsec += 1000000000;
> > +  ts_invalid.tv_nsec += 1000000000000;

I got so used to converting from µs to ns that I added three extra zeroes
unnecessarily here. It fits in a 64-bit long, but not a 32-bit one.

Thanks. I shall do more testing on 32-bit targets.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait
  2019-03-05 16:45   ` Adhemerval Zanella
@ 2019-05-04 20:22     ` Mike Crowe
  0 siblings, 0 replies; 33+ messages in thread
From: Mike Crowe @ 2019-05-04 20:22 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Tuesday 05 March 2019 at 13:45:13 -0300, Adhemerval Zanella wrote:
> 
> 
> On 27/02/2019 15:23, Mike Crowe wrote:
> > Add:
> > 
> >  int pthread_cond_clockwait (pthread_cond_t *cond,
> >                              pthread_mutex_t *mutex,
> >                              clockid_t clockid,
> >                              const struct timespec *abstime)
> > 
> > which behaves just like pthread_cond_timedwait except it always measures
> > abstime against the supplied clockid. Currently supports CLOCK_REALTIME and
> > CLOCK_MONOTONIC and returns EINVAL if any other clock is specified.
> > 
> > Includes feedback from many others. This function was originally
> > proposed[1] as pthread_cond_timedwaitonclock_np, but The Austin Group
> > preferred the new name.
> > 
> > * nptl/Makefile: Add tst-cond26 and tst-cond27
> > 
> > * nptl/Versions (GLIBC_2.30): Add pthread_cond_clockwait
> > 
> > * sysdeps/nptl/pthread.h: Likewise
> > 
> > * nptl/forward.c: Add __pthread_cond_clockwait (not sure if it should be
> >   __USE_GNU while it's still only proposed for POSIX.)
> > 
> > * nptl/forward.c: Likewise
> > 
> > * nptl/pthreadP.h: Likewise
> > 
> > * sysdeps/nptl/pthread-functions.h: Likewise.
> > 
> > * nptl/pthread_cond_wait.c (__pthread_cond_wait_common): Add clockid
> >   parameter and comment describing why we don't need to check its value.
> >   Use that value 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.
> > 
> > * 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.
> > 
> > * sysdeps/unix/sysv/linux/arm/libpthread.abilist,
> >  sysdeps/unix/sysv/linux/i386/libpthread.abilist,
> >  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Add
> >  pthread_cond_clockwait
> > 
> > * manual/threads.texi: Document pthread_cond_clockwait. The comment was
> >   provided by Carlos O'Donell.
> > 
> > [1] https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
> > ---
> >  manual/threads.texi                                  |  20 ++-
> >  nptl/Makefile                                        |   1 +-
> >  nptl/Versions                                        |   2 +-
> >  nptl/forward.c                                       |   5 +-
> >  nptl/nptl-init.c                                     |   1 +-
> >  nptl/pthreadP.h                                      |   4 +-
> >  nptl/pthread_cond_wait.c                             |  43 ++++-
> >  nptl/tst-cond11.c                                    |  30 ++-
> >  nptl/tst-cond26.c                                    |  91 ++++++++++-
> >  nptl/tst-cond27.c                                    | 113 ++++++++++++-
> >  sysdeps/nptl/pthread-functions.h                     |   4 +-
> >  sysdeps/nptl/pthread.h                               |  13 +-
> >  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist |   1 +-
> >  13 files changed, 314 insertions(+), 14 deletions(-)
> >  create mode 100644 nptl/tst-cond26.c
> >  create mode 100644 nptl/tst-cond27.c

[snip]

> > diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
> > index daa4e25..5deb54b 100644
> > --- a/nptl/pthread_cond_wait.c
> > +++ b/nptl/pthread_cond_wait.c

[snip]

> > @@ -664,10 +671,40 @@ __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);
> > +}
> > +
> 
> Ok.
> 
> > +/* 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;
> 
> The timespec check is used in different parts internally, I wonder
> if it would better to consolidate it somewhere.

Yes, I think some sort of timespec_valid function would make sense. Where
would be a good place to put it?

> > +
> > +  /* We only support CLOCK_REALTIME and CLOCK_MONOTONIC */
> > +  if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
> > +    return EINVAL;
> 
> Why not use lll_futex_supported_clockid here?

In fact, it should be futex_abstimed_supported_clockid.

> > +
> > +  /* If we do not support waiting using CLOCK_MONOTONIC, return an error.  */
> > +  if (clockid == CLOCK_MONOTONIC
> > +      && !futex_supports_exact_relative_timeouts ())
> > +    return EINVAL;
> 
> Why exactly do we need futex_supports_exact_relative_timeouts if Linux
> always set it to true?

I copied the use of it from the implementation of
pthread_condattr_setclock. It's described in sysdeps/nptl/futex-internal.h,
but there's no definition of it for anything other than Linux. It seems
quite possible that it has no use at all.

I can try removing it from pthread_condattr_setclock, but that would
probably be better as a separate change.

Mike.

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2019-05-04 20:23 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-27 18:23 [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Mike Crowe
2019-02-27 18:23 ` [PATCH 1/7] nptl: Add clockid parameter to futex timed wait calls Mike Crowe
2019-03-05 12:39   ` Adhemerval Zanella
2019-03-10  8:59     ` Mike Crowe
2019-03-11 11:50       ` Adhemerval Zanella
2019-02-27 18:23 ` [PATCH 2/7] nptl: Add POSIX-proposed sem_clockwait Mike Crowe
2019-02-27 18:35   ` Joseph Myers
2019-03-05 13:31   ` Adhemerval Zanella
2019-03-10 16:17     ` Mike Crowe
2019-03-19 17:07       ` Adhemerval Zanella
2019-03-14 14:09   ` Yann Droneaud
2019-03-14 14:39     ` Mike Crowe
2019-02-27 18:23 ` [PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait Mike Crowe
2019-03-05 16:45   ` Adhemerval Zanella
2019-05-04 20:22     ` Mike Crowe
2019-02-27 18:23 ` [PATCH 4/7] nptl: pthread_rwlock: Move timeout validation into _full functions Mike Crowe
2019-03-05 16:48   ` Adhemerval Zanella
2019-02-27 18:23 ` [PATCH 5/7] nptl/tst-rwlock14: Test pthread/rwlock_timedwrlock correctly Mike Crowe
2019-03-05 17:36   ` Adhemerval Zanella
2019-02-27 18:23 ` [PATCH 6/7] nptl/tst-rwlock: Use clock_gettime/timespec rather than gettimeofday/timeval Mike Crowe
2019-03-05 18:02   ` Adhemerval Zanella
2019-03-20 21:34     ` Mike Crowe
2019-03-14 14:44   ` Yann Droneaud
2019-02-27 18:23 ` [PATCH 7/7] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock Mike Crowe
2019-03-07 12:59   ` Adhemerval Zanella
2019-03-05 12:35 ` [PATCH 0/7] Implement proposed POSIX _clockwait variants of existing _timedwait functions Adhemerval Zanella
2019-03-06 21:15   ` Joseph Myers
2019-03-10  9:12     ` Mike Crowe
2019-03-11 23:13       ` Joseph Myers
2019-03-13 21:42   ` Mike Crowe
2019-03-14 11:30     ` Adhemerval Zanella
2019-03-15 13:25 ` Yann Droneaud
2019-03-15 13:36   ` Mike Crowe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).