This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v2] Semaphores: add sem_clockwait GNU extension [BZ #14717]


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_clockwait() function behaves just like sem_timedwait() but
lets the user specify the clock against which the timeout is measured.
The implementation is based on [1] which covers all functions that take an
absolute struct timespec timeout.

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

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

 One minor issue exists with this implementation: semaphore.h does not expose
 the CLOCK_* constants. It is the users resposibility to include time.h for
 their definition. AFAICT POSIX.1-2008 would allow semaphore.h to include
 time.h but I'm reluctant to do that unconditionally.

 ChangeLog                                          |  50 +++++++++
 NEWS                                               |   5 +
 htl/Makefile                                       |   2 +-
 htl/Versions                                       |   3 +
 manual/ipc.texi                                    |  13 +++
 nptl/Makefile                                      |   5 +-
 nptl/Versions                                      |   4 +
 nptl/sem_clockwait.c                               |  52 +++++++++
 nptl/sem_timedwait.c                               |   2 +-
 nptl/sem_wait.c                                    |   2 +-
 nptl/sem_waitcommon.c                              |  41 +++++--
 nptl/tst-sem17.c                                   | 119 +++++++++++++++++++++
 sysdeps/htl/sem-clockwait.c                        |  40 +++++++
 sysdeps/htl/sem-timedwait.c                        |   7 +-
 sysdeps/htl/sem-wait.c                             |   5 +-
 sysdeps/mach/hurd/i386/libpthread.abilist          |   1 +
 sysdeps/pthread/semaphore.h                        |   7 ++
 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 +
 40 files changed, 362 insertions(+), 19 deletions(-)
 create mode 100644 nptl/sem_clockwait.c
 create mode 100644 nptl/tst-sem17.c
 create mode 100644 sysdeps/htl/sem-clockwait.c

diff --git a/ChangeLog b/ChangeLog
index e419448fe6..69f2a36674 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2018-12-14  Jan Klötzke  <jan@kloetzke.net>
+
+	[BZ #14717]
+	* NEWS: Mention sem_clockwait.
+	* htl/Makefile (libpthread-routines): Add sem-clockwait.
+	* htl/Versions: Add sem_clockwait.
+	* manual/ipc.texi: Likewise.
+	* nptl/Makefile (libpthread-routines): Add sem_clockwait.
+	(tests): Add tst-sem17.
+	* nptl/Versions: Add sem_clockwait.
+	* nptl/sem_clockwait.c: New file.
+	* nptl/sem_timedwait.c (sem_timedwait): Add __new_sem_wait_slow
+	parameter.
+	* nptl/sem_wait.c: Add __new_sem_wait_slow parameter.
+	* nptl/sem_waitcommon.c (do_futex_wait): Add 'monotonic' parameter.
+	* nptl/tst-sem17.c: New file.
+	* sysdeps/htl/sem-clockwait.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_clockwait.
+	* 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/be/libpthread.abilist:
+	Likewise.
+	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/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-13  Joseph Myers  <joseph@codesourcery.com>
 
 	* sysdeps/mach/hurd/i386/init-first.c (_hurd_stack_setup): Do not
diff --git a/NEWS b/NEWS
index ae80818df4..1d8c78cf57 100644
--- a/NEWS
+++ b/NEWS
@@ -46,6 +46,11 @@ Major new features:
   incosistent mutex state after fork call in multithread environment.
   In both popen and system there is no direct access to user-defined mutexes.
 
+* The sem_clockwait function has been added. It complements sem_timedwait by
+  allowing to select the clock against which the absolute timeout is measured.
+  Using CLOCK_MONOTONIC enables an application to wait without being affected
+  by system clock adjustments.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The glibc.tune tunable namespace has been renamed to glibc.cpu and the
diff --git a/htl/Makefile b/htl/Makefile
index 11c21df4d3..cebf3cca0e 100644
--- a/htl/Makefile
+++ b/htl/Makefile
@@ -128,7 +128,7 @@ libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate	    \
 	pt-getschedparam pt-setschedparam pt-setschedprio		    \
 	pt-yield							    \
 									    \
-	sem-close sem-destroy sem-getvalue sem-init sem-open		    \
+	sem-clockwait sem-close sem-destroy sem-getvalue sem-init sem-open  \
 	sem-post sem-timedwait sem-trywait sem-unlink			    \
 	sem-wait							    \
 									    \
diff --git a/htl/Versions b/htl/Versions
index c5a616da10..39aced3245 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_clockwait;
+  }
   GLIBC_PRIVATE {
     __shm_directory;
     __pthread_threads;
diff --git a/manual/ipc.texi b/manual/ipc.texi
index 081b98fe29..05e2e216bd 100644
--- a/manual/ipc.texi
+++ b/manual/ipc.texi
@@ -100,6 +100,19 @@ by @theglibc{}.
 @c Same safety issues as sem_wait.
 @end deftypefun
 
+@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clock_id}, 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 allows the calling thread
+to select the clock against which the absolute timeout is measured. Currently
+@code{CLOCK_MONOTONIC} and @code{CLOCK_REALTIME} are supported. Invoking this
+function with @code{CLOCK_REALTIME} has the identical behaviour as
+@code{sem_timedwait}. By using @code{CLOCK_MONOTONIC} the timeout will be
+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 b01f2b0626..76f850d780 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_clockwait sem_timedwait sem_post \
 		      cleanup cleanup_defer cleanup_compat \
 		      cleanup_defer_compat unwind \
 		      pt-longjmp pt-cleanup\
@@ -193,6 +193,7 @@ CFLAGS-pthread_once.c += $(uses-callbacks) -fexceptions \
 			-fasynchronous-unwind-tables
 CFLAGS-pthread_cond_wait.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-sem_wait.c += -fexceptions -fasynchronous-unwind-tables
+CFLAGS-sem_clockwait.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-sem_timedwait.c += -fexceptions -fasynchronous-unwind-tables
 
 # These are the function wrappers we have to duplicate here.
@@ -263,7 +264,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
 	tst-key1 tst-key2 tst-key3 tst-key4 \
 	tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
 	tst-sem8 tst-sem9 tst-sem10 tst-sem14 \
-	tst-sem15 tst-sem16 \
+	tst-sem15 tst-sem16 tst-sem17 \
 	tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
 	tst-align tst-align3 \
 	tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
diff --git a/nptl/Versions b/nptl/Versions
index e7f691da7a..4d4a79da55 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_clockwait;
+  }
+
   GLIBC_PRIVATE {
     __pthread_initialize_minimal;
     __pthread_clock_gettime; __pthread_clock_settime;
diff --git a/nptl/sem_clockwait.c b/nptl/sem_clockwait.c
new file mode 100644
index 0000000000..f0d9487c82
--- /dev/null
+++ b/nptl/sem_clockwait.c
@@ -0,0 +1,52 @@
+/* sem_clockwait -- wait on a semaphore with timeout against specific clock.
+   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_clockwait is only
+   provided if __USE_GNU is defined.  */
+int
+sem_clockwait (sem_t *sem, clockid_t clock_id, const struct timespec *abstime)
+{
+  if (__glibc_unlikely (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (__glibc_unlikely (clock_id != CLOCK_MONOTONIC
+			&& clock_id != CLOCK_REALTIME))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* If we do not support waiting using CLOCK_MONOTONIC, return an error.  */
+  if (clock_id == CLOCK_MONOTONIC
+      && !futex_supports_exact_relative_timeouts())
+    return ENOTSUP;
+
+  /* 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,
+			       clock_id == CLOCK_MONOTONIC);
+}
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_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/nptl/tst-sem17.c b/nptl/tst-sem17.c
new file mode 100644
index 0000000000..12561b8911
--- /dev/null
+++ b/nptl/tst-sem17.c
@@ -0,0 +1,119 @@
+/* Copyright (C) 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 <errno.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define EXPECT_OK(exp)							    \
+  do {									    \
+    int ret = (exp);							    \
+    if (ret < 0)							    \
+      {									    \
+	printf ("%s:%d: call failed: %s\n", __FILE__, __LINE__,		    \
+		strerror(errno));					    \
+	return 1;							    \
+      }									    \
+  } while (0)
+
+#define SEM_CLOCKWAIT_EXPECT_FAIL(err, clk)				    \
+  do {									    \
+    errno = 0;								    \
+    if (sem_clockwait (&s, (clk), &ts) >= 0)				    \
+      {									    \
+	printf ("%s:%d: sem_clockwait did not fail\n", __FILE__, __LINE__); \
+	return 1;							    \
+      }									    \
+    if (errno != (err))							    \
+      {									    \
+	printf("%s:%d: sem_clockwait did not fail with %d but %d\n",	    \
+	       __FILE__, __LINE__, (err), errno);			    \
+	return 1;							    \
+      }									    \
+  } while (0)
+
+static int
+do_test (void)
+{
+  sem_t s;
+  int val;
+
+  if (sem_init (&s, 0, 2) != 0)
+    {
+      puts ("sem_init failed");
+      return 1;
+    }
+
+  struct timespec ts = { 0, 0 };
+
+  /* CLOCK_REALTIME accepted */
+  EXPECT_OK(sem_clockwait(&s, CLOCK_REALTIME, &ts));
+
+  /* CLOCK_MONOTONIC accepted */
+  EXPECT_OK(sem_clockwait(&s, CLOCK_MONOTONIC, &ts));
+
+  /* invalid clock fails */
+  SEM_CLOCKWAIT_EXPECT_FAIL(EINVAL, 42);
+
+  /* semaphore value ought to be zero by now */
+  EXPECT_OK(sem_getvalue(&s, &val));
+  if (val != 0)
+    {
+      puts("semphore value not zero");
+      return 1;
+    }
+
+  /* invalid tv_nsec */
+  ts.tv_nsec = 1000000001;
+  SEM_CLOCKWAIT_EXPECT_FAIL(EINVAL, CLOCK_MONOTONIC);
+  ts.tv_nsec = -1;
+  SEM_CLOCKWAIT_EXPECT_FAIL(EINVAL, CLOCK_MONOTONIC);
+
+  /* ancient tv_sec */
+  ts.tv_sec = -2;
+  ts.tv_nsec = 0;
+  SEM_CLOCKWAIT_EXPECT_FAIL(ETIMEDOUT, CLOCK_MONOTONIC);
+
+  /* wait 100ms with CLOCK_MONOTONIC */
+  EXPECT_OK(clock_gettime(CLOCK_MONOTONIC, &ts));
+  ts.tv_nsec += 100000000;
+  if (ts.tv_nsec >= 1000000000)
+    {
+      ++ts.tv_sec;
+      ts.tv_nsec -= 1000000000;
+    }
+
+  SEM_CLOCKWAIT_EXPECT_FAIL(ETIMEDOUT, CLOCK_MONOTONIC);
+
+  struct timespec ts2;
+  EXPECT_OK(clock_gettime(CLOCK_MONOTONIC, &ts2));
+
+  if (ts2.tv_sec < ts.tv_sec
+      || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec < ts.tv_nsec))
+    {
+      puts ("timeout too short");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/htl/sem-clockwait.c b/sysdeps/htl/sem-clockwait.c
new file mode 100644
index 0000000000..68eae9a5ab
--- /dev/null
+++ b/sysdeps/htl/sem-clockwait.c
@@ -0,0 +1,40 @@
+/* Wait on a semaphore with timeout on certain clock.  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_clockwait (sem_t *restrict sem, clockid_t clock_id,
+		 const struct timespec *restrict timeout)
+{
+  if (__glibc_unlikely (clock_id != CLOCK_MONOTONIC
+			&& clock_id != CLOCK_REALTIME))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  return __sem_timedwait_internal (sem, timeout, clock_id);
+}
+
+strong_alias (__sem_clockwait, sem_clockwait);
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..6085a7ff9c 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_clockwait F
diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
index ff672ebd24..94417d7d95 100644
--- a/sysdeps/pthread/semaphore.h
+++ b/sysdeps/pthread/semaphore.h
@@ -61,6 +61,13 @@ extern int sem_timedwait (sem_t *__restrict __sem,
 			  const struct timespec *__restrict __abstime);
 #endif
 
+#ifdef __USE_GNU
+/* Similar to `sem_timedwait' but with configurable clock.  */
+extern int sem_clockwait (sem_t *__restrict __sem,
+			  clockid_t __clock_id,
+			  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..1f6e81e572 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_clockwait F
diff --git a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
index b413007ccb..ff915631b6 100644
--- a/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
index af82a4c632..c15acc206c 100644
--- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
@@ -27,6 +27,7 @@ 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_clockwait F
 GLIBC_2.4 _IO_flockfile F
 GLIBC_2.4 _IO_ftrylockfile F
 GLIBC_2.4 _IO_funlockfile F
diff --git a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
index bcba07f575..c11b16802f 100644
--- a/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libpthread.abilist
@@ -219,6 +219,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/i386/libpthread.abilist b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
index bece86d246..3adc3fd963 100644
--- a/sysdeps/unix/sysv/linux/i386/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
index ccc9449826..57d1fe0206 100644
--- a/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libpthread.abilist
@@ -219,6 +219,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
index af82a4c632..c15acc206c 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
@@ -27,6 +27,7 @@ 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_clockwait F
 GLIBC_2.4 _IO_flockfile F
 GLIBC_2.4 _IO_ftrylockfile F
 GLIBC_2.4 _IO_funlockfile F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
index bece86d246..3adc3fd963 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist b/sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
index 5067375d23..60d75df085 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_clockwait F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
index 02144967c6..1c26f72767 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
index 02144967c6..1c26f72767 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/nios2/libpthread.abilist b/sysdeps/unix/sysv/linux/nios2/libpthread.abilist
index 78cac2ae27..5ded824c40 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_clockwait F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
index 09e8447b06..e65bfd94f3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init 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..5ac044fad7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
@@ -27,6 +27,7 @@ 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_clockwait F
 GLIBC_2.3 _IO_flockfile F
 GLIBC_2.3 _IO_ftrylockfile F
 GLIBC_2.3 _IO_funlockfile 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..1f6e81e572 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_clockwait F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
index c370fda73d..077574fea6 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_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 d05468f3b2..919ae6dc42 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
@@ -229,6 +229,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init 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..4178c015cf 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
@@ -221,6 +221,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/sh/libpthread.abilist b/sysdeps/unix/sysv/linux/sh/libpthread.abilist
index bcba07f575..c11b16802f 100644
--- a/sysdeps/unix/sysv/linux/sh/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libpthread.abilist
@@ -219,6 +219,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
index b413007ccb..ff915631b6 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
@@ -227,6 +227,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
index ccc9449826..57d1fe0206 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
@@ -219,6 +219,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init 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..b7f0ee5045 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
@@ -219,6 +219,7 @@ 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_clockwait F
 GLIBC_2.3.2 pthread_cond_broadcast F
 GLIBC_2.3.2 pthread_cond_destroy F
 GLIBC_2.3.2 pthread_cond_init 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..356412e100 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_clockwait F
-- 
2.11.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]