about summary refs log tree commit diff
path: root/nptl/pthread_cond_wait.c
diff options
context:
space:
mode:
authorMike Crowe <mac@mcrowe.com>2019-06-21 17:36:56 +0000
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-07-12 13:36:24 +0000
commitafe4de7d283ebd88157126c5494ce1796194c16e (patch)
tree8b170b34eee52377b2a13e9856dac3c888e721e7 /nptl/pthread_cond_wait.c
parent6615f77978bd12f06157fae8d4523b3ec475062b (diff)
downloadglibc-afe4de7d283ebd88157126c5494ce1796194c16e.tar.gz
glibc-afe4de7d283ebd88157126c5494ce1796194c16e.tar.xz
glibc-afe4de7d283ebd88157126c5494ce1796194c16e.zip
nptl: Add POSIX-proposed pthread_cond_clockwait
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
	* 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 when calling
	futex_abstimed_wait_cancelable 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.
	* sysdeps/mach/hurd/i386/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/aarch64/libpthread.abilist
	* (GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/alpha/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/arm/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/csky/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/hppa/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/i386/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/ia64/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/nios2/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/riscv/rv64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sh/libpthread.abilist (GLIBC_2.30):
	* Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libpthread.abilist
	(GLIBC_2.30): Likewise.
	* 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.
	* 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

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'nptl/pthread_cond_wait.c')
-rw-r--r--nptl/pthread_cond_wait.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
index 7385562f57..558f930cd2 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. */
+
   /* 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
@@ -511,10 +517,6 @@ __pthread_cond_wait_common (pthread_cond_t *cond, pthread_mutex_t *mutex,
 	        err = ETIMEDOUT;
 	      else
 		{
-		  const clockid_t clockid =
-		    ((flags & __PTHREAD_COND_CLOCK_MONOTONIC_MASK) != 0) ?
-		    CLOCK_MONOTONIC : CLOCK_REALTIME;
-
 		  err = futex_abstimed_wait_cancelable
                     (cond->__data.__g_signals + g, 0, clockid, abstime,
                      private);
@@ -632,7 +634,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.  */
@@ -644,10 +647,39 @@ __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);
+}
+
+/* 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;
+
+  if (!futex_abstimed_supported_clockid (clockid))
+    return EINVAL;
+
+  /* If we do not support waiting using CLOCK_MONOTONIC, return an error.  */
+  if (clockid == CLOCK_MONOTONIC
+      && !futex_supports_exact_relative_timeouts ())
+    return EINVAL;
+
+  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);