[2/7] nptl: Add POSIX-proposed sem_clockwait
diff mbox series

Message ID 47415e51fea8d960fc993cf0e0b8db6a19511d28.1551291557.git-series.mac@mcrowe.com
State New
Headers show
Series
  • Implement proposed POSIX _clockwait variants of existing _timedwait functions
Related show

Commit Message

Mike Crowe Feb. 27, 2019, 6:23 p.m. UTC
Add:

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

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

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

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

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

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

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

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

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

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

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

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

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

Comments

Joseph Myers Feb. 27, 2019, 6:35 p.m. UTC | #1
On Wed, 27 Feb 2019, Mike Crowe wrote:

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

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

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

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

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

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

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

Use TEST_COMPARE (errno, EINVAL).

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

Use TEST_COMPARE (nwaiters, 0).

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

As before.

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

As before.

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

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

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

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

Missing first line description.

> +/* Copyright (C) 2019 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <semaphore.h>
> +#include <stdio.h>
> +#include <time.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +
> +#define NOT_A_VALID_CLOCK 123456
> +
> +static int
> +do_test (void)
> +{
> +  sem_t s;
> +  struct timespec ts;
> +
> +  if (sem_init (&s, 0, 1) == -1)
> +    {
> +      puts ("sem_init failed");
> +      return 1;
> +    }

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

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

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

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

TEST_COMPARE (errno, EINVAL)).

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

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

>  
> +/* A bogus clock value that tells run_test to use
> +   sem_timedwait rather than sem_clockwait */
> +#define	CLOCK_USE_TIMEDWAIT (-1)
>  
>  static int
> -do_test (void)
> +do_test_clock (clockid_t clockid)
>  {
>    sem_t s;
>    struct timespec ts;
> -  struct timeval tv;
>  
>    if (sem_init (&s, 0, 1) == -1)
>      {
> @@ -43,13 +45,8 @@ do_test (void)
>        return 1;
>      }
>  
> -  if (gettimeofday (&tv, NULL) != 0)
> -    {
> -      puts ("gettimeofday failed");
> -      return 1;
> -    }
> -
> -  TIMEVAL_TO_TIMESPEC (&tv, &ts);
> +  (void) clock_gettime (clockid == CLOCK_USE_TIMEDWAIT
> +			? CLOCK_REALTIME : clockid, &ts);
>  
>    /* We wait for half a second.  */
>    ts.tv_nsec += 500000000;
> @@ -60,7 +57,9 @@ do_test (void)
>      }
>  
>    errno = 0;
> -  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
> +  if (TEMP_FAILURE_RETRY ((clockid == CLOCK_USE_TIMEDWAIT)
> +			  ? sem_timedwait (&s, &ts)
> +			  : sem_clockwait (&s, clockid, &ts)) != -1)
>      {
>        puts ("sem_timedwait succeeded");
>        return 1;
> @@ -73,7 +72,8 @@ do_test (void)
>      }
>  
>    struct timespec ts2;
> -  if (clock_gettime (CLOCK_REALTIME, &ts2) != 0)
> +  if (clock_gettime (clockid == CLOCK_USE_TIMEDWAIT
> +		     ? CLOCK_REALTIME : clockid, &ts2) != 0)
>      {
>        puts ("clock_gettime failed");
>        return 1;
> @@ -89,5 +89,13 @@ do_test (void)
>    return 0;
>  }
>  
> +static int do_test (void)
> +{
> +  do_test_clock (CLOCK_USE_TIMEDWAIT);
> +  do_test_clock (CLOCK_REALTIME);
> +  do_test_clock (CLOCK_MONOTONIC);
> +  return 0;
> +}
> +
>  #define TEST_FUNCTION do_test ()
>  #include "../test-skeleton.c"
> diff --git a/sysdeps/pthread/semaphore.h b/sysdeps/pthread/semaphore.h
> index 41ff927..2e68b16 100644
> --- a/sysdeps/pthread/semaphore.h
> +++ b/sysdeps/pthread/semaphore.h
> @@ -59,6 +59,10 @@ extern int sem_wait (sem_t *__sem);
>     __THROW.  */
>  extern int sem_timedwait (sem_t *__restrict __sem,
>  			  const struct timespec *__restrict __abstime);
> +
> +extern int sem_clockwait (sem_t *__restrict __sem,
> +			  clockid_t clock,
> +			  const struct timespec *__restrict __abstime);
>  #endif
>  
>  /* Test whether SEM is posted.  */
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 931c827..454d340 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
>  GLIBC_2.3.4 pthread_getaffinity_np F
>  GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
> +GLIBC_2.30 sem_clockwait F
>  GLIBC_2.4 pthread_mutex_consistent_np F
>  GLIBC_2.4 pthread_mutex_getprioceiling F
>  GLIBC_2.4 pthread_mutex_setprioceiling F
>
Mike Crowe March 10, 2019, 4:17 p.m. UTC | #3
On Tuesday 05 March 2019 at 10:31:33 -0300, Adhemerval Zanella wrote:
> On 27/02/2019 15:23, Mike Crowe wrote:
> > diff --git a/nptl/tst-sem5.c b/nptl/tst-sem5.c
> > index 2149ade..7f1031d 100644
> > --- a/nptl/tst-sem5.c
> > +++ b/nptl/tst-sem5.c
> > @@ -23,13 +23,15 @@
> >  #include <unistd.h>
> >  #include <sys/time.h>
> 
> As for tst-sem13.c, I think it would be good to adapt to libsupport.

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

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

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

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

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

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

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

   TIMEVAL_TO_TIMESPEC (&tv, &ts);

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

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

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

-  if (ts2.tv_sec < ts.tv_sec
-      || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec < ts.tv_nsec))
-    {
-      puts ("timeout too short");
-      return 1;
-    }
+  TEST_VERIFY (ts2.tv_sec > ts.tv_sec
+               || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec > ts.tv_nsec));

   return 0;
 }

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

Thanks.

Mike.
Yann Droneaud March 14, 2019, 2:09 p.m. UTC | #4
Hi,

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

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

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

Why is it only added to linux x86_64 ?

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

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

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

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

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

I think you can just simplify to:

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

LGTM, thanks.


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

Patch
diff mbox series

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