[v3,5/6] nptl: Add POSIX-proposed pthread_rwlock_clockrdlock & pthread_rwlock_clockwrlock

Message ID 601652d60b3bb1f3e3157e71d9164fc6faf3f182.1558987219.git-series.mac@mcrowe.com
State Superseded
Headers

Commit Message

Mike Crowe May 27, 2019, 8:03 p.m. UTC
  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.

	* sysdeps/mach/hurd/i386/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
	(GLIBC_2.30): Likewise.

	* nptl/tst-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
	rwlock, a clockid and function name can be passed to the thread.
	(do_test_clock): Rename from do_test. 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. Use xpthread_create and xpthread_join.
	(do_test): Call do_test_clock to test each clockid in turn.

	* nptl/tst-rwlock7.c: Likewise.

	* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept
	thread_args structure so that the (now int) thread number, the
	clockid and the function name can be passed to the thread.
	(do_test_clock): Renamed from do_test. Pass the necessary
	thread_args when creating the reader and writer threads. Use
	xpthread_create and xpthread_join.
	(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.
---
 ChangeLog                                                       | 113 +++++++-
 manual/threads.texi                                             |  28 ++-
 nptl/Makefile                                                   |   2 +-
 nptl/Versions                                                   |   1 +-
 nptl/pthread_rwlock_clockrdlock.c                               |  29 ++-
 nptl/pthread_rwlock_clockwrlock.c                               |  29 ++-
 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                                              |   8 +-
 nptl/tst-rwlock14.c                                             |  12 +-
 nptl/tst-rwlock6.c                                              |  94 ++++--
 nptl/tst-rwlock7.c                                              |  83 +++--
 nptl/tst-rwlock9.c                                              | 102 ++++--
 sysdeps/nptl/pthread.h                                          |  14 +-
 sysdeps/unix/sysv/linux/aarch64/libpthread.abilist              |   2 +-
 sysdeps/unix/sysv/linux/alpha/libpthread.abilist                |   2 +-
 sysdeps/unix/sysv/linux/arm/libpthread.abilist                  |   2 +-
 sysdeps/unix/sysv/linux/csky/libpthread.abilist                 |   2 +-
 sysdeps/unix/sysv/linux/hppa/libpthread.abilist                 |   2 +-
 sysdeps/unix/sysv/linux/i386/libpthread.abilist                 |   2 +-
 sysdeps/unix/sysv/linux/ia64/libpthread.abilist                 |   2 +-
 sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist        |   2 +-
 sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist          |   2 +-
 sysdeps/unix/sysv/linux/microblaze/libpthread.abilist           |   2 +-
 sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist          |   2 +-
 sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist          |   2 +-
 sysdeps/unix/sysv/linux/nios2/libpthread.abilist                |   2 +-
 sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist    |   2 +-
 sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist |   2 +-
 sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist |   2 +-
 sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist           |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist         |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist         |   2 +-
 sysdeps/unix/sysv/linux/sh/libpthread.abilist                   |   2 +-
 sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist        |   2 +-
 sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist        |   2 +-
 sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist            |   2 +-
 sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist           |   2 +-
 41 files changed, 511 insertions(+), 100 deletions(-)
 create mode 100644 nptl/pthread_rwlock_clockrdlock.c
 create mode 100644 nptl/pthread_rwlock_clockwrlock.c
  

Comments

Adhemerval Zanella Netto June 7, 2019, 2:05 p.m. UTC | #1
On 27/05/2019 17:03, 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.
> 
> 	* sysdeps/mach/hurd/i386/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> 	(GLIBC_2.30): Likewise.
> 
> 	* nptl/tst-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
> 	rwlock, a clockid and function name can be passed to the thread.
> 	(do_test_clock): Rename from do_test. 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. Use xpthread_create and xpthread_join.
> 	(do_test): Call do_test_clock to test each clockid in turn.
> 
> 	* nptl/tst-rwlock7.c: Likewise.
> 
> 	* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept
> 	thread_args structure so that the (now int) thread number, the
> 	clockid and the function name can be passed to the thread.
> 	(do_test_clock): Renamed from do_test. Pass the necessary
> 	thread_args when creating the reader and writer threads. Use
> 	xpthread_create and xpthread_join.
> 	(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.
> ---
>  ChangeLog                                                       | 113 +++++++-
>  manual/threads.texi                                             |  28 ++-
>  nptl/Makefile                                                   |   2 +-
>  nptl/Versions                                                   |   1 +-
>  nptl/pthread_rwlock_clockrdlock.c                               |  29 ++-
>  nptl/pthread_rwlock_clockwrlock.c                               |  29 ++-
>  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                                              |   8 +-
>  nptl/tst-rwlock14.c                                             |  12 +-
>  nptl/tst-rwlock6.c                                              |  94 ++++--
>  nptl/tst-rwlock7.c                                              |  83 +++--
>  nptl/tst-rwlock9.c                                              | 102 ++++--
>  sysdeps/nptl/pthread.h                                          |  14 +-
>  sysdeps/unix/sysv/linux/aarch64/libpthread.abilist              |   2 +-
>  sysdeps/unix/sysv/linux/alpha/libpthread.abilist                |   2 +-
>  sysdeps/unix/sysv/linux/arm/libpthread.abilist                  |   2 +-
>  sysdeps/unix/sysv/linux/csky/libpthread.abilist                 |   2 +-
>  sysdeps/unix/sysv/linux/hppa/libpthread.abilist                 |   2 +-
>  sysdeps/unix/sysv/linux/i386/libpthread.abilist                 |   2 +-
>  sysdeps/unix/sysv/linux/ia64/libpthread.abilist                 |   2 +-
>  sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist        |   2 +-
>  sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist          |   2 +-
>  sysdeps/unix/sysv/linux/microblaze/libpthread.abilist           |   2 +-
>  sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist          |   2 +-
>  sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist          |   2 +-
>  sysdeps/unix/sysv/linux/nios2/libpthread.abilist                |   2 +-
>  sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist    |   2 +-
>  sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist |   2 +-
>  sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist |   2 +-
>  sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist           |   2 +-
>  sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist         |   2 +-
>  sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist         |   2 +-
>  sysdeps/unix/sysv/linux/sh/libpthread.abilist                   |   2 +-
>  sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist        |   2 +-
>  sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist        |   2 +-
>  sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist            |   2 +-
>  sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist           |   2 +-
>  41 files changed, 511 insertions(+), 100 deletions(-)
>  create mode 100644 nptl/pthread_rwlock_clockrdlock.c
>  create mode 100644 nptl/pthread_rwlock_clockwrlock.c
> 
> diff --git a/ChangeLog b/ChangeLog
> index 22a8bdc..66589f8 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,5 +1,118 @@
>  2019-05-27  Mike Crowe  <mac@mcrowe.com>
>  
> +	nptl: Add POSIX-proposed pthread_rwlock_clockrdlock &
> +	pthread_rwlock_clockwrlock 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.
> +
> +	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> +	(GLIBC_2.30): Likewise.
> +
> +	* nptl/tst-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
> +	rwlock, a clockid and function name can be passed to the thread.
> +	(do_test_clock): Rename from do_test. 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. Use xpthread_create and xpthread_join.
> +	(do_test): Call do_test_clock to test each clockid in turn.
> +
> +	* nptl/tst-rwlock7.c: Likewise.
> +
> +	* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept
> +	thread_args structure so that the (now int) thread number, the
> +	clockid and the function name can be passed to the thread.
> +	(do_test_clock): Renamed from do_test. Pass the necessary
> +	thread_args when creating the reader and writer threads. Use
> +	xpthread_create and xpthread_join.
> +	(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.
> +
> +2019-05-27  Mike Crowe  <mac@mcrowe.com>
> +
>  	nptl: pthread_rwlock: Move timeout validation into _full functions
>  
>  	* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full):
> 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

Ok.

> diff --git a/nptl/Makefile b/nptl/Makefile
> index 70a2139..d86513a 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 \

Ok.

> 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 {

Ok.

> diff --git a/nptl/pthread_rwlock_clockrdlock.c b/nptl/pthread_rwlock_clockrdlock.c
> new file mode 100644
> index 0000000..3c252f5
> --- /dev/null
> +++ b/nptl/pthread_rwlock_clockrdlock.c
> @@ -0,0 +1,29 @@
> +/* Implement pthread_rwlock_clockrdlock.
> +
> +   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);
> +}

Ok.

> diff --git a/nptl/pthread_rwlock_clockwrlock.c b/nptl/pthread_rwlock_clockwrlock.c
> new file mode 100644
> index 0000000..38ba693
> --- /dev/null
> +++ b/nptl/pthread_rwlock_clockwrlock.c
> @@ -0,0 +1,29 @@
> +/* Implement pthread_rwlock_clockwrlock.
> +
> +   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);
> +}

Ok.

As a side note, the '__pthread_rwlock_wrlock_full' implementation is currently
included on 6 implementations (pthread_rwlock_timedrdlock.c, 
pthread_rwlock_wrlock.c, pthread_rwlock_rdlock.c, pthread_rwlock_tryrdlock.c,
pthread_rwlock_unlock.c, and pthread_rwlock_timedwrlock.c).  I wonder if it
would be better to factored it out to be an internal symbol instead.

It would incur in a slight better code size, but we will need to check how
it changes the performance. I would not expect much, since it would be tail
call to an internal symbol.

> 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;

The futex_abstimed_wait already check for abstime and if its tv_sec < 0.  Would 
it be better to move the clock validity when it would be really used?

>  
> @@ -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

Ok.

> @@ -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;

As before.

>  
> @@ -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 56fb8a5..c5040c5 100644
> --- a/nptl/tst-abstime.c
> +++ b/nptl/tst-abstime.c
> @@ -38,6 +38,14 @@ th (void *arg)
>    TEST_COMPARE (pthread_mutex_timedlock (&m1, &t), ETIMEDOUT);
>    TEST_COMPARE (pthread_rwlock_timedrdlock (&rw1, &t), ETIMEDOUT);
>    TEST_COMPARE (pthread_rwlock_timedwrlock (&rw2, &t), ETIMEDOUT);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_REALTIME, &t),
> +                ETIMEDOUT);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&rw2, CLOCK_REALTIME, &t),
> +                ETIMEDOUT);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_MONOTONIC, &t),
> +                ETIMEDOUT);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&rw2, CLOCK_MONOTONIC, &t),
> +                ETIMEDOUT);
>    return NULL;
>  }
>  

Ok.

> diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c
> index af176b6..f4e1422 100644
> --- a/nptl/tst-rwlock14.c
> +++ b/nptl/tst-rwlock14.c
> @@ -64,19 +64,31 @@ do_test (void)
>    ts.tv_nsec = -1;
>  
>    TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
>    TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
>  
>    ts.tv_nsec = 1000000000;
>  
>    TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
>    TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
>  
>    ts.tv_nsec = (__typeof (ts.tv_nsec)) 0x100001000LL;
>    if ((__typeof (ts.tv_nsec)) 0x100001000LL != 0x100001000LL)
>      ts.tv_nsec = 2000000000;
>  
>    TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
>    TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
> +  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
>  
>    return 0;
>  }

Ok.

> diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
> index 5e73f50..d6020bf 100644
> --- a/nptl/tst-rwlock6.c
> +++ b/nptl/tst-rwlock6.c
> @@ -28,6 +28,11 @@
>  #include <support/xtime.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,
> @@ -35,43 +40,63 @@ 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;
> -  xclock_gettime (CLOCK_REALTIME, &ts_start);
> +  xclock_gettime (clockid_for_get, &ts_start);
>  
>    struct timespec ts_timeout = timespec_add (ts_start,
>                                               make_timespec (0, 300000000));
>  
> -  puts ("child calling timedrdlock");
> +  printf ("child calling %srdlock\n", fnname);

I think for debug logging it is better to enable only if test_verbose
(support/support_test_main.c:197) is set.

>  
> -  TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), ETIMEDOUT);
> +  if (clockid == CLOCK_USE_TIMEDLOCK)
> +    TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), ETIMEDOUT);
> +  else
> +    TEST_COMPARE (pthread_rwlock_clockrdlock (r, clockid, &ts_timeout),
> +                  ETIMEDOUT);
>  
> -  puts ("1st child timedrdlock done");
> +  printf ("1st child %srdlock done\n", fnname);

Ditto.

>  
>    TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout);
>  
> -  xclock_gettime (CLOCK_REALTIME, &ts_timeout);
> +  xclock_gettime (clockid_for_get, &ts_timeout);
>    ts_timeout.tv_sec += 10;
>    /* Note that the following operation makes ts invalid.  */
>    ts_timeout.tv_nsec += 1000000000;
>  
> -  TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), EINVAL);
> +  if (clockid == CLOCK_USE_TIMEDLOCK)
> +    TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), EINVAL);
> +  else
> +    TEST_COMPARE (pthread_rwlock_clockrdlock (r, clockid, &ts_timeout), EINVAL);
>  
> -  puts ("2nd child timedrdlock done");
> +  printf ("2nd child %srdlock done\n", fnname);
>  
>    return NULL;
>  }
>  

Ok.

>  
>  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)
>      {
> @@ -91,39 +116,46 @@ do_test (void)
>          FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);
>  
>        struct timespec ts;
> -      xclock_gettime (CLOCK_REALTIME, &ts);
> +      xclock_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)
> -        FAIL_EXIT1 ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e);
> +        FAIL_EXIT1 ("round %Zu: %swrlock failed (%d)\n",
> +                    cnt, fnname, e);
>  
> -      puts ("1st timedwrlock done");
> +      printf ("1st %swrlock done\n", fnname);

Ditto.

>  
> -      xclock_gettime (CLOCK_REALTIME, &ts);
> +      xclock_gettime (clockid_for_get, &ts);
>        ++ts.tv_sec;
> -      TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EDEADLK);
> +      if (clockid == CLOCK_USE_TIMEDLOCK)
> +        TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EDEADLK);
> +      else
> +        TEST_COMPARE (pthread_rwlock_clockrdlock (&r, clockid, &ts), EDEADLK);
>  
> -      puts ("1st timedrdlock done");
> +      printf ("1st %srdlock done\n", fnname);

Ditto.

>  
> -      xclock_gettime (CLOCK_REALTIME, &ts);
> +      xclock_gettime (clockid_for_get, &ts);
>        ++ts.tv_sec;
> -      TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EDEADLK);
> +      if (clockid == CLOCK_USE_TIMEDLOCK)
> +        TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EDEADLK);
> +      else
> +        TEST_COMPARE (pthread_rwlock_clockwrlock (&r, clockid, &ts), EDEADLK);
>  
> -      puts ("2nd timedwrlock done");
> +      printf ("2nd %swrlock done\n", fnname);

Ditto.

>  
> -      pthread_t th;
> -      if (pthread_create (&th, NULL, tf, &r) != 0)
> -        FAIL_EXIT1 ("round %Zu: create failed\n", cnt);
> +      struct thread_args args;
> +      args.rwlock = &r;
> +      args.clockid = clockid;
> +      args.fnname = fnname;
> +      pthread_t th = xpthread_create (NULL, tf, &args);
>  
>        puts ("started thread");
>  
> -      void *status;
> -      if (pthread_join (th, &status) != 0)
> -        FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
> -      if (status != NULL)
> -        FAIL_EXIT1 ("failure in round %Zu\n", cnt);
> +      (void) xpthread_join (th);
>  
>        puts ("joined thread");
>  
> @@ -134,4 +166,12 @@ 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;
> +}
> +
>  #include <support/test-driver.c>

Ok.

> diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
> index df50f0a..1c31572 100644
> --- a/nptl/tst-rwlock7.c
> +++ b/nptl/tst-rwlock7.c
> @@ -28,6 +28,11 @@
>  #include <support/xtime.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,
> @@ -35,40 +40,60 @@ 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;
> -  xclock_gettime (CLOCK_REALTIME, &ts_start);
> +  xclock_gettime (clockid_for_get, &ts_start);
>    const struct timespec ts_timeout = timespec_add (ts_start,
>                                                     make_timespec (0, 300000000));
>  
> -  TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
> -  puts ("child: timedwrlock failed with ETIMEDOUT");
> +  if (clockid == CLOCK_USE_TIMEDLOCK)
> +    TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
> +  else
> +    TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_timeout),
> +                  ETIMEDOUT);
> +  printf ("child: %swrlock failed with ETIMEDOUT", fnname);
>  
> -  TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout);
> +  TEST_TIMESPEC_NOW_OR_AFTER (clockid_for_get, ts_timeout);
>  
>    struct timespec ts_invalid;
> -  xclock_gettime (CLOCK_REALTIME, &ts_invalid);
> +  xclock_gettime (clockid_for_get, &ts_invalid);
>    ts_invalid.tv_sec += 10;
>    /* Note that the following operation makes ts invalid.  */
>    ts_invalid.tv_nsec += 1000000000;
>  
> -  TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);
> +  if (clockid == CLOCK_USE_TIMEDLOCK)
> +    TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);
> +  else
> +    TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_invalid), EINVAL);
>  
> -  puts ("child: timedwrlock failed with EINVAL");
> +  printf ("child: %swrlock failed with EINVAL", fnname);
>  
>    return NULL;
>  }
>  
>  

Ok.

>  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)
>      {
> @@ -88,23 +113,27 @@ do_test (void)
>          FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);
>  
>        struct timespec ts;
> -      xclock_gettime (CLOCK_REALTIME, &ts);
> +      xclock_gettime (clockid_for_get, &ts);
>  
>        ++ts.tv_sec;
>  
>        /* Get a read lock.  */
> -      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
> -        FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt);
> -
> -      printf ("%zu: got timedrdlock\n", cnt);
> -
> -      pthread_t th;
> -      if (pthread_create (&th, NULL, tf, &r) != 0)
> -        FAIL_EXIT1 ("round %Zu: create failed\n", cnt);
> -
> -      void *status;
> -      if (pthread_join (th, &status) != 0)
> -        FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
> +      if (clockid == CLOCK_USE_TIMEDLOCK) {
> +        if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
> +          FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt);
> +      } else {
> +        if (pthread_rwlock_clockrdlock (&r, clockid, &ts) != 0)
> +          FAIL_EXIT1 ("round %Zu: rwlock_%srdlock failed\n", cnt, fnname);
> +      }
> +
> +      printf ("%zu: got %srdlock\n", cnt, fnname);

Ditto.

> +
> +      struct thread_args args;
> +      args.rwlock = &r;
> +      args.clockid = clockid;
> +      args.fnname = fnname;
> +      pthread_t th = xpthread_create(NULL, tf, &args);
> +      void *status = xpthread_join (th);
>        if (status != NULL)
>          FAIL_EXIT1 ("failure in round %Zu\n", cnt);

Ok.

>  
> @@ -115,4 +144,14 @@ 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;
> +}
> +
>  #include <support/test-driver.c>

Ok.

> diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
> index e772247..e975554 100644
> --- a/nptl/tst-rwlock9.c
> +++ b/nptl/tst-rwlock9.c
> @@ -26,6 +26,7 @@
>  #include <sys/time.h>
>  #include <support/check.h>
>  #include <support/timespec.h>
> +#include <support/xthread.h>
>  
>  
>  #define NWRITERS 15
> @@ -40,12 +41,30 @@ static const struct timespec delay = { 0, 1000000 };
>  # 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 clockid_t clockid_for_get =
> +    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
> +  const char *fnname = args->fnname;
> +
>    struct timespec ts;
>    int n;
>  
> @@ -54,27 +73,29 @@ writer_thread (void *nr)
>        int e;
>        do
>  	{
> -	  xclock_gettime (CLOCK_REALTIME, &ts);
> +	  xclock_gettime (clockid_for_get, &ts);
>  
>            ts = timespec_add (ts, timeout);
>            ts = timespec_add (ts, timeout);
>  
> -	  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)
> -            FAIL_EXIT1 ("timedwrlock failed");
> +            FAIL_EXIT1 ("%swrlock failed", fnname);
>  	}
>        while (e == ETIMEDOUT);
>  
> -      printf ("writer thread %ld succeeded\n", (long int) nr);
> +      printf ("writer thread %d succeeded\n", nr);
>  
>        nanosleep (&delay, NULL);
>  
>        if (pthread_rwlock_unlock (&lock) != 0)
>          FAIL_EXIT1 ("unlock for writer failed");
>  
> -      printf ("writer thread %ld released\n", (long int) nr);
> +      printf ("writer thread %d released\n", nr);
>      }
>  
>    return NULL;

Ok.

> @@ -82,8 +103,15 @@ 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 clockid_t clockid_for_get =
> +    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
> +  const char *fnname = args->fnname;
> +
>    struct timespec ts;
>    int n;
>  
> @@ -92,26 +120,29 @@ reader_thread (void *nr)
>        int e;
>        do
>  	{
> -	  xclock_gettime (CLOCK_REALTIME, &ts);
> +	  xclock_gettime (clockid_for_get, &ts);
>  
>            ts = timespec_add (ts, timeout);
>  
> -	  printf ("reader thread %ld tries again\n", (long int) nr);
> +	  printf ("reader thread %d tries again\n", nr);
>  
> -	  e = pthread_rwlock_timedrdlock (&lock, &ts);
> +	  if (clockid == CLOCK_USE_TIMEDLOCK)
> +	    e = pthread_rwlock_timedrdlock (&lock, &ts);
> +          else
> +	    e = pthread_rwlock_clockrdlock (&lock, clockid, &ts);
>  	  if (e != 0 && e != ETIMEDOUT)
> -            FAIL_EXIT1 ("timedrdlock failed");
> +            FAIL_EXIT1 ("%srdlock failed", fnname);
>  	}
>        while (e == ETIMEDOUT);
>  
> -      printf ("reader thread %ld succeeded\n", (long int) nr);
> +      printf ("reader thread %d succeeded\n", nr);
>  
>        nanosleep (&delay, NULL);
>  
>        if (pthread_rwlock_unlock (&lock) != 0)
>          FAIL_EXIT1 ("unlock for reader failed");
>  
> -      printf ("reader thread %ld released\n", (long int) nr);
> +      printf ("reader thread %d released\n", nr);
>      }
>  
>    return NULL;

Ok.

> @@ -119,12 +150,11 @@ 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];
>    int n;
> -  void *res;
>    pthread_rwlockattr_t a;
>  
>    if (pthread_rwlockattr_init (&a) != 0)
> @@ -142,23 +172,37 @@ do_test (void)
>    /* Make sure we see all message, even those on stdout.  */
>    setvbuf (stdout, NULL, _IONBF, 0);
>  
> -  for (n = 0; n < NWRITERS; ++n)
> -    if (pthread_create (&thwr[n], NULL, writer_thread,
> -			(void *) (long int) n) != 0)
> -      FAIL_EXIT1 ("writer create failed");
> -
> -  for (n = 0; n < NREADERS; ++n)
> -    if (pthread_create (&thrd[n], NULL, reader_thread,
> -			(void *) (long int) n) != 0)
> -      FAIL_EXIT1 ("reader create failed");
> +  struct thread_args wargs[NWRITERS];
> +  for (n = 0; n < NWRITERS; ++n) {
> +    wargs[n].nr = n;
> +    wargs[n].clockid = clockid;
> +    wargs[n].fnname = fnname;
> +    thwr[n] = xpthread_create (NULL, writer_thread, &wargs[n]);
> +  }
> +
> +  struct thread_args rargs[NREADERS];
> +  for (n = 0; n < NREADERS; ++n) {
> +    rargs[n].nr = n;
> +    rargs[n].clockid = clockid;
> +    rargs[n].fnname = fnname;
> +    thrd[n] = xpthread_create (NULL, reader_thread, &rargs[n]);
> +  }
>  
>    /* Wait for all the threads.  */
>    for (n = 0; n < NWRITERS; ++n)
> -    if (pthread_join (thwr[n], &res) != 0)
> -      FAIL_EXIT1 ("writer join failed");
> +    xpthread_join (thwr[n]);
>    for (n = 0; n < NREADERS; ++n)
> -    if (pthread_join (thrd[n], &res) != 0)
> -      FAIL_EXIT1 ("reader join failed");
> +    xpthread_join (thrd[n]);
> +
> +  return 0;
> +}
> +

Ok.

> +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;
>  }

Ok.

> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index f000b1e..e78003e 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -909,6 +909,13 @@ extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
>  				       __abstime) __THROWNL __nonnull ((1, 2));
>  # endif
>  
> +# ifdef __USE_GNU
> +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.  */
>  extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock)
>       __THROWNL __nonnull ((1));

Ok.

> @@ -924,6 +931,13 @@ extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
>  				       __abstime) __THROWNL __nonnull ((1, 2));
>  # endif
>  
> +# ifdef __USE_GNU
> +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.  */
>  extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock)
>       __THROWNL __nonnull ((1));

Ok.

> diff --git a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
> index 5af4b8a..9f65baf 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
> @@ -244,4 +244,6 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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
> diff --git a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
> index a00adfb..0709855 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
> @@ -228,6 +228,8 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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.3.2 pthread_cond_broadcast F
>  GLIBC_2.3.2 pthread_cond_destroy F
> diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
> index 4aeee7b..a2be572 100644
> --- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
> @@ -28,6 +28,8 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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 _IO_flockfile F
>  GLIBC_2.4 _IO_ftrylockfile F
> diff --git a/sysdeps/unix/sysv/linux/csky/libpthread.abilist b/sysdeps/unix/sysv/linux/csky/libpthread.abilist
> index 2c08b76..c3a1834 100644
> --- a/sysdeps/unix/sysv/linux/csky/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libpthread.abilist
> @@ -234,4 +234,6 @@ GLIBC_2.29 wait F
>  GLIBC_2.29 waitpid F
>  GLIBC_2.29 write 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
> diff --git a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
> index dc0d4ad..2a00ebc 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/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
> diff --git a/sysdeps/unix/sysv/linux/i386/libpthread.abilist b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
> index 1830e40..4479947 100644
> --- a/sysdeps/unix/sysv/linux/i386/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
> @@ -254,6 +254,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
> diff --git a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
> index 0811d73..40a1faf 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
> @@ -248,6 +248,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
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> index 4aeee7b..a2be572 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> @@ -28,6 +28,8 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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 _IO_flockfile F
>  GLIBC_2.4 _IO_ftrylockfile F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> index 1830e40..4479947 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> @@ -254,6 +254,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
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
> index f2be6b4..254b708 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
> @@ -244,4 +244,6 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
> index 41527fe..29ffdd1 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
> @@ -256,6 +256,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
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
> index 41527fe..29ffdd1 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
> @@ -256,6 +256,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
> diff --git a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
> index 04fc3a6..3fae328 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
> @@ -242,4 +242,6 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
> index ebdab1a..a90010d 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
> @@ -256,6 +256,8 @@ GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
>  GLIBC_2.3.4 siglongjmp 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
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
> index 8a1fb34..339eab8 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
> @@ -247,6 +247,8 @@ GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
>  GLIBC_2.3.4 siglongjmp 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
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
> index 5af4b8a..9f65baf 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
> @@ -244,4 +244,6 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
> index a1c8c2e..83082fb 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
> @@ -236,4 +236,6 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
> index 0feb3cf..54e937b 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
> @@ -256,6 +256,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
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
> index cc4f160..87f978b 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
> @@ -248,6 +248,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
> diff --git a/sysdeps/unix/sysv/linux/sh/libpthread.abilist b/sysdeps/unix/sysv/linux/sh/libpthread.abilist
> index dc0d4ad..2a00ebc 100644
> --- a/sysdeps/unix/sysv/linux/sh/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/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
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
> index ed0574a..bc29a66 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
> @@ -256,6 +256,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
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
> index 0811d73..40a1faf 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
> @@ -248,6 +248,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
> 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
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> index 5d02b03..92cd2f4 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> @@ -244,4 +244,6 @@ GLIBC_2.28 tss_delete F
>  GLIBC_2.28 tss_get F
>  GLIBC_2.28 tss_set 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
> 

Ok (all affected ABI seems to be taking in consideration).
  
Mike Crowe June 7, 2019, 5:14 p.m. UTC | #2
[snip review comments that I will address]

On Friday 07 June 2019 at 11:05:44 -0300, Adhemerval Zanella wrote:
> > diff --git a/nptl/pthread_rwlock_clockwrlock.c b/nptl/pthread_rwlock_clockwrlock.c
> > new file mode 100644
> > index 0000000..38ba693
> > --- /dev/null
> > +++ b/nptl/pthread_rwlock_clockwrlock.c
> > @@ -0,0 +1,29 @@
> > +/* Implement pthread_rwlock_clockwrlock.
> > +
> > +   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);
> > +}
> 
> Ok.
> 
> As a side note, the '__pthread_rwlock_wrlock_full' implementation is currently
> included on 6 implementations (pthread_rwlock_timedrdlock.c, 
> pthread_rwlock_wrlock.c, pthread_rwlock_rdlock.c, pthread_rwlock_tryrdlock.c,
> pthread_rwlock_unlock.c, and pthread_rwlock_timedwrlock.c).  I wonder if it
> would be better to factored it out to be an internal symbol instead.
> 
> It would incur in a slight better code size, but we will need to check how
> it changes the performance. I would not expect much, since it would be tail
> call to an internal symbol.

For x86_64, it looks like pthread_rwlock_timedrdlock is about 700 bytes, so
we could gain approximately 3.5K by doing that.

I'm not sure that I'm knowledgeable enough in benchmarking real-world
scenarios to be able to come up with a test I'd trust, and I can come up
with theoretical arguments in both directions.

> > 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;
> 
> The futex_abstimed_wait already check for abstime and if its tv_sec < 0.  Would 
> it be better to move the clock validity when it would be really used?

I think that it's better to consistently return an error if an invalid
clock is supplied, even if it is not necessary to use the timeout. Doing
otherwise risks bugs (in code using glibc) that aren't found until much
later.

Mike.
  
Adhemerval Zanella Netto June 11, 2019, 12:19 p.m. UTC | #3
On 07/06/2019 14:14, Mike Crowe wrote:
> [snip review comments that I will address]
> 
> On Friday 07 June 2019 at 11:05:44 -0300, Adhemerval Zanella wrote:
>>> diff --git a/nptl/pthread_rwlock_clockwrlock.c b/nptl/pthread_rwlock_clockwrlock.c
>>> new file mode 100644
>>> index 0000000..38ba693
>>> --- /dev/null
>>> +++ b/nptl/pthread_rwlock_clockwrlock.c
>>> @@ -0,0 +1,29 @@
>>> +/* Implement pthread_rwlock_clockwrlock.
>>> +
>>> +   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);
>>> +}
>>
>> Ok.
>>
>> As a side note, the '__pthread_rwlock_wrlock_full' implementation is currently
>> included on 6 implementations (pthread_rwlock_timedrdlock.c, 
>> pthread_rwlock_wrlock.c, pthread_rwlock_rdlock.c, pthread_rwlock_tryrdlock.c,
>> pthread_rwlock_unlock.c, and pthread_rwlock_timedwrlock.c).  I wonder if it
>> would be better to factored it out to be an internal symbol instead.
>>
>> It would incur in a slight better code size, but we will need to check how
>> it changes the performance. I would not expect much, since it would be tail
>> call to an internal symbol.
> 
> For x86_64, it looks like pthread_rwlock_timedrdlock is about 700 bytes, so
> we could gain approximately 3.5K by doing that.
> 
> I'm not sure that I'm knowledgeable enough in benchmarking real-world
> scenarios to be able to come up with a test I'd trust, and I can come up
> with theoretical arguments in both directions.

I think 3.5k is noticeable and if performance-wise it does not yield any
drawback I think it would be good refactor. I don't have neither performance
workload to validate this change, but I presume on most architecture it would
be a tail call which would just an extra jump without the need to handle 
potential extra code segments.

I am ccing Torvalds, who rewrote the pthread cond code. Torvalds, do you recall
why you set the code to be inline instead of create an internal common symbol? 
Do you think refactoring to share the code would yield any performance
regressions?

> 
>>> 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;
>>
>> The futex_abstimed_wait already check for abstime and if its tv_sec < 0.  Would 
>> it be better to move the clock validity when it would be really used?
> 
> I think that it's better to consistently return an error if an invalid
> clock is supplied, even if it is not necessary to use the timeout. Doing
> otherwise risks bugs (in code using glibc) that aren't found until much
> later.

Right, but I am thinking that if we eventually refactor to make it a common
internal symbol compiler might not be able infer abstime is always null (even
if is called with a NULL value for abstime). I will check again if current
organization with all patchset applied is ok.
  
Torvald Riegel June 11, 2019, 12:33 p.m. UTC | #4
On Tue, 2019-06-11 at 09:19 -0300, Adhemerval Zanella wrote:
> 
> On 07/06/2019 14:14, Mike Crowe wrote:
> > [snip review comments that I will address]
> > 
> > On Friday 07 June 2019 at 11:05:44 -0300, Adhemerval Zanella wrote:
> > > > diff --git a/nptl/pthread_rwlock_clockwrlock.c b/nptl/pthread_rwlock_clockwrlock.c
> > > > new file mode 100644
> > > > index 0000000..38ba693
> > > > --- /dev/null
> > > > +++ b/nptl/pthread_rwlock_clockwrlock.c
> > > > @@ -0,0 +1,29 @@
> > > > +/* Implement pthread_rwlock_clockwrlock.
> > > > +
> > > > +   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);
> > > > +}
> > > 
> > > Ok.
> > > 
> > > As a side note, the '__pthread_rwlock_wrlock_full' implementation is currently
> > > included on 6 implementations (pthread_rwlock_timedrdlock.c, 
> > > pthread_rwlock_wrlock.c, pthread_rwlock_rdlock.c, pthread_rwlock_tryrdlock.c,
> > > pthread_rwlock_unlock.c, and pthread_rwlock_timedwrlock.c).  I wonder if it
> > > would be better to factored it out to be an internal symbol instead.
> > > 
> > > It would incur in a slight better code size, but we will need to check how
> > > it changes the performance. I would not expect much, since it would be tail
> > > call to an internal symbol.
> > 
> > For x86_64, it looks like pthread_rwlock_timedrdlock is about 700 bytes, so
> > we could gain approximately 3.5K by doing that.
> > 
> > I'm not sure that I'm knowledgeable enough in benchmarking real-world
> > scenarios to be able to come up with a test I'd trust, and I can come up
> > with theoretical arguments in both directions.
> 
> I think 3.5k is noticeable and if performance-wise it does not yield any
> drawback I think it would be good refactor. I don't have neither performance
> workload to validate this change, but I presume on most architecture it would
> be a tail call which would just an extra jump without the need to handle 
> potential extra code segments.
> 
> I am ccing Torvalds, who rewrote the pthread cond code. Torvalds, do you recall
> why you set the code to be inline instead of create an internal common symbol?

I wasn't aware that there was that much concern about code size, and I
wanted to give as much optimization opportunity to the compiler as
possible.  There is not that much information (like abstime==NULL) that is
passed in into the full algorithm, so maybe it doesn't matter as much in
the end.

> Do you think refactoring to share the code would yield any performance
> regressions?

Not sure.  It might only be noticable matter on the fast paths, so maybe
check those (eg, single-threaded pthread_rwlock_tryrdlock).
  

Patch

diff --git a/ChangeLog b/ChangeLog
index 22a8bdc..66589f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,118 @@ 
 2019-05-27  Mike Crowe  <mac@mcrowe.com>
 
+	nptl: Add POSIX-proposed pthread_rwlock_clockrdlock &
+	pthread_rwlock_clockwrlock 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.
+
+	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
+	(GLIBC_2.30): Likewise.
+
+	* nptl/tst-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
+	rwlock, a clockid and function name can be passed to the thread.
+	(do_test_clock): Rename from do_test. 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. Use xpthread_create and xpthread_join.
+	(do_test): Call do_test_clock to test each clockid in turn.
+
+	* nptl/tst-rwlock7.c: Likewise.
+
+	* nptl/tst-rwlock9.c (writer_thread, reader_thread): Accept
+	thread_args structure so that the (now int) thread number, the
+	clockid and the function name can be passed to the thread.
+	(do_test_clock): Renamed from do_test. Pass the necessary
+	thread_args when creating the reader and writer threads. Use
+	xpthread_create and xpthread_join.
+	(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.
+
+2019-05-27  Mike Crowe  <mac@mcrowe.com>
+
 	nptl: pthread_rwlock: Move timeout validation into _full functions
 
 	* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full):
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 70a2139..d86513a 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..3c252f5
--- /dev/null
+++ b/nptl/pthread_rwlock_clockrdlock.c
@@ -0,0 +1,29 @@ 
+/* Implement pthread_rwlock_clockrdlock.
+
+   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..38ba693
--- /dev/null
+++ b/nptl/pthread_rwlock_clockwrlock.c
@@ -0,0 +1,29 @@ 
+/* Implement pthread_rwlock_clockwrlock.
+
+   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 56fb8a5..c5040c5 100644
--- a/nptl/tst-abstime.c
+++ b/nptl/tst-abstime.c
@@ -38,6 +38,14 @@  th (void *arg)
   TEST_COMPARE (pthread_mutex_timedlock (&m1, &t), ETIMEDOUT);
   TEST_COMPARE (pthread_rwlock_timedrdlock (&rw1, &t), ETIMEDOUT);
   TEST_COMPARE (pthread_rwlock_timedwrlock (&rw2, &t), ETIMEDOUT);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_REALTIME, &t),
+                ETIMEDOUT);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&rw2, CLOCK_REALTIME, &t),
+                ETIMEDOUT);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&rw1, CLOCK_MONOTONIC, &t),
+                ETIMEDOUT);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&rw2, CLOCK_MONOTONIC, &t),
+                ETIMEDOUT);
   return NULL;
 }
 
diff --git a/nptl/tst-rwlock14.c b/nptl/tst-rwlock14.c
index af176b6..f4e1422 100644
--- a/nptl/tst-rwlock14.c
+++ b/nptl/tst-rwlock14.c
@@ -64,19 +64,31 @@  do_test (void)
   ts.tv_nsec = -1;
 
   TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
   TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
 
   ts.tv_nsec = 1000000000;
 
   TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
   TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
 
   ts.tv_nsec = (__typeof (ts.tv_nsec)) 0x100001000LL;
   if ((__typeof (ts.tv_nsec)) 0x100001000LL != 0x100001000LL)
     ts.tv_nsec = 2000000000;
 
   TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_REALTIME, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockrdlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
   TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_REALTIME, &ts), EINVAL);
+  TEST_COMPARE (pthread_rwlock_clockwrlock (&r, CLOCK_MONOTONIC, &ts), EINVAL);
 
   return 0;
 }
diff --git a/nptl/tst-rwlock6.c b/nptl/tst-rwlock6.c
index 5e73f50..d6020bf 100644
--- a/nptl/tst-rwlock6.c
+++ b/nptl/tst-rwlock6.c
@@ -28,6 +28,11 @@ 
 #include <support/xtime.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,
@@ -35,43 +40,63 @@  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;
-  xclock_gettime (CLOCK_REALTIME, &ts_start);
+  xclock_gettime (clockid_for_get, &ts_start);
 
   struct timespec ts_timeout = timespec_add (ts_start,
                                              make_timespec (0, 300000000));
 
-  puts ("child calling timedrdlock");
+  printf ("child calling %srdlock\n", fnname);
 
-  TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), ETIMEDOUT);
+  if (clockid == CLOCK_USE_TIMEDLOCK)
+    TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), ETIMEDOUT);
+  else
+    TEST_COMPARE (pthread_rwlock_clockrdlock (r, clockid, &ts_timeout),
+                  ETIMEDOUT);
 
-  puts ("1st child timedrdlock done");
+  printf ("1st child %srdlock done\n", fnname);
 
   TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout);
 
-  xclock_gettime (CLOCK_REALTIME, &ts_timeout);
+  xclock_gettime (clockid_for_get, &ts_timeout);
   ts_timeout.tv_sec += 10;
   /* Note that the following operation makes ts invalid.  */
   ts_timeout.tv_nsec += 1000000000;
 
-  TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), EINVAL);
+  if (clockid == CLOCK_USE_TIMEDLOCK)
+    TEST_COMPARE (pthread_rwlock_timedrdlock (r, &ts_timeout), EINVAL);
+  else
+    TEST_COMPARE (pthread_rwlock_clockrdlock (r, clockid, &ts_timeout), EINVAL);
 
-  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)
     {
@@ -91,39 +116,46 @@  do_test (void)
         FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);
 
       struct timespec ts;
-      xclock_gettime (CLOCK_REALTIME, &ts);
+      xclock_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)
-        FAIL_EXIT1 ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e);
+        FAIL_EXIT1 ("round %Zu: %swrlock failed (%d)\n",
+                    cnt, fnname, e);
 
-      puts ("1st timedwrlock done");
+      printf ("1st %swrlock done\n", fnname);
 
-      xclock_gettime (CLOCK_REALTIME, &ts);
+      xclock_gettime (clockid_for_get, &ts);
       ++ts.tv_sec;
-      TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EDEADLK);
+      if (clockid == CLOCK_USE_TIMEDLOCK)
+        TEST_COMPARE (pthread_rwlock_timedrdlock (&r, &ts), EDEADLK);
+      else
+        TEST_COMPARE (pthread_rwlock_clockrdlock (&r, clockid, &ts), EDEADLK);
 
-      puts ("1st timedrdlock done");
+      printf ("1st %srdlock done\n", fnname);
 
-      xclock_gettime (CLOCK_REALTIME, &ts);
+      xclock_gettime (clockid_for_get, &ts);
       ++ts.tv_sec;
-      TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EDEADLK);
+      if (clockid == CLOCK_USE_TIMEDLOCK)
+        TEST_COMPARE (pthread_rwlock_timedwrlock (&r, &ts), EDEADLK);
+      else
+        TEST_COMPARE (pthread_rwlock_clockwrlock (&r, clockid, &ts), EDEADLK);
 
-      puts ("2nd timedwrlock done");
+      printf ("2nd %swrlock done\n", fnname);
 
-      pthread_t th;
-      if (pthread_create (&th, NULL, tf, &r) != 0)
-        FAIL_EXIT1 ("round %Zu: create failed\n", cnt);
+      struct thread_args args;
+      args.rwlock = &r;
+      args.clockid = clockid;
+      args.fnname = fnname;
+      pthread_t th = xpthread_create (NULL, tf, &args);
 
       puts ("started thread");
 
-      void *status;
-      if (pthread_join (th, &status) != 0)
-        FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
-      if (status != NULL)
-        FAIL_EXIT1 ("failure in round %Zu\n", cnt);
+      (void) xpthread_join (th);
 
       puts ("joined thread");
 
@@ -134,4 +166,12 @@  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;
+}
+
 #include <support/test-driver.c>
diff --git a/nptl/tst-rwlock7.c b/nptl/tst-rwlock7.c
index df50f0a..1c31572 100644
--- a/nptl/tst-rwlock7.c
+++ b/nptl/tst-rwlock7.c
@@ -28,6 +28,11 @@ 
 #include <support/xtime.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,
@@ -35,40 +40,60 @@  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;
-  xclock_gettime (CLOCK_REALTIME, &ts_start);
+  xclock_gettime (clockid_for_get, &ts_start);
   const struct timespec ts_timeout = timespec_add (ts_start,
                                                    make_timespec (0, 300000000));
 
-  TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
-  puts ("child: timedwrlock failed with ETIMEDOUT");
+  if (clockid == CLOCK_USE_TIMEDLOCK)
+    TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_timeout), ETIMEDOUT);
+  else
+    TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_timeout),
+                  ETIMEDOUT);
+  printf ("child: %swrlock failed with ETIMEDOUT", fnname);
 
-  TEST_TIMESPEC_NOW_OR_AFTER (CLOCK_REALTIME, ts_timeout);
+  TEST_TIMESPEC_NOW_OR_AFTER (clockid_for_get, ts_timeout);
 
   struct timespec ts_invalid;
-  xclock_gettime (CLOCK_REALTIME, &ts_invalid);
+  xclock_gettime (clockid_for_get, &ts_invalid);
   ts_invalid.tv_sec += 10;
   /* Note that the following operation makes ts invalid.  */
   ts_invalid.tv_nsec += 1000000000;
 
-  TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);
+  if (clockid == CLOCK_USE_TIMEDLOCK)
+    TEST_COMPARE (pthread_rwlock_timedwrlock (r, &ts_invalid), EINVAL);
+  else
+    TEST_COMPARE (pthread_rwlock_clockwrlock (r, clockid, &ts_invalid), EINVAL);
 
-  puts ("child: timedwrlock failed with EINVAL");
+  printf ("child: %swrlock failed with EINVAL", 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)
     {
@@ -88,23 +113,27 @@  do_test (void)
         FAIL_EXIT1 ("round %Zu: rwlockattr_destroy failed\n", cnt);
 
       struct timespec ts;
-      xclock_gettime (CLOCK_REALTIME, &ts);
+      xclock_gettime (clockid_for_get, &ts);
 
       ++ts.tv_sec;
 
       /* Get a read lock.  */
-      if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
-        FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt);
-
-      printf ("%zu: got timedrdlock\n", cnt);
-
-      pthread_t th;
-      if (pthread_create (&th, NULL, tf, &r) != 0)
-        FAIL_EXIT1 ("round %Zu: create failed\n", cnt);
-
-      void *status;
-      if (pthread_join (th, &status) != 0)
-        FAIL_EXIT1 ("round %Zu: join failed\n", cnt);
+      if (clockid == CLOCK_USE_TIMEDLOCK) {
+        if (pthread_rwlock_timedrdlock (&r, &ts) != 0)
+          FAIL_EXIT1 ("round %Zu: rwlock_timedrdlock failed\n", cnt);
+      } else {
+        if (pthread_rwlock_clockrdlock (&r, clockid, &ts) != 0)
+          FAIL_EXIT1 ("round %Zu: rwlock_%srdlock failed\n", cnt, fnname);
+      }
+
+      printf ("%zu: got %srdlock\n", cnt, fnname);
+
+      struct thread_args args;
+      args.rwlock = &r;
+      args.clockid = clockid;
+      args.fnname = fnname;
+      pthread_t th = xpthread_create(NULL, tf, &args);
+      void *status = xpthread_join (th);
       if (status != NULL)
         FAIL_EXIT1 ("failure in round %Zu\n", cnt);
 
@@ -115,4 +144,14 @@  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;
+}
+
 #include <support/test-driver.c>
diff --git a/nptl/tst-rwlock9.c b/nptl/tst-rwlock9.c
index e772247..e975554 100644
--- a/nptl/tst-rwlock9.c
+++ b/nptl/tst-rwlock9.c
@@ -26,6 +26,7 @@ 
 #include <sys/time.h>
 #include <support/check.h>
 #include <support/timespec.h>
+#include <support/xthread.h>
 
 
 #define NWRITERS 15
@@ -40,12 +41,30 @@  static const struct timespec delay = { 0, 1000000 };
 # 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 clockid_t clockid_for_get =
+    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
+  const char *fnname = args->fnname;
+
   struct timespec ts;
   int n;
 
@@ -54,27 +73,29 @@  writer_thread (void *nr)
       int e;
       do
 	{
-	  xclock_gettime (CLOCK_REALTIME, &ts);
+	  xclock_gettime (clockid_for_get, &ts);
 
           ts = timespec_add (ts, timeout);
           ts = timespec_add (ts, timeout);
 
-	  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)
-            FAIL_EXIT1 ("timedwrlock failed");
+            FAIL_EXIT1 ("%swrlock failed", fnname);
 	}
       while (e == ETIMEDOUT);
 
-      printf ("writer thread %ld succeeded\n", (long int) nr);
+      printf ("writer thread %d succeeded\n", nr);
 
       nanosleep (&delay, NULL);
 
       if (pthread_rwlock_unlock (&lock) != 0)
         FAIL_EXIT1 ("unlock for writer failed");
 
-      printf ("writer thread %ld released\n", (long int) nr);
+      printf ("writer thread %d released\n", nr);
     }
 
   return NULL;
@@ -82,8 +103,15 @@  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 clockid_t clockid_for_get =
+    (clockid == CLOCK_USE_TIMEDLOCK) ? CLOCK_REALTIME : clockid;
+  const char *fnname = args->fnname;
+
   struct timespec ts;
   int n;
 
@@ -92,26 +120,29 @@  reader_thread (void *nr)
       int e;
       do
 	{
-	  xclock_gettime (CLOCK_REALTIME, &ts);
+	  xclock_gettime (clockid_for_get, &ts);
 
           ts = timespec_add (ts, timeout);
 
-	  printf ("reader thread %ld tries again\n", (long int) nr);
+	  printf ("reader thread %d tries again\n", nr);
 
-	  e = pthread_rwlock_timedrdlock (&lock, &ts);
+	  if (clockid == CLOCK_USE_TIMEDLOCK)
+	    e = pthread_rwlock_timedrdlock (&lock, &ts);
+          else
+	    e = pthread_rwlock_clockrdlock (&lock, clockid, &ts);
 	  if (e != 0 && e != ETIMEDOUT)
-            FAIL_EXIT1 ("timedrdlock failed");
+            FAIL_EXIT1 ("%srdlock failed", fnname);
 	}
       while (e == ETIMEDOUT);
 
-      printf ("reader thread %ld succeeded\n", (long int) nr);
+      printf ("reader thread %d succeeded\n", nr);
 
       nanosleep (&delay, NULL);
 
       if (pthread_rwlock_unlock (&lock) != 0)
         FAIL_EXIT1 ("unlock for reader failed");
 
-      printf ("reader thread %ld released\n", (long int) nr);
+      printf ("reader thread %d released\n", nr);
     }
 
   return NULL;
@@ -119,12 +150,11 @@  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];
   int n;
-  void *res;
   pthread_rwlockattr_t a;
 
   if (pthread_rwlockattr_init (&a) != 0)
@@ -142,23 +172,37 @@  do_test (void)
   /* Make sure we see all message, even those on stdout.  */
   setvbuf (stdout, NULL, _IONBF, 0);
 
-  for (n = 0; n < NWRITERS; ++n)
-    if (pthread_create (&thwr[n], NULL, writer_thread,
-			(void *) (long int) n) != 0)
-      FAIL_EXIT1 ("writer create failed");
-
-  for (n = 0; n < NREADERS; ++n)
-    if (pthread_create (&thrd[n], NULL, reader_thread,
-			(void *) (long int) n) != 0)
-      FAIL_EXIT1 ("reader create failed");
+  struct thread_args wargs[NWRITERS];
+  for (n = 0; n < NWRITERS; ++n) {
+    wargs[n].nr = n;
+    wargs[n].clockid = clockid;
+    wargs[n].fnname = fnname;
+    thwr[n] = xpthread_create (NULL, writer_thread, &wargs[n]);
+  }
+
+  struct thread_args rargs[NREADERS];
+  for (n = 0; n < NREADERS; ++n) {
+    rargs[n].nr = n;
+    rargs[n].clockid = clockid;
+    rargs[n].fnname = fnname;
+    thrd[n] = xpthread_create (NULL, reader_thread, &rargs[n]);
+  }
 
   /* Wait for all the threads.  */
   for (n = 0; n < NWRITERS; ++n)
-    if (pthread_join (thwr[n], &res) != 0)
-      FAIL_EXIT1 ("writer join failed");
+    xpthread_join (thwr[n]);
   for (n = 0; n < NREADERS; ++n)
-    if (pthread_join (thrd[n], &res) != 0)
-      FAIL_EXIT1 ("reader join failed");
+    xpthread_join (thrd[n]);
+
+  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;
 }
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index f000b1e..e78003e 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -909,6 +909,13 @@  extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
 				       __abstime) __THROWNL __nonnull ((1, 2));
 # endif
 
+# ifdef __USE_GNU
+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.  */
 extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock)
      __THROWNL __nonnull ((1));
@@ -924,6 +931,13 @@  extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
 				       __abstime) __THROWNL __nonnull ((1, 2));
 # endif
 
+# ifdef __USE_GNU
+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.  */
 extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock)
      __THROWNL __nonnull ((1));
diff --git a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
index 5af4b8a..9f65baf 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
@@ -244,4 +244,6 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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
diff --git a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
index a00adfb..0709855 100644
--- a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
@@ -228,6 +228,8 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
index 4aeee7b..a2be572 100644
--- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
@@ -28,6 +28,8 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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 _IO_flockfile F
 GLIBC_2.4 _IO_ftrylockfile F
diff --git a/sysdeps/unix/sysv/linux/csky/libpthread.abilist b/sysdeps/unix/sysv/linux/csky/libpthread.abilist
index 2c08b76..c3a1834 100644
--- a/sysdeps/unix/sysv/linux/csky/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libpthread.abilist
@@ -234,4 +234,6 @@  GLIBC_2.29 wait F
 GLIBC_2.29 waitpid F
 GLIBC_2.29 write 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
diff --git a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
index dc0d4ad..2a00ebc 100644
--- a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/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
diff --git a/sysdeps/unix/sysv/linux/i386/libpthread.abilist b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
index 1830e40..4479947 100644
--- a/sysdeps/unix/sysv/linux/i386/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
@@ -254,6 +254,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
diff --git a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
index 0811d73..40a1faf 100644
--- a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
@@ -248,6 +248,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
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
index 4aeee7b..a2be572 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
@@ -28,6 +28,8 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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 _IO_flockfile F
 GLIBC_2.4 _IO_ftrylockfile F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
index 1830e40..4479947 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
@@ -254,6 +254,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
diff --git a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
index f2be6b4..254b708 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
@@ -244,4 +244,6 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
index 41527fe..29ffdd1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
@@ -256,6 +256,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
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
index 41527fe..29ffdd1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
@@ -256,6 +256,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
diff --git a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
index 04fc3a6..3fae328 100644
--- a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
@@ -242,4 +242,6 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
index ebdab1a..a90010d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
@@ -256,6 +256,8 @@  GLIBC_2.3.4 pthread_setaffinity_np F
 GLIBC_2.3.4 pthread_setschedprio F
 GLIBC_2.3.4 siglongjmp 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
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
index 8a1fb34..339eab8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
@@ -247,6 +247,8 @@  GLIBC_2.3.4 pthread_setaffinity_np F
 GLIBC_2.3.4 pthread_setschedprio F
 GLIBC_2.3.4 siglongjmp 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
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
index 5af4b8a..9f65baf 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
@@ -244,4 +244,6 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
index a1c8c2e..83082fb 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
@@ -236,4 +236,6 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
index 0feb3cf..54e937b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
@@ -256,6 +256,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
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
index cc4f160..87f978b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
@@ -248,6 +248,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
diff --git a/sysdeps/unix/sysv/linux/sh/libpthread.abilist b/sysdeps/unix/sysv/linux/sh/libpthread.abilist
index dc0d4ad..2a00ebc 100644
--- a/sysdeps/unix/sysv/linux/sh/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sh/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
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
index ed0574a..bc29a66 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
@@ -256,6 +256,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
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
index 0811d73..40a1faf 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
@@ -248,6 +248,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
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
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
index 5d02b03..92cd2f4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
@@ -244,4 +244,6 @@  GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set 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