Semaphores: add sem_timedwait_monotonic GNU extension [BZ #14717]

Message ID 20181213200009.22246-1-jan@kloetzke.net
State New, archived
Headers

Commit Message

Jan Klötzke Dec. 13, 2018, 8 p.m. UTC
  As defined by POSIX.1-2001 the 'abstime' timeout of  sem_timedwait()
shall be based on CLOCK_REALTIME. This has the unpleasant effect that
application timeouts are affected by system clock adjustments.

The added sem_timedwait_monotonic() function behaves just like
sem_timedwait() but is based on CLOCK_MONOTONIC. An identically named
function is already provided by QNX for the same reasons.

Signed-off-by: Jan Klötzke <jan@kloetzke.net>
---

Tested on AArch64 and X86_64.

 ChangeLog                                          | 48 ++++++++++++++++++++++
 htl/Makefile                                       |  4 +-
 htl/Versions                                       |  3 ++
 manual/ipc.texi                                    | 11 +++++
 nptl/Makefile                                      |  3 +-
 nptl/Versions                                      |  4 ++
 nptl/sem_timedwait.c                               |  2 +-
 nptl/sem_timedwait_monotonic.c                     | 40 ++++++++++++++++++
 nptl/sem_wait.c                                    |  2 +-
 nptl/sem_waitcommon.c                              | 41 ++++++++++++++----
 sysdeps/htl/sem-timedwait-monotonic.c              | 32 +++++++++++++++
 sysdeps/htl/sem-timedwait.c                        |  7 ++--
 sysdeps/htl/sem-wait.c                             |  5 ++-
 sysdeps/mach/hurd/i386/libpthread.abilist          |  1 +
 sysdeps/pthread/semaphore.h                        |  6 +++
 sysdeps/unix/sysv/linux/aarch64/libpthread.abilist |  1 +
 sysdeps/unix/sysv/linux/alpha/libpthread.abilist   |  1 +
 sysdeps/unix/sysv/linux/arm/libpthread.abilist     |  1 +
 sysdeps/unix/sysv/linux/hppa/libpthread.abilist    |  1 +
 sysdeps/unix/sysv/linux/i386/libpthread.abilist    |  1 +
 sysdeps/unix/sysv/linux/ia64/libpthread.abilist    |  1 +
 .../sysv/linux/m68k/coldfire/libpthread.abilist    |  1 +
 .../unix/sysv/linux/m68k/m680x0/libpthread.abilist |  1 +
 .../unix/sysv/linux/microblaze/libpthread.abilist  |  1 +
 .../unix/sysv/linux/mips/mips32/libpthread.abilist |  1 +
 .../unix/sysv/linux/mips/mips64/libpthread.abilist |  1 +
 sysdeps/unix/sysv/linux/nios2/libpthread.abilist   |  1 +
 .../linux/powerpc/powerpc32/libpthread.abilist     |  1 +
 .../linux/powerpc/powerpc64/be/libpthread.abilist  |  1 +
 .../linux/powerpc/powerpc64/le/libpthread.abilist  |  1 +
 .../unix/sysv/linux/riscv/rv64/libpthread.abilist  |  1 +
 .../sysv/linux/s390/s390-32/libpthread.abilist     |  1 +
 .../sysv/linux/s390/s390-64/libpthread.abilist     |  1 +
 sysdeps/unix/sysv/linux/sh/libpthread.abilist      |  1 +
 .../sysv/linux/sparc/sparc32/libpthread.abilist    |  1 +
 .../sysv/linux/sparc/sparc64/libpthread.abilist    |  1 +
 .../unix/sysv/linux/x86_64/64/libpthread.abilist   |  1 +
 .../unix/sysv/linux/x86_64/x32/libpthread.abilist  |  1 +
 38 files changed, 213 insertions(+), 19 deletions(-)
 create mode 100644 nptl/sem_timedwait_monotonic.c
 create mode 100644 sysdeps/htl/sem-timedwait-monotonic.c
  

Comments

Joseph Myers Dec. 13, 2018, 8:28 p.m. UTC | #1
On Thu, 13 Dec 2018, Jan Klötzke wrote:

> The added sem_timedwait_monotonic() function behaves just like
> sem_timedwait() but is based on CLOCK_MONOTONIC. An identically named
> function is already provided by QNX for the same reasons.

My understanding from the Austin Group discussion was that the preferred 
approach was functions with "clock" instead of "timed" in their names, 
taking a clockid parameter (so sem_clockwait in this case).

http://austingroupbugs.net/view.php?id=1216

Note that new functions need a NEWS entry.  They also need testcases; I 
don't see any in this patch.

How has this patch been tested?  I'd have expected it to fail the ABI 
tests, because

> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 931c8277a8..a69993f4d9 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -254,3 +254,4 @@ GLIBC_2.4 pthread_mutexattr_getrobust_np F
>  GLIBC_2.4 pthread_mutexattr_setprioceiling F
>  GLIBC_2.4 pthread_mutexattr_setprotocol F
>  GLIBC_2.4 pthread_mutexattr_setrobust_np F
> +GLIBC_2.29 sem_timedwait_monotonic F

(for example) is not placing the new entry in its correct (LC_ALL=C) 
sorted location.

Are you covered by an FSF copyright assignment?
  
Jan Klötzke Dec. 14, 2018, 9:03 p.m. UTC | #2
On Thu, Dec 13, 2018 at 08:28:12PM +0000, Joseph Myers wrote:
> On Thu, 13 Dec 2018, Jan Klötzke wrote:
> 
> > The added sem_timedwait_monotonic() function behaves just like
> > sem_timedwait() but is based on CLOCK_MONOTONIC. An identically named
> > function is already provided by QNX for the same reasons.
> 
> My understanding from the Austin Group discussion was that the preferred 
> approach was functions with "clock" instead of "timed" in their names, 
> taking a clockid parameter (so sem_clockwait in this case).
> 
> http://austingroupbugs.net/view.php?id=1216

Oh, I wasn't aware of this proposal. Looks reasonable and even more
generic. I will send a v2 accordingly. I'm not sure if I find the time
to implement the other proposed functions but it looks worth it.

> Note that new functions need a NEWS entry.  They also need testcases; I 
> don't see any in this patch.

Will fix that with v2 too.

> How has this patch been tested?  I'd have expected it to fail the ABI 
> tests, because
> 
> > diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > index 931c8277a8..a69993f4d9 100644
> > --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> > @@ -254,3 +254,4 @@ GLIBC_2.4 pthread_mutexattr_getrobust_np F
> >  GLIBC_2.4 pthread_mutexattr_setprioceiling F
> >  GLIBC_2.4 pthread_mutexattr_setprotocol F
> >  GLIBC_2.4 pthread_mutexattr_setrobust_np F
> > +GLIBC_2.29 sem_timedwait_monotonic F
> 
> (for example) is not placing the new entry in its correct (LC_ALL=C) 
> sorted location.

The cold and harsh truth is that I forgot to execute the tests. My bad.
I only tested it by running some manual tests with the new version.

> Are you covered by an FSF copyright assignment?

Not yet. Quite frankly I'm a bit lost what needs to be done exactly to
pass the legal part.

Regards,
Jan
  
Joseph Myers Dec. 14, 2018, 9:11 p.m. UTC | #3
On Fri, 14 Dec 2018, Jan Klötzke wrote:

> > Are you covered by an FSF copyright assignment?
> 
> Not yet. Quite frankly I'm a bit lost what needs to be done exactly to
> pass the legal part.

https://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/Copyright/request-assign.future
  
Carlos O'Donell Dec. 14, 2018, 9:28 p.m. UTC | #4
On 12/14/18 4:11 PM, Joseph Myers wrote:
> On Fri, 14 Dec 2018, Jan Klötzke wrote:
> 
>>> Are you covered by an FSF copyright assignment?
>>
>> Not yet. Quite frankly I'm a bit lost what needs to be done exactly to
>> pass the legal part.
> 
> https://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/Copyright/request-assign.future
> 

You follow those instructions, and the FSF will kick off the process.

Please feel free to reach out to me if you have any issues or questions.

Thank you again for contributing to the project.
  
Jan Klötzke Dec. 14, 2018, 9:51 p.m. UTC | #5
On Fri, Dec 14, 2018 at 04:28:11PM -0500, Carlos O'Donell wrote:
> On 12/14/18 4:11 PM, Joseph Myers wrote:
> > On Fri, 14 Dec 2018, Jan Klötzke wrote:
> > 
> >>> Are you covered by an FSF copyright assignment?
> >>
> >> Not yet. Quite frankly I'm a bit lost what needs to be done exactly to
> >> pass the legal part.
> > 
> > https://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/Copyright/request-assign.future
> > 
> 
> You follow those instructions, and the FSF will kick off the process.
> 
> Please feel free to reach out to me if you have any issues or questions.
> 
> Thank you again for contributing to the project.

Thanks - much appreciated. E-mail is already out. I'll come back once
the legal process is finshed...

Regards,
Jan
  

Patch

diff --git a/ChangeLog b/ChangeLog
index 92683cb643..9386c129eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,51 @@ 
+2018-12-13  Jan Klötzke  <jan@kloetzke.net>
+
+	[BZ #14717]
+	* htl/Makefile (libpthread-routines): Add sem-timedwait-monotonic.
+	* htl/Versions: Add sem_timedwait_monotonic.
+	* manual/ipc.texi: Likewise.
+	* nptl/Makefile: Likewise.
+	* nptl/Versions: Likewise.
+	* nptl/sem_timedwait.c (sem_timedwait): Add __new_sem_wait_slow
+	parameter.
+	* nptl/sem_timedwait_monotonic.c: New file.
+	* nptl/sem_wait.c: Add __new_sem_wait_slow parameter.
+	* nptl/sem_waitcommon.c (do_futex_wait): Add 'monotonic' parameter.
+	* sysdeps/htl/sem-timedwait-monotonic.c: New file.
+	* sysdeps/htl/sem-timedwait.c (__sem_timedwait_internal): Add
+	'clock_id' parameter.
+	(__sem_timedwait): Pass CLOCK_REALTIME to __sem_timedwait_internal.
+	* sysdeps/htl/sem-wait.c (__sem_wait): Likewise.
+	* sysdeps/mach/hurd/i386/libpthread.abilist: Add
+	sem_timedwait_monotonic.
+	* sysdeps/pthread/semaphore.h: Likewise.
+	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/arm/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/i386/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread-le.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libpthread.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/sh/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Likewise.
+	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist: Likewise.
+
 2018-12-12  Joseph Myers  <joseph@codesourcery.com>
 
 	* sysdeps/x86/fpu/bits/mathinline.h (hypot): Remove inline
diff --git a/htl/Makefile b/htl/Makefile
index 11c21df4d3..72125058b4 100644
--- a/htl/Makefile
+++ b/htl/Makefile
@@ -129,8 +129,8 @@  libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate	    \
 	pt-yield							    \
 									    \
 	sem-close sem-destroy sem-getvalue sem-init sem-open		    \
-	sem-post sem-timedwait sem-trywait sem-unlink			    \
-	sem-wait							    \
+	sem-post sem-timedwait sem-timedwait-monotonic sem-trywait	    \
+	sem-unlink sem-wait						    \
 									    \
 	shm-directory							    \
 									    \
diff --git a/htl/Versions b/htl/Versions
index c5a616da10..a4598ba39c 100644
--- a/htl/Versions
+++ b/htl/Versions
@@ -141,6 +141,9 @@  libpthread {
     pthread_hurd_cond_wait_np;
     pthread_hurd_cond_timedwait_np;
   }
+  GLIBC_2.29 {
+    sem_timedwait_monotonic;
+  }
   GLIBC_PRIVATE {
     __shm_directory;
     __pthread_threads;
diff --git a/manual/ipc.texi b/manual/ipc.texi
index 081b98fe29..c122d436a8 100644
--- a/manual/ipc.texi
+++ b/manual/ipc.texi
@@ -100,6 +100,17 @@  by @theglibc{}.
 @c Same safety issues as sem_wait.
 @end deftypefun
 
+@deftypefun int sem_timedwait_monotonic (sem_t *@var{sem}, const struct timespec *@var{abstime});
+@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}}
+@c Same safety issues as sem_wait.
+This function is similar to @code{sem_timedwait}, but uses
+@code{CLOCK_MONOTONIC} instead of @code{CLOCK_REALTIME} for the absolute
+timeout. This makes the timeout unaffected by changes to the system real time
+clock.
+
+This function is a GNU extension.
+@end deftypefun
+
 @deftypefun int sem_trywait (sem_t *@var{sem});
 @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
 @c All atomic operations are safe in all contexts.
diff --git a/nptl/Makefile b/nptl/Makefile
index 34ae830276..3c52bc0979 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -114,7 +114,7 @@  libpthread-routines = nptl-init nptlfreeres vars events version pt-interp \
 		      sem_init sem_destroy \
 		      sem_open sem_close sem_unlink \
 		      sem_getvalue \
-		      sem_wait sem_timedwait sem_post \
+		      sem_wait sem_timedwait sem_timedwait_monotonic sem_post \
 		      cleanup cleanup_defer cleanup_compat \
 		      cleanup_defer_compat unwind \
 		      pt-longjmp pt-cleanup\
@@ -194,6 +194,7 @@  CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \
 CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sem_timedwait_monotonic.c += -fexceptions -fasynchronous-unwind-tables
 
 # These are the function wrappers we have to duplicate here.
 CFLAGS-fcntl.c += -fexceptions -fasynchronous-unwind-tables
diff --git a/nptl/Versions b/nptl/Versions
index e7f691da7a..a32c1ef252 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -277,6 +277,10 @@  libpthread {
     cnd_timedwait; cnd_wait; tss_create; tss_delete; tss_get; tss_set;
   }
 
+  GLIBC_2.29 {
+    sem_timedwait_monotonic;
+  }
+
   GLIBC_PRIVATE {
     __pthread_initialize_minimal;
     __pthread_clock_gettime; __pthread_clock_settime;
diff --git a/nptl/sem_timedwait.c b/nptl/sem_timedwait.c
index 8886ea2fb3..dec6882f41 100644
--- a/nptl/sem_timedwait.c
+++ b/nptl/sem_timedwait.c
@@ -36,5 +36,5 @@  sem_timedwait (sem_t *sem, const struct timespec *abstime)
   if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
     return 0;
   else
-    return __new_sem_wait_slow((struct new_sem *) sem, abstime);
+    return __new_sem_wait_slow((struct new_sem *) sem, abstime, 0);
 }
diff --git a/nptl/sem_timedwait_monotonic.c b/nptl/sem_timedwait_monotonic.c
new file mode 100644
index 0000000000..832b58175b
--- /dev/null
+++ b/nptl/sem_timedwait_monotonic.c
@@ -0,0 +1,40 @@ 
+/* sem_timedwait_monotonic -- wait on a semaphore with timeout against CLOCK_MONOTONIC.
+   Copyright (C) 2003-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "sem_waitcommon.c"
+
+/* This is in a separate file because because sem_timedwait_monotonic is only
+   provided if __USE_GNU is defined.  */
+int
+sem_timedwait_monotonic (sem_t *sem, const struct timespec *abstime)
+{
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Check sem_wait.c for a more detailed explanation why it is required.  */
+  __pthread_testcancel ();
+
+  if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
+    return 0;
+  else
+    return __new_sem_wait_slow((struct new_sem *) sem, abstime, 1);
+}
+
diff --git a/nptl/sem_wait.c b/nptl/sem_wait.c
index e7d910613f..de29868fdb 100644
--- a/nptl/sem_wait.c
+++ b/nptl/sem_wait.c
@@ -39,7 +39,7 @@  __new_sem_wait (sem_t *sem)
   if (__new_sem_wait_fast ((struct new_sem *) sem, 0) == 0)
     return 0;
   else
-    return __new_sem_wait_slow((struct new_sem *) sem, NULL);
+    return __new_sem_wait_slow((struct new_sem *) sem, NULL, 0);
 }
 versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
 
diff --git a/nptl/sem_waitcommon.c b/nptl/sem_waitcommon.c
index 30984be2d0..7012c3fdf1 100644
--- a/nptl/sem_waitcommon.c
+++ b/nptl/sem_waitcommon.c
@@ -103,19 +103,42 @@  __sem_wait_cleanup (void *arg)
    users don't seem to need it.  */
 static int
 __attribute__ ((noinline))
-do_futex_wait (struct new_sem *sem, const struct timespec *abstime)
+do_futex_wait (struct new_sem *sem, const struct timespec *abstime, int monotonic)
 {
   int err;
+  unsigned int * futex_word;
 
 #if __HAVE_64B_ATOMICS
-  err = futex_abstimed_wait_cancelable (
-      (unsigned int *) &sem->data + SEM_VALUE_OFFSET, 0, abstime,
-      sem->private);
+  futex_word = (unsigned int *) &sem->data + SEM_VALUE_OFFSET;
 #else
-  err = futex_abstimed_wait_cancelable (&sem->value, SEM_NWAITERS_MASK,
-					abstime, sem->private);
+  futex_word = &sem->value;
 #endif
 
+  if (monotonic)
+    {
+      /* CLOCK_MONOTONIC is requested.  */
+      struct timespec rt;
+      if (__clock_gettime (CLOCK_MONOTONIC, &rt) != 0)
+	__libc_fatal ("clock_gettime does not support "
+		      "CLOCK_MONOTONIC\n");
+      /* Convert the absolute timeout value to a relative
+	 timeout.  */
+      rt.tv_sec = abstime->tv_sec - rt.tv_sec;
+      rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec;
+      if (rt.tv_nsec < 0)
+	{
+	  rt.tv_nsec += 1000000000;
+	  --rt.tv_sec;
+	}
+      /* Did we already time out?  */
+      if (__glibc_unlikely (rt.tv_sec < 0))
+	err = ETIMEDOUT;
+      else
+	err = futex_reltimed_wait_cancelable (futex_word, 0, &rt, sem->private);
+    }
+  else
+    err = futex_abstimed_wait_cancelable (futex_word, 0, abstime, sem->private);
+
   return err;
 }
 
@@ -160,7 +183,7 @@  __new_sem_wait_fast (struct new_sem *sem, int definitive_result)
 /* Slow path that blocks.  */
 static int
 __attribute__ ((noinline))
-__new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
+__new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime, int monotonic)
 {
   int err = 0;
 
@@ -178,7 +201,7 @@  __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
       /* If there is no token available, sleep until there is.  */
       if ((d & SEM_VALUE_MASK) == 0)
 	{
-	  err = do_futex_wait (sem, abstime);
+	  err = do_futex_wait (sem, abstime, monotonic);
 	  /* A futex return value of 0 or EAGAIN is due to a real or spurious
 	     wake-up, or due to a change in the number of tokens.  We retry in
 	     these cases.
@@ -279,7 +302,7 @@  __new_sem_wait_slow (struct new_sem *sem, const struct timespec *abstime)
 	  if ((v >> SEM_VALUE_SHIFT) == 0)
 	    {
 	      /* See __HAVE_64B_ATOMICS variant.  */
-	      err = do_futex_wait(sem, abstime);
+	      err = do_futex_wait(sem, abstime, monotonic);
 	      if (err == ETIMEDOUT || err == EINTR)
 		{
 		  __set_errno (err);
diff --git a/sysdeps/htl/sem-timedwait-monotonic.c b/sysdeps/htl/sem-timedwait-monotonic.c
new file mode 100644
index 0000000000..4ba370f17f
--- /dev/null
+++ b/sysdeps/htl/sem-timedwait-monotonic.c
@@ -0,0 +1,32 @@ 
+/* Wait on a semaphore.  Generic version.
+   Copyright (C) 2005-2018 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 <semaphore.h>
+#include <pt-internal.h>
+
+extern int __sem_timedwait_internal (sem_t *restrict sem,
+				     const struct timespec *restrict timeout,
+				     clockid_t clock_id);
+
+int
+__sem_timedwait_monotonic (sem_t *restrict sem, const struct timespec *restrict timeout)
+{
+  return __sem_timedwait_internal (sem, timeout, CLOCK_MONOTONIC);
+}
+
+strong_alias (__sem_timedwait_monotonic, sem_timedwait_monotonic);
diff --git a/sysdeps/htl/sem-timedwait.c b/sysdeps/htl/sem-timedwait.c
index 803a5c04f4..a7a057faca 100644
--- a/sysdeps/htl/sem-timedwait.c
+++ b/sysdeps/htl/sem-timedwait.c
@@ -24,7 +24,8 @@ 
 
 int
 __sem_timedwait_internal (sem_t *restrict sem,
-			  const struct timespec *restrict timeout)
+			  const struct timespec *restrict timeout,
+			  clockid_t clock_id)
 {
   error_t err;
   int drain;
@@ -53,7 +54,7 @@  __sem_timedwait_internal (sem_t *restrict sem,
 
   /* Block the thread.  */
   if (timeout != NULL)
-    err = __pthread_timedblock (self, timeout, CLOCK_REALTIME);
+    err = __pthread_timedblock (self, timeout, clock_id);
   else
     {
       err = 0;
@@ -92,7 +93,7 @@  __sem_timedwait_internal (sem_t *restrict sem,
 int
 __sem_timedwait (sem_t *restrict sem, const struct timespec *restrict timeout)
 {
-  return __sem_timedwait_internal (sem, timeout);
+  return __sem_timedwait_internal (sem, timeout, CLOCK_REALTIME);
 }
 
 weak_alias (__sem_timedwait, sem_timedwait);
diff --git a/sysdeps/htl/sem-wait.c b/sysdeps/htl/sem-wait.c
index 9fcd22781b..484c43dc13 100644
--- a/sysdeps/htl/sem-wait.c
+++ b/sysdeps/htl/sem-wait.c
@@ -20,12 +20,13 @@ 
 #include <pt-internal.h>
 
 extern int __sem_timedwait_internal (sem_t *restrict sem,
-				     const struct timespec *restrict timeout);
+				     const struct timespec *restrict timeout,
+				     clockid_t clock_id);
 
 int
 __sem_wait (sem_t *sem)
 {
-  return __sem_timedwait_internal (sem, 0);
+  return __sem_timedwait_internal (sem, 0, CLOCK_REALTIME);
 }
 
 strong_alias (__sem_wait, sem_wait);
diff --git a/sysdeps/mach/hurd/i386/libpthread.abilist b/sysdeps/mach/hurd/i386/libpthread.abilist
index 4c7d06d073..8443bdc890 100644
--- a/sysdeps/mach/hurd/i386/libpthread.abilist
+++ b/sysdeps/mach/hurd/i386/libpthread.abilist
@@ -147,3 +147,4 @@  GLIBC_2.2.6 _IO_ftrylockfile F
 GLIBC_2.2.6 _IO_funlockfile F
 GLIBC_2.21 pthread_hurd_cond_timedwait_np F
 GLIBC_2.21 pthread_hurd_cond_wait_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
index ff672ebd24..66eca69d61 100644
--- a/sysdeps/pthread/semaphore.h
+++ b/sysdeps/pthread/semaphore.h
@@ -61,6 +61,12 @@  extern int sem_timedwait (sem_t *__restrict __sem,
 			  const struct timespec *__restrict __abstime);
 #endif
 
+#ifdef __USE_GNU
+/* Similar to `sem_timedwait' but uses CLOCK_MONOTONIC.  */
+extern int sem_timedwait_monotonic (sem_t *__restrict __sem,
+			  const struct timespec *__restrict __abstime);
+#endif
+
 /* Test whether SEM is posted.  */
 extern int sem_trywait (sem_t *__sem) __THROWNL;
 
diff --git a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
index 9a9e4cee85..82de41f4fc 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
@@ -243,3 +243,4 @@  GLIBC_2.28 tss_create F
 GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
index b413007ccb..7c30232cbf 100644
--- a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
@@ -264,3 +264,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
index af82a4c632..cd9d66e996 100644
--- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
@@ -243,3 +243,4 @@  GLIBC_2.4 vfork F
 GLIBC_2.4 wait F
 GLIBC_2.4 waitpid F
 GLIBC_2.4 write F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
index bcba07f575..539c7438db 100644
--- a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
@@ -254,3 +254,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/i386/libpthread.abilist b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
index bece86d246..c3f9e95879 100644
--- a/sysdeps/unix/sysv/linux/i386/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
@@ -262,3 +262,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
index ccc9449826..9d6d8469da 100644
--- a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
@@ -256,3 +256,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
index af82a4c632..cd9d66e996 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
@@ -243,3 +243,4 @@  GLIBC_2.4 vfork F
 GLIBC_2.4 wait F
 GLIBC_2.4 waitpid F
 GLIBC_2.4 write F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
index bece86d246..c3f9e95879 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
@@ -262,3 +262,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
index 5067375d23..02f686d5e4 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
@@ -243,3 +243,4 @@  GLIBC_2.28 tss_create F
 GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
index 02144967c6..6d55011941 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
@@ -264,3 +264,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
index 02144967c6..6d55011941 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
@@ -264,3 +264,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
index 78cac2ae27..5b9f4dc4ac 100644
--- a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
@@ -241,3 +241,4 @@  GLIBC_2.28 tss_create F
 GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
index 09e8447b06..303ba82a4a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
@@ -266,3 +266,4 @@  GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
 GLIBC_2.6 pthread_attr_setstack F
 GLIBC_2.6 pthread_attr_setstacksize F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
index 8300958d47..1c29426977 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
@@ -257,3 +257,4 @@  GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
 GLIBC_2.6 pthread_attr_setstack F
 GLIBC_2.6 pthread_attr_setstacksize F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
index 9a9e4cee85..82de41f4fc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
@@ -243,3 +243,4 @@  GLIBC_2.28 tss_create F
 GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
index c370fda73d..57e4071753 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
@@ -235,3 +235,4 @@  GLIBC_2.28 tss_create F
 GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
index d05468f3b2..ac05de8918 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
@@ -264,3 +264,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
index e8161aa747..93ba9b5704 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
@@ -256,3 +256,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/sh/libpthread.abilist b/sysdeps/unix/sysv/linux/sh/libpthread.abilist
index bcba07f575..539c7438db 100644
--- a/sysdeps/unix/sysv/linux/sh/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libpthread.abilist
@@ -254,3 +254,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
index b413007ccb..7c30232cbf 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
@@ -264,3 +264,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
index ccc9449826..9d6d8469da 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
@@ -256,3 +256,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
index 931c8277a8..a69993f4d9 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
@@ -254,3 +254,4 @@  GLIBC_2.4 pthread_mutexattr_getrobust_np F
 GLIBC_2.4 pthread_mutexattr_setprioceiling F
 GLIBC_2.4 pthread_mutexattr_setprotocol F
 GLIBC_2.4 pthread_mutexattr_setrobust_np F
+GLIBC_2.29 sem_timedwait_monotonic F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
index c09c9b015a..0af240bd36 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
@@ -243,3 +243,4 @@  GLIBC_2.28 tss_create F
 GLIBC_2.28 tss_delete F
 GLIBC_2.28 tss_get F
 GLIBC_2.28 tss_set F
+GLIBC_2.29 sem_timedwait_monotonic F