[PATCH 3/7] nptl: Add POSIX-proposed pthread_cond_clockwait

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue Mar 5 16:45:00 GMT 2019



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

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

>    GLIBC_PRIVATE {
> diff --git a/nptl/forward.c b/nptl/forward.c
> index ed1e7d0..50f358f 100644
> --- a/nptl/forward.c
> +++ b/nptl/forward.c
> @@ -164,6 +164,11 @@ FORWARD (__pthread_cond_timedwait,
>  	  const struct timespec *abstime), (cond, mutex, abstime), 0)
>  versioned_symbol (libc, __pthread_cond_timedwait, pthread_cond_timedwait,
>  		  GLIBC_2_3_2);
> +FORWARD (__pthread_cond_clockwait,
> +	 (pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid,
> +	  const struct timespec *abstime), (cond, mutex, clockid, abstime),
> +	 0)
> +weak_alias (__pthread_cond_clockwait, pthread_cond_clockwait);
>  
>  
>  FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
> diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
> index b5895fa..c872b9f 100644
> --- a/nptl/nptl-init.c
> +++ b/nptl/nptl-init.c
> @@ -104,6 +104,7 @@ static const struct pthread_functions pthread_functions =
>      .ptr___pthread_cond_signal = __pthread_cond_signal,
>      .ptr___pthread_cond_wait = __pthread_cond_wait,
>      .ptr___pthread_cond_timedwait = __pthread_cond_timedwait,
> +    .ptr___pthread_cond_clockwait = __pthread_cond_clockwait,
>  # if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
>      .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
>      .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
> diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
> index 626bd4b..28c0ee5 100644
> --- a/nptl/pthreadP.h
> +++ b/nptl/pthreadP.h
> @@ -487,6 +487,10 @@ extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
>  extern int __pthread_cond_timedwait (pthread_cond_t *cond,
>  				     pthread_mutex_t *mutex,
>  				     const struct timespec *abstime);
> +extern int __pthread_cond_clockwait (pthread_cond_t *cond,
> +				     pthread_mutex_t *mutex,
> +				     clockid_t clockid,
> +				     const struct timespec *abstime);
>  extern int __pthread_condattr_destroy (pthread_condattr_t *attr);
>  extern int __pthread_condattr_init (pthread_condattr_t *attr);
>  extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *));
> diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
> index daa4e25..5deb54b 100644
> --- a/nptl/pthread_cond_wait.c
> +++ b/nptl/pthread_cond_wait.c
> @@ -378,6 +378,7 @@ __condvar_cleanup_waiting (void *arg)
>  */
>  static __always_inline int
>  __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
> +    clockid_t clockid,
>      const struct timespec *abstime)
>  {
>    const int maxspin = 0;
> @@ -386,6 +387,11 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>  
>    LIBC_PROBE (cond_wait, 2, cond, mutex);
>  
> +  /* clockid will already have been checked by
> +     __pthread_cond_clockwait or pthread_condattr_setclock, or we
> +     don't use it if abstime is NULL, so we don't need to check it
> +     here. */
> +

Ok.

>    /* Acquire a position (SEQ) in the waiter sequence (WSEQ).  We use an
>       atomic operation because signals and broadcasts may update the group
>       switch without acquiring the mutex.  We do not need release MO here
> @@ -510,7 +516,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>  	      if (__glibc_unlikely (abstime->tv_sec < 0))
>  	        err = ETIMEDOUT;
>  
> -	      else if ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0)
> +	      else if (clockid == CLOCK_MONOTONIC)
>  		{
>  		  /* CLOCK_MONOTONIC is requested.  */
>  		  struct timespec rt;
> @@ -652,7 +658,8 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>  int
>  __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
>  {
> -  return __pthread_cond_wait_common (cond, mutex, NULL);
> +  /* clockid is unused when abstime is NULL. */
> +  return __pthread_cond_wait_common (cond, mutex, 0, NULL);
>  }
>  
>  /* See __pthread_cond_wait_common.  */

Ok.

> @@ -664,10 +671,40 @@ __pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
>       it can assume that abstime is not NULL.  */
>    if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
>      return EINVAL;
> -  return __pthread_cond_wait_common (cond, mutex, abstime);
> +
> +  /* Relaxed MO is suffice because clock ID bit is only modified
> +     in condition creation.  */
> +  unsigned int flags = atomic_load_relaxed (&cond->__data.__wrefs);
> +  clockid_t clockid = (flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK)
> +                    ? CLOCK_MONOTONIC : CLOCK_REALTIME;
> +  return __pthread_cond_wait_common (cond, mutex, clockid, abstime);
> +}
> +

Ok.

> +/* See __pthread_cond_wait_common.  */
> +int
> +__pthread_cond_clockwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
> +			  clockid_t clockid,
> +			  const struct timespec *abstime)
> +{
> +  /* Check parameter validity.  This should also tell the compiler that
> +     it can assume that abstime is not NULL.  */
> +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
> +    return EINVAL;

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

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

Why not use lll_futex_supported_clockid here?

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

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

> +
> +  return __pthread_cond_wait_common (cond, mutex, clockid, abstime);
>  }
>  
>  versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
>  		  GLIBC_2_3_2);
>  versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
>  		  GLIBC_2_3_2);
> +weak_alias (__pthread_cond_clockwait, pthread_cond_clockwait);
> diff --git a/nptl/tst-cond11.c b/nptl/tst-cond11.c
> index 97a8bd0..4df6b15 100644
> --- a/nptl/tst-cond11.c
> +++ b/nptl/tst-cond11.c
> @@ -22,17 +22,20 @@
>  #include <time.h>
>  #include <unistd.h>
Not a requisite, but since you are touching the testcase it might a
good time to change it to use libsupport.

>  
> +/* A bogus clock value that tells run_test to use
> +   pthread_cond_timedwait rather than pthread_condclockwait. */
> +#define CLOCK_USE_ATTR_CLOCK (-1)
>  
>  #if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0
>  static int
> -run_test (clockid_t cl)
> +run_test (clockid_t attr_clock, clockid_t wait_clock)
>  {
>    pthread_condattr_t condattr;
>    pthread_cond_t cond;
>    pthread_mutexattr_t mutattr;
>    pthread_mutex_t mut;
>  
> -  printf ("clock = %d\n", (int) cl);
> +  printf ("attr_clock = %d\n", (int) attr_clock);
>  
>    if (pthread_condattr_init (&condattr) != 0)
>      {
> @@ -40,7 +43,7 @@ run_test (clockid_t cl)
>        return 1;
>      }
>  
> -  if (pthread_condattr_setclock (&condattr, cl) != 0)
> +  if (pthread_condattr_setclock (&condattr, attr_clock) != 0)
>      {
>        puts ("condattr_setclock failed");
>        return 1;
> @@ -52,10 +55,10 @@ run_test (clockid_t cl)
>        puts ("condattr_getclock failed");
>        return 1;
>      }
> -  if (cl != cl2)
> +  if (attr_clock != cl2)
>      {
>        printf ("condattr_getclock returned wrong value: %d, expected %d\n",
> -	      (int) cl2, (int) cl);
> +	      (int) cl2, (int) attr_clock);
>        return 1;
>      }
>  
> @@ -108,7 +111,7 @@ run_test (clockid_t cl)
>      }
>  
>    struct timespec ts;
> -  if (clock_gettime (cl, &ts) != 0)
> +  if (clock_gettime ((wait_clock == CLOCK_USE_ATTR_CLOCK) ? attr_clock : wait_clock, &ts) != 0)

Line too long.

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

Ditto.

>      {
>        puts ("second clock_gettime failed");
>        return 1;
> @@ -176,7 +181,7 @@ do_test (void)
>  
>  #else
>  
> -  int res = run_test (CLOCK_REALTIME);
> +  int res = run_test (CLOCK_REALTIME, CLOCK_USE_ATTR_CLOCK);
>  
>  # if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
>  #  if _POSIX_MONOTONIC_CLOCK == 0
> @@ -189,8 +194,13 @@ do_test (void)
>        res = 1;
>      }
>    else
> +    {
>  #  endif
> -    res |= run_test (CLOCK_MONOTONIC);
> +      res |= run_test (CLOCK_MONOTONIC, CLOCK_USE_ATTR_CLOCK);
> +      res |= run_test (CLOCK_REALTIME, CLOCK_MONOTONIC);
> +      res |= run_test (CLOCK_MONOTONIC, CLOCK_MONOTONIC);
> +      res |= run_test (CLOCK_MONOTONIC, CLOCK_REALTIME);
> +    }
>  # else
>    puts ("_POSIX_MONOTONIC_CLOCK not defined");
>  # endif
> diff --git a/nptl/tst-cond26.c b/nptl/tst-cond26.c
> new file mode 100644
> index 0000000..83b041d
> --- /dev/null
> +++ b/nptl/tst-cond26.c
> @@ -0,0 +1,91 @@
> +/* Test unsupported/bad clocks passed to pthread_cond_clockwait.
> +
> +   Copyright (C) 2019 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <time.h>
> +#include <unistd.h>
> +
> +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
> +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
> +
> +static int test_bad_clockid (clockid_t clockid)
> +{
> +  struct timespec ts = {0,0};
> +  int rc = pthread_cond_clockwait (&cond, &mut, clockid, &ts);

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

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

Use TEST_VERIFY (rc == 0);

> +  else if (rc != EINVAL)

Use TEST_COMPARE (rc, EINVAL).

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

Use xpthread_mutex_lock.

> +
> +  int rc = 0;
> +
> +  /* These clocks are meaningless to pthread_cond_clockwait. */
> +#if defined(CLOCK_PROCESS_CPUTIME_ID)
> +  rc |= test_bad_clockid (CLOCK_PROCESS_CPUTIME_ID);
> +#endif
> +#if defined(CLOCK_THREAD_CPUTIME_ID)
> +  rc |= test_bad_clockid (CLOCK_PROCESS_CPUTIME_ID);
> +#endif
> +
> +  /* These clocks might be meaningful, but are currently unsupported
> +     by pthread_cond_clockwait. */
> +#if defined(CLOCK_REALTIME_COARSE)
> +  rc |= test_bad_clockid (CLOCK_REALTIME_COARSE);
> +#endif
> +#if defined(CLOCK_MONOTONIC_RAW)
> +  rc |= test_bad_clockid (CLOCK_MONOTONIC_RAW);
> +#endif
> +#if defined(CLOCK_MONOTONIC_COARSE)
> +  rc |= test_bad_clockid (CLOCK_MONOTONIC_COARSE);
> +#endif
> +#if defined(CLOCK_BOOTTIME)
> +  rc |= test_bad_clockid (CLOCK_BOOTTIME);
> +#endif
> +
> +  /* This is a completely invalid clock. */
> +  rc |= test_bad_clockid (NOT_A_VALID_CLOCK);
> +
> +  return rc;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-cond27.c b/nptl/tst-cond27.c
> new file mode 100644
> index 0000000..efca7fd
> --- /dev/null
> +++ b/nptl/tst-cond27.c
> @@ -0,0 +1,113 @@
> +/* Test pthread_cond_clockwait, based on tst-cond5.c
> +
> +   Copyright (C) 2019 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <time.h>
> +#include <sys/time.h>
> +
> +
> +static pthread_mutex_t mut;
> +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
> +
> +
> +static int
> +do_test_clock (clockid_t clockid)
> +{
> +  pthread_mutexattr_t ma;
> +  int err;
> +  struct timespec ts;
> +
> +  if (pthread_mutexattr_init (&ma) != 0)
> +    {
> +      puts ("mutexattr_init failed");
> +      exit (1);
> +    }

Use xpthread_mutexattr_init.

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

Use xpthread_mutexattr_settype.

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

Use xpthread_mutex_init.

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

Use xpthread_mutex_lock.

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

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

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

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

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

Use TEST_COMPARE (err, ETIMEDOUT).

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

Use xpthread_mutex_unlock.

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

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

> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/nptl/pthread-functions.h b/sysdeps/nptl/pthread-functions.h
> index cd5e94d..cfa9660 100644
> --- a/sysdeps/nptl/pthread-functions.h
> +++ b/sysdeps/nptl/pthread-functions.h
> @@ -55,6 +55,10 @@ struct pthread_functions
>    int (*ptr___pthread_cond_wait) (pthread_cond_t *, pthread_mutex_t *);
>    int (*ptr___pthread_cond_timedwait) (pthread_cond_t *, pthread_mutex_t *,
>  				       const struct timespec *);
> +  int (*ptr___pthread_cond_clockwait) (pthread_cond_t *,
> +				       pthread_mutex_t *,
> +				       clockid_t,
> +				       const struct timespec *);
>    int (*ptr___pthread_cond_broadcast_2_0) (pthread_cond_2_0_t *);
>    int (*ptr___pthread_cond_destroy_2_0) (pthread_cond_2_0_t *);
>    int (*ptr___pthread_cond_init_2_0) (pthread_cond_2_0_t *,
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 704a3c4..d4fe9d9 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -1003,6 +1003,19 @@ extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
>  				   const struct timespec *__restrict __abstime)
>       __nonnull ((1, 2, 3));
>  
> +/* Wait for condition variable COND to be signaled or broadcast until
> +   ABSTIME measured by the specified clock. MUTEX is assumed to be
> +   locked before. CLOCK is the clock to use. ABSTIME is an absolute
> +   time specification against CLOCK's epoch.
> +
> +   This function is a cancellation point and therefore not marked with
> +   __THROW. */
> +extern int pthread_cond_clockwait (pthread_cond_t *__restrict __cond,
> +				   pthread_mutex_t *__restrict __mutex,
> +				   __clockid_t __clock_id,
> +				   const struct timespec *__restrict __abstime)
> +     __nonnull ((1, 2, 4));
> +
>  /* Functions for handling condition variable attributes.  */
>  
>  /* Initialize condition variable attribute ATTR.  */
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 454d340..aaa1c3b 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -245,6 +245,7 @@ GLIBC_2.3.4 pthread_attr_setaffinity_np F
>  GLIBC_2.3.4 pthread_getaffinity_np F
>  GLIBC_2.3.4 pthread_setaffinity_np F
>  GLIBC_2.3.4 pthread_setschedprio F
> +GLIBC_2.30 pthread_cond_clockwait F
>  GLIBC_2.30 sem_clockwait F
>  GLIBC_2.4 pthread_mutex_consistent_np F
>  GLIBC_2.4 pthread_mutex_getprioceiling F
> 



More information about the Libc-alpha mailing list