about summary refs log tree commit diff
path: root/nptl/sysdeps/pthread
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/pthread')
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_broadcast.c12
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_signal.c21
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_timedwait.c8
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_wait.c11
4 files changed, 43 insertions, 9 deletions
diff --git a/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/nptl/sysdeps/pthread/pthread_cond_broadcast.c
index 1076fe3c50..f34f58cc99 100644
--- a/nptl/sysdeps/pthread/pthread_cond_broadcast.c
+++ b/nptl/sysdeps/pthread/pthread_cond_broadcast.c
@@ -25,6 +25,7 @@
 #include <pthreadP.h>
 
 #include <shlib-compat.h>
+#include <kernel-features.h>
 
 
 int
@@ -54,7 +55,16 @@ __pthread_cond_broadcast (cond)
 #endif
 
       /* Wake everybody.  */
-      lll_futex_wake (futex, INT_MAX);
+      pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
+      if (__builtin_expect (lll_futex_requeue (futex, 1, MAX_INT,
+					       &mut->__data.__lock) == -EINVAL,
+			    0))
+	{
+	  /* The requeue functionality is not available.  */
+#ifndef __ASSUME_FUTEX_REQUEUE
+	  lll_futex_wake (futex, MAX_INT);
+#endif
+	}
 
       /* That's all.  */
       return 0;
diff --git a/nptl/sysdeps/pthread/pthread_cond_signal.c b/nptl/sysdeps/pthread/pthread_cond_signal.c
index 1a035fe05f..b9d8af07b2 100644
--- a/nptl/sysdeps/pthread/pthread_cond_signal.c
+++ b/nptl/sysdeps/pthread/pthread_cond_signal.c
@@ -25,13 +25,15 @@
 #include <pthreadP.h>
 
 #include <shlib-compat.h>
+#include <kernel-features.h>
+
 
 int
 __pthread_cond_signal (cond)
      pthread_cond_t *cond;
 {
   /* Make sure we are alone.  */
-  lll_mutex_lock(cond->__data.__lock);
+  lll_mutex_lock (cond->__data.__lock);
 
   /* Are there any waiters to be woken?  */
   if (cond->__data.__total_seq > cond->__data.__wakeup_seq)
@@ -50,7 +52,22 @@ __pthread_cond_signal (cond)
 #endif
 
       /* Wake one.  */
-      lll_futex_wake (futex, 1);
+      int r = lll_futex_requeue (futex, 0, 1, &cond->__data.__lock);
+      if (__builtin_expect (r == -EINVAL, 0))
+	{
+	  /* The requeue functionality is not available.  */
+#ifndef __ASSUME_FUTEX_REQUEUE
+	  lll_futex_wake (futex, 1);
+#endif
+	}
+      else if (r != 0)
+	{
+	  /* We always have to make the syscall if requeue actually
+	     moved a thread.  */
+	  lll_mutex_unlock_force (cond->__data.__lock);
+
+	  return 0;
+	}
     }
 
   /* We are done.  */
diff --git a/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/nptl/sysdeps/pthread/pthread_cond_timedwait.c
index 23cf0acb99..4dd6f2e02a 100644
--- a/nptl/sysdeps/pthread/pthread_cond_timedwait.c
+++ b/nptl/sysdeps/pthread/pthread_cond_timedwait.c
@@ -66,6 +66,10 @@ __pthread_cond_timedwait (cond, mutex, abstime)
   /* We have one new user of the condvar.  */
   ++cond->__data.__total_seq;
 
+  /* Remember the mutex we are using here.  If there is already a
+     different address store this is a bad user bug.  */
+  cond->__data.__mutex = mutex;
+
   /* Prepare structure passed to cancellation handler.  */
   cbuffer.cond = cond;
   cbuffer.mutex = mutex;
@@ -145,7 +149,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
       lll_mutex_unlock (cond->__data.__lock);
 
       /* Enable asynchronous cancellation.  Required by the standard.  */
-      __pthread_enable_asynccancel_2 (&cbuffer.oldtype);
+      cbuffer.oldtype = __pthread_enable_asynccancel ();
 
       /* Wait until woken by signal or broadcast.  Note that we
 	 truncate the 'val' value to 32 bits.  */
@@ -184,7 +188,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
   __pthread_cleanup_pop (&buffer, 0);
 
   /* Get the mutex before returning.  */
-  err = __pthread_mutex_lock_internal (mutex);
+  err = __pthread_mutex_cond_lock (mutex);
 
   return err ?: result;
 }
diff --git a/nptl/sysdeps/pthread/pthread_cond_wait.c b/nptl/sysdeps/pthread/pthread_cond_wait.c
index 708566be03..da94cc2d6b 100644
--- a/nptl/sysdeps/pthread/pthread_cond_wait.c
+++ b/nptl/sysdeps/pthread/pthread_cond_wait.c
@@ -65,8 +65,7 @@ __condvar_cleanup (void *arg)
 
   /* Get the mutex before returning unless asynchronous cancellation
      is in effect.  */
-  if (!(cbuffer->oldtype & CANCELTYPE_BITMASK))
-    __pthread_mutex_lock_internal (cbuffer->mutex);
+  __pthread_mutex_cond_lock (cbuffer->mutex);
 }
 
 
@@ -93,6 +92,10 @@ __pthread_cond_wait (cond, mutex)
   /* We have one new user of the condvar.  */
   ++cond->__data.__total_seq;
 
+  /* Remember the mutex we are using here.  If there is already a
+     different address store this is a bad user bug.  */
+  cond->__data.__mutex = mutex;
+
   /* Prepare structure passed to cancellation handler.  */
   cbuffer.cond = cond;
   cbuffer.mutex = mutex;
@@ -123,7 +126,7 @@ __pthread_cond_wait (cond, mutex)
       lll_mutex_unlock (cond->__data.__lock);
 
       /* Enable asynchronous cancellation.  Required by the standard.  */
-      __pthread_enable_asynccancel_2 (&cbuffer.oldtype);
+      cbuffer.oldtype = __pthread_enable_asynccancel ();
 
       /* Wait until woken by signal or broadcast.  Note that we
 	 truncate the 'val' value to 32 bits.  */
@@ -150,7 +153,7 @@ __pthread_cond_wait (cond, mutex)
   __pthread_cleanup_pop (&buffer, 0);
 
   /* Get the mutex before returning.  */
-  return __pthread_mutex_lock_internal (mutex);
+  return __pthread_mutex_cond_lock (mutex);
 }
 
 versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,