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]

Re: [RFCv4] Add pthread_cond_timedwaitonclock_np



On 22/06/2017 14:05, Mike Crowe wrote:
> C++11's std::condition_variable::wait_until specifies the clock to be used
> at the time of the wait and permits separate waits on the same condition
> variable instance using different clocks.
> 
> Unfortunately pthread_cond_timedwait always uses the clock that was
> specified (or defaulted) when pthread_cond_init was called. libstdc++'s
> current implementation converts all waits to
> std::chrono::system_clock (i.e. CLOCK_REALTIME) which can race against
> the system clock changing.
> 
> Let's invent a brand-new function pthread_cond_timedwaitonclock_np which
> accepts both the clock and the time point as parameters is straightforward
> and means that the C++11 standard behaviour can be implemented in libstdc++
> on Linux at least.
> 
> Earlier versions of this patch were proposed in 2015 but further progress
> stalled waiting for the assembly implementation of pthread_cond_timedwait.S
> to be removed by Torvald Riegel. This happened in
> ed19993b5b0d05d62cc883571519a67dae481a14.
> 
> See the following threads for previous versions and discussion:
> 
> * https://sourceware.org/ml/libc-alpha/2015-07/msg00193.html
> * https://sourceware.org/ml/libc-alpha/2015-08/msg00186.html
> * https://sourceware.org/ml/libc-alpha/2015-08/msg00230.html
> 
> Some of the abilist updates for other architectures appear to have gone
> missing during the rebase. If this change is reviewed favourably then I
> shall try to include them.

I think it is a reasonable addition, however I have some concerns if this
would just another bad discussed ABI to fix and specific issues that will
be replaced by another better or simple solution (as your last comment in
BZ#41861 [1]).  It also concerns that it was not brought to Austin Group
attention as suggested by Szabolcs [2].

Torvald, do you think a new API to specific a clock is a reasonable addition
for GLIBC? Rich, any thought about this new API (any possible musl inclusion
in nearby future in case of glibc acceptance)? Do you think we should
approach Austin Group first? The issue with C++ seems to a QoI one that is
currently defined afaik as implementation-defined, so it would be an
enhancement

The patch itself has some minor issues about formatting that I outlined
below.

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861
[2] https://sourceware.org/ml/libc-alpha/2015-07/msg00194.html

> 
> Signed-off-by: Mike Crowe <mac@mcrowe.com>
> ---
>  ChangeLog                                          |  48 +++++
>  manual/threads.texi                                |  21 +++
>  nptl/Makefile                                      |   4 +-
>  nptl/Versions                                      |   7 +
>  nptl/forward.c                                     |   5 +
>  nptl/nptl-init.c                                   |   1 +
>  nptl/pthreadP.h                                    |   4 +
>  nptl/pthread_cond_wait.c                           |  28 ++-
>  nptl/tst-cond11-onclock.c                          | 209 +++++++++++++++++++++
>  nptl/tst-cond5-onclock.c                           | 114 +++++++++++
>  sysdeps/nptl/pthread-functions.h                   |   4 +
>  sysdeps/nptl/pthread.h                             |  15 ++
>  sysdeps/unix/sysv/linux/arm/libc.abilist           |   1 +
>  sysdeps/unix/sysv/linux/arm/libpthread.abilist     |   1 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist          |   1 +
>  sysdeps/unix/sysv/linux/i386/libpthread.abilist    |   1 +
>  .../sysv/linux/m68k/coldfire/libpthread.abilist    |   1 +
>  .../unix/sysv/linux/m68k/m680x0/libpthread.abilist |   1 +
>  sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   1 +
>  .../unix/sysv/linux/x86_64/64/libpthread.abilist   |   2 +
>  sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   1 +
>  .../unix/sysv/linux/x86_64/x32/libpthread.abilist  |   1 +
>  22 files changed, 466 insertions(+), 5 deletions(-)
>  create mode 100644 nptl/tst-cond11-onclock.c
>  create mode 100644 nptl/tst-cond5-onclock.c
> 
> diff --git a/ChangeLog b/ChangeLog
> index 46a70ff7ce..385deb472f 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,51 @@
> +2017-06-22  Mike Crowe  <mac@mcrowe.com>
> +
> +	* sysdeps/nptl/pthread.h: Add pthread_cond_timedwaitonclock_np
> +	declaration
> +	* nptl/pthread_cond.c:
> +	(__pthread_cond_wait_common): Add clockid parameter to determine
> +	which clock to use.
> +	(__pthread_cond_wait): Add dummy clockid parameter when calling
> +	__pthread_cond_wait_common.
> +	(__pthread_cond_timedwait): Read default clock set during
> +	pthread_cond_init to supply as clockid parameter in call to
> +	__pthread_cond_wait_common.
> +	(__pthread_cond_timedwaitonclock_np): New function that supports
> +	specifying clock to use at call time rather than initialisation
> +	time.
> +	(pthread_cond_timdwaitonclock_np): Weak alias for
> +	__pthread_cond_timedwaitonclock_np
> +	* nptl/tst-cond5-onclock.c: New file to test
> +	pthread_cond_timedwaitonclock_np
> +	* nptl/tst-cond11-onclock.c: New file to test
> +	pthread_cond_timedwaitonclock_np
> +	* nptl/Makefile: Add tst-cond5-onclock and tst-cond11-onclock
> +	* nptl/Versions (GLIBC_2.26): Add pthread_cond_timedwaitonclock_np
> +	to both libc and libpthread
> +	* nptl/pthread_functions.h: Add
> +	ptr___pthread_cond_timedwaitonclock_np
> +	* nptl/forward.c (pthread_functions): Forward
> +	pthread_cond_timedwaitonclock_np from libc to libpthread3
> +	* nptl/nptl-init.c: Forwarding function initialisation for
> +	pthread_cond_timedwaitonclock_np
> +	* nptl/pthreadP.h (__pthread_cond_timedwait_np): Add
> +	* manual/threads.texi: Add documentation for
> +	pthread_cond_timedwaitonclock_np
> +	* sysdeps/unix/sysv/linux/aarch64/libc.abilist: Add
> +	pthread_cond_timedwaitonclock_np
> +	* sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/arm/libpthread.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/i386/libpthread.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise
> +	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist: Likewise
> +
>  2017-06-21  Florian Weimer  <fweimer@redhat.com>
>  
>  	* intl/loadmsgcat.c: Remove alloca support.
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 769d974d50..8b3652c859 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -124,6 +124,27 @@ The system does not have sufficient memory.
>  @end table
>  @end deftypefun
>  
> +@comment pthread.h
> +@comment GNU
> +@deftypefun int pthread_cond_timedwaitonclock_np (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 POSIX @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, @code{clockid} must be either @code{CLOCK_MONOTONIC}
> +or @code{CLOCK_REALTIME}. This variant is necessary in order to implement
> +C++11's @code{std::condition_variable::wait_until} method correctly.
> +@end deftypefun

I think we can't omit the C++11 requirement on manual.


> +
>  @c FIXME these are undocumented:
>  @c pthread_atfork
>  @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 853da72e74..8cf661dc64 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -235,8 +235,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
>  	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \
>  	tst-mutexpi9 \
>  	tst-spin1 tst-spin2 tst-spin3 tst-spin4 \
> -	tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
> -	tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
> +	tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond5-onclock tst-cond6 tst-cond7 \
> +	tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond11-onclock tst-cond12 tst-cond13 \

Line too long, split in multiple ones.

>  	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-cond-except \
> diff --git a/nptl/Versions b/nptl/Versions
> index 0ae5def464..1cf8c2fbad 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -28,6 +28,9 @@ libc {
>      pthread_cond_wait; pthread_cond_signal;
>      pthread_cond_broadcast; pthread_cond_timedwait;
>    }
> +  GLIBC_2.26 {
> +    pthread_cond_timedwaitonclock_np;
> +  }

The libc addition seems wrong, whhy this is required?

>    GLIBC_PRIVATE {
>      __libc_alloca_cutoff;
>      # Internal libc interface to libpthread
> @@ -265,6 +268,10 @@ libpthread {
>    GLIBC_2.22 {
>    }
>  
> +  GLIBC_2.26 {
> +    pthread_cond_timedwaitonclock_np;
> +  }
> +
>    GLIBC_PRIVATE {
>      __pthread_initialize_minimal;
>      __pthread_clock_gettime; __pthread_clock_settime;
> diff --git a/nptl/forward.c b/nptl/forward.c
> index ac96765f29..c5fcb2f066 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_timedwaitonclock_np,
> +	 (pthread_cond_t *cond, pthread_mutex_t *mutex, clockid_t clockid,
> +	  const struct timespec *abstime), (cond, mutex, clockid, abstime),
> +	 0)
> +weak_alias (__pthread_cond_timedwaitonclock_np, pthread_cond_timedwaitonclock_np);
>  
>  
>  FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
> diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
> index 29216077a2..b913515fe9 100644
> --- a/nptl/nptl-init.c
> +++ b/nptl/nptl-init.c
> @@ -106,6 +106,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_timedwaitonclock_np = __pthread_cond_timedwaitonclock_np,
>  # 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 7fc1e50f78..c7e7587479 100644
> --- a/nptl/pthreadP.h
> +++ b/nptl/pthreadP.h
> @@ -488,6 +488,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_timedwaitonclock_np (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 7812b94a3a..d0166b86d5 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;
> @@ -510,7 +511,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 +653,7 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
>  int__PTHREAD_COND_CLOCK_MONOTONIC_MASK
>  __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
>  {
> -  return __pthread_cond_wait_common (cond, mutex, NULL);
> +  return __pthread_cond_wait_common (cond, mutex, CLOCK_REALTIME, NULL);
>  }
>  

I would prefer to just use '0' and states clockid_t is unused due 'abstime' being NULL.

>  /* See __pthread_cond_wait_common.  */
> @@ -664,10 +665,31 @@ __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);
> +
> +  clockid_t clockid = ((cond->__data.__wrefs & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
> +  return __pthread_cond_wait_common (cond, mutex, clockid, abstime);
> +}

Line to long and I think it is required to state why a plain load to
__wrefs in this specific case is suffice for synchronization.  In fact
I think it would be better to just use a relaxed MO:

    /* 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 clock = (flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK)
                      ? CLOCK_MONOTONIC : CLOCK_REALTIME;
    return __pthread_cond_wait_common (cond, mutex, clock, abstime);

> +
> +/* See __pthread_cond_wait_common.  */
> +int
> +__pthread_cond_timedwaitonclock_np (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;
> +
> +  /* We only support CLOCK_REALTIME and CLOCK_MONOTONIC */
> +  if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
> +    return EINVAL;

I think we shold also add the test present on pthread_condattr_setclock
(Which will in fact turn to always 'true' due 'futex_supports_exact_relative_timeouts'
being always true in Linux) for consistency.

  /* If we do not support waiting using CLOCK_MONOTONIC, return an error.  */
  if (clock_id == CLOCK_MONOTONIC
      && !futex_supports_exact_relative_timeouts())
    return ENOTSUP;

> +
> +  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_timedwaitonclock_np, pthread_cond_timedwaitonclock_np);
> diff --git a/nptl/tst-cond11-onclock.c b/nptl/tst-cond11-onclock.c
> new file mode 100644
> index 0000000000..439cd404de
> --- /dev/null
> +++ b/nptl/tst-cond11-onclock.c
> @@ -0,0 +1,209 @@
> +/* Test pthread_cond_timedwaitonclock_np, based on tst-cond11.c
> +   Copyright (C) 2003-2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +   Contributed by Mike Crowe <mac@mcrowe.com>, 2015.
> +
> +   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>
> +
> +
> +#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0
> +static int
> +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 ("attr_clock = %d, wait_clock = %d\n", (int) attr_clock, (int) wait_clock);
> +
> +  if (pthread_condattr_init (&condattr) != 0)
> +    {
> +      puts ("condattr_init failed");
> +      return 1;
> +    }
> +
> +  if (pthread_condattr_setclock (&condattr, attr_clock) != 0)
> +    {
> +      puts ("condattr_setclock failed");
> +      return 1;
> +    }
> +
> +  clockid_t cl2;
> +  if (pthread_condattr_getclock (&condattr, &cl2) != 0)
> +    {
> +      puts ("condattr_getclock failed");
> +      return 1;
> +    }
> +  if (attr_clock != cl2)
> +    {
> +      printf ("condattr_getclock returned wrong value: %d, expected %d\n",
> +	      (int) cl2, (int) attr_clock);
> +      return 1;
> +    }
> +
> +  if (pthread_cond_init (&cond, &condattr) != 0)
> +    {
> +      puts ("cond_init failed");
> +      return 1;
> +    }
> +
> +  if (pthread_condattr_destroy (&condattr) != 0)
> +    {
> +      puts ("condattr_destroy failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutexattr_init (&mutattr) != 0)
> +    {
> +      puts ("mutexattr_init failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK) != 0)
> +    {
> +      puts ("mutexattr_settype failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutex_init (&mut, &mutattr) != 0)
> +    {
> +      puts ("mutex_init failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutexattr_destroy (&mutattr) != 0)
> +    {
> +      puts ("mutexattr_destroy failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutex_lock (&mut) != 0)
> +    {
> +      puts ("mutex_lock failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutex_lock (&mut) != EDEADLK)
> +    {
> +      puts ("2nd mutex_lock did not return EDEADLK");
> +      return 1;
> +    }
> +
> +  struct timespec ts;
> +  if (clock_gettime (wait_clock, &ts) != 0)
> +    {
> +      puts ("clock_gettime failed");
> +      return 1;
> +    }
> +
> +  /* Wait one second.  */
> +  ++ts.tv_sec;
> +
> +  int e = pthread_cond_timedwaitonclock_np (&cond, &mut, wait_clock, &ts);
> +  if (e == 0)
> +    {
> +      puts ("cond_timedwait succeeded");
> +      return 1;
> +    }
> +  else if (e != ETIMEDOUT)
> +    {
> +      puts ("cond_timedwait did not return ETIMEDOUT");
> +      return 1;
> +    }
> +
> +  struct timespec ts2;
> +  if (clock_gettime (wait_clock, &ts2) != 0)
> +    {
> +      puts ("second clock_gettime failed");
> +      return 1;
> +    }
> +
> +  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;
> +    }
> +
> +  if (pthread_mutex_unlock (&mut) != 0)
> +    {
> +      puts ("mutex_unlock failed");
> +      return 1;
> +    }
> +
> +  if (pthread_mutex_destroy (&mut) != 0)
> +    {
> +      puts ("mutex_destroy failed");
> +      return 1;
> +    }
> +
> +  if (pthread_cond_destroy (&cond) != 0)
> +    {
> +      puts ("cond_destroy failed");
> +      return 1;
> +    }
> +
> +  return 0;
> +}
> +#endif
> +
> +
> +static int
> +do_test (void)
> +{
> +#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1
> +
> +  puts ("_POSIX_CLOCK_SELECTION not supported, test skipped");
> +  return 0;
> +
> +#else
> +
> +  int res = run_test (CLOCK_REALTIME, CLOCK_REALTIME);
> +
> +# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
> +#  if _POSIX_MONOTONIC_CLOCK == 0
> +  int e = sysconf (_SC_MONOTONIC_CLOCK);
> +  if (e < 0)
> +    puts ("CLOCK_MONOTONIC not supported");
> +  else if (e == 0)
> +    {
> +      puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0");
> +      res = 1;
> +    }
> +  else
> +#  endif
> +    {
> +      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
> +
> +  return res;
> +#endif
> +}
> +
> +#define TIMEOUT 12
> +#define TEST_FUNCTION do_test ()
> +#include "../test-skeleton.c"

We create tests using libsupport now, support/README, support/README-testing.c
have some examples.  It is simplifies a lot the error reporting and code
on tests.

> diff --git a/nptl/tst-cond5-onclock.c b/nptl/tst-cond5-onclock.c
> new file mode 100644
> index 0000000000..adb3342781
> --- /dev/null
> +++ b/nptl/tst-cond5-onclock.c
> @@ -0,0 +1,114 @@
> +/* Test pthread_cond_timedwaitonclock_np, based on tst-cond5.c
> +   Copyright (C) 2002-2017 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +   Contributed by Mike Crowe <mac@mcrowe.com>, 2015.
> +
> +   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_onclock(clockid_t clockid)
> +{
> +  pthread_mutexattr_t ma;
> +  int err;
> +  struct timespec ts;
> +
> +  if (pthread_mutexattr_init (&ma) != 0)
> +    {
> +      puts ("mutexattr_init failed");
> +      exit (1);
> +    }
> +
> +  if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0)
> +    {
> +      puts ("mutexattr_settype failed");
> +      exit (1);
> +    }
> +
> +  if (pthread_mutex_init (&mut, &ma) != 0)
> +    {
> +      puts ("mutex_init failed");
> +      exit (1);
> +    }
> +
> +  /* Get the mutex.  */
> +  if (pthread_mutex_lock (&mut) != 0)
> +    {
> +      puts ("mutex_lock failed");
> +      exit (1);
> +    }
> +
> +  /* Waiting for the condition will fail.  But we want the timeout here.  */
> +  if (clock_gettime (clockid, &ts) != 0)
> +    {
> +      puts ("clock_gettime failed");
> +      exit (1);
> +    }
> +
> +  ts.tv_nsec += 500000000;
> +  if (ts.tv_nsec >= 1000000000)
> +    {
> +      ts.tv_nsec -= 1000000000;
> +      ++ts.tv_sec;
> +    }
> +  err = pthread_cond_timedwaitonclock_np (&cond, &mut, clockid, &ts);
> +  if (err == 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)
> +    {
> +      printf ("cond_timedwait returned with %s\n", strerror (err));
> +      exit (1);
> +    }
> +
> +  err = pthread_mutex_unlock (&mut);
> +  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_onclock(CLOCK_MONOTONIC);
> +  if (rc == 0)
> +    rc = do_test_onclock(CLOCK_REALTIME);
> +
> +  return rc;
> +}
> +
> +#define TEST_FUNCTION do_test ()
> +#include "../test-skeleton.c"
> diff --git a/sysdeps/nptl/pthread-functions.h b/sysdeps/nptl/pthread-functions.h
> index 4006fc6c25..8225fdbfca 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_timedwaitonclock_np) (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 632ea7bc36..e95df8f592 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -1003,6 +1003,21 @@ extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
>  				   const struct timespec *__restrict __abstime)
>       __nonnull ((1, 2, 3));
>  
> +#ifdef __USE_GNU
> +/* 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_timedwaitonclock_np (pthread_cond_t *__restrict __cond,
> +					     pthread_mutex_t *__restrict __mutex,
> +					     __clockid_t __clock_id,
> +					     const struct timespec *__restrict __abstime)
> +     __nonnull ((1, 2, 4));
> +#endif
> +
>  /* Functions for handling condition variable attributes.  */
>  
>  /* Initialize condition variable attribute ATTR.  */
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index d2a206a8df..b0ecb71d3b 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -101,6 +101,7 @@ GLIBC_2.25 strfroml F
>  GLIBC_2.26 GLIBC_2.26 A
>  GLIBC_2.26 preadv2 F
>  GLIBC_2.26 preadv64v2 F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.26 pwritev2 F
>  GLIBC_2.26 pwritev64v2 F
>  GLIBC_2.26 reallocarray F
> diff --git a/sysdeps/unix/sysv/linux/arm/libpthread.abilist b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
> index 91545c1542..32b3331c19 100644
> --- a/sysdeps/unix/sysv/linux/arm/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libpthread.abilist
> @@ -9,6 +9,7 @@ GLIBC_2.12 pthread_setname_np F
>  GLIBC_2.18 GLIBC_2.18 A
>  GLIBC_2.18 pthread_getattr_default_np F
>  GLIBC_2.18 pthread_setattr_default_np F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.4 GLIBC_2.4 A
>  GLIBC_2.4 _IO_flockfile F
>  GLIBC_2.4 _IO_ftrylockfile F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 2ff1998ac9..1bcf512fa1 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2023,6 +2023,7 @@ GLIBC_2.25 strfroml F
>  GLIBC_2.26 GLIBC_2.26 A
>  GLIBC_2.26 preadv2 F
>  GLIBC_2.26 preadv64v2 F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.26 pwritev2 F
>  GLIBC_2.26 pwritev64v2 F
>  GLIBC_2.26 reallocarray F
> diff --git a/sysdeps/unix/sysv/linux/i386/libpthread.abilist b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
> index 8f9c3254be..3ae0e37475 100644
> --- a/sysdeps/unix/sysv/linux/i386/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libpthread.abilist
> @@ -216,6 +216,7 @@ GLIBC_2.2.3 GLIBC_2.2.3 A
>  GLIBC_2.2.3 pthread_getattr_np F
>  GLIBC_2.2.6 GLIBC_2.2.6 A
>  GLIBC_2.2.6 __nanosleep F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.3.2 GLIBC_2.3.2 A
>  GLIBC_2.3.2 pthread_cond_broadcast F
>  GLIBC_2.3.2 pthread_cond_destroy F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> index 91545c1542..32b3331c19 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
> @@ -9,6 +9,7 @@ GLIBC_2.12 pthread_setname_np F
>  GLIBC_2.18 GLIBC_2.18 A
>  GLIBC_2.18 pthread_getattr_default_np F
>  GLIBC_2.18 pthread_setattr_default_np F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.4 GLIBC_2.4 A
>  GLIBC_2.4 _IO_flockfile F
>  GLIBC_2.4 _IO_ftrylockfile F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> index 8f9c3254be..3ae0e37475 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
> @@ -216,6 +216,7 @@ GLIBC_2.2.3 GLIBC_2.2.3 A
>  GLIBC_2.2.3 pthread_getattr_np F
>  GLIBC_2.2.6 GLIBC_2.2.6 A
>  GLIBC_2.2.6 __nanosleep F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.3.2 GLIBC_2.3.2 A
>  GLIBC_2.3.2 pthread_cond_broadcast F
>  GLIBC_2.3.2 pthread_cond_destroy F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 513524d932..13f13e04db 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -1864,6 +1864,7 @@ GLIBC_2.25 strfroml F
>  GLIBC_2.26 GLIBC_2.26 A
>  GLIBC_2.26 preadv2 F
>  GLIBC_2.26 preadv64v2 F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.26 pwritev2 F
>  GLIBC_2.26 pwritev64v2 F
>  GLIBC_2.26 reallocarray F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> index 85365c057c..accb1d8d6f 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
> @@ -203,6 +203,8 @@ GLIBC_2.2.5 waitpid F
>  GLIBC_2.2.5 write F
>  GLIBC_2.2.6 GLIBC_2.2.6 A
>  GLIBC_2.2.6 __nanosleep F
> +GLIBC_2.26 GLIBC_2.26 A
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.3.2 GLIBC_2.3.2 A
>  GLIBC_2.3.2 pthread_cond_broadcast F
>  GLIBC_2.3.2 pthread_cond_destroy F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 0c557e9f43..db930f6307 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2107,6 +2107,7 @@ GLIBC_2.25 strfroml F
>  GLIBC_2.26 GLIBC_2.26 A
>  GLIBC_2.26 preadv2 F
>  GLIBC_2.26 preadv64v2 F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
>  GLIBC_2.26 pwritev2 F
>  GLIBC_2.26 pwritev64v2 F
>  GLIBC_2.26 reallocarray F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> index 6cd0fc3487..d89762bd33 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
> @@ -224,3 +224,4 @@ GLIBC_2.16 write F
>  GLIBC_2.18 GLIBC_2.18 A
>  GLIBC_2.18 pthread_getattr_default_np F
>  GLIBC_2.18 pthread_setattr_default_np F
> +GLIBC_2.26 pthread_cond_timedwaitonclock_np F
> 


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