[BZ #163]
[platform/upstream/glibc.git] / nptl / sysdeps / pthread / pthread_cond_wait.c
index da94cc2..a05060a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
 
@@ -32,6 +32,7 @@ struct _condvar_cleanup_buffer
   int oldtype;
   pthread_cond_t *cond;
   pthread_mutex_t *mutex;
+  unsigned int bc_seq;
 };
 
 
@@ -45,10 +46,13 @@ __condvar_cleanup (void *arg)
   /* We are going to modify shared data.  */
   lll_mutex_lock (cbuffer->cond->__data.__lock);
 
-  /* This thread is not waiting anymore.  Adjust the sequence counters
-     appropriately.  */
-  ++cbuffer->cond->__data.__wakeup_seq;
-  ++cbuffer->cond->__data.__woken_seq;
+  if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
+    {
+      /* This thread is not waiting anymore.  Adjust the sequence counters
+        appropriately.  */
+      ++cbuffer->cond->__data.__wakeup_seq;
+      ++cbuffer->cond->__data.__woken_seq;
+    }
 
   /* We are done.  */
   lll_mutex_unlock (cbuffer->cond->__data.__lock);
@@ -82,8 +86,8 @@ __pthread_cond_wait (cond, mutex)
   lll_mutex_lock (cond->__data.__lock);
 
   /* Now we can release the mutex.  */
-  err = __pthread_mutex_unlock_internal (mutex);
-  if (err)
+  err = __pthread_mutex_unlock_usercnt (mutex, 0);
+  if (__builtin_expect (err, 0))
     {
       lll_mutex_unlock (cond->__data.__lock);
       return err;
@@ -93,8 +97,10 @@ __pthread_cond_wait (cond, mutex)
   ++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;
+     different address store this is a bad user bug.  Do not store
+     anything for pshared condvars.  */
+  if (cond->__data.__mutex != (void *) ~0l)
+    cond->__data.__mutex = mutex;
 
   /* Prepare structure passed to cancellation handler.  */
   cbuffer.cond = cond;
@@ -109,6 +115,8 @@ __pthread_cond_wait (cond, mutex)
   unsigned long long int val;
   unsigned long long int seq;
   val = seq = cond->__data.__wakeup_seq;
+  /* Remember the broadcast counter.  */
+  cbuffer.bc_seq = cond->__data.__broadcast_seq;
 
   /* The futex syscall operates on a 32-bit word.  That is fine, we
      just use the low 32 bits of the sequence counter.  */
@@ -135,17 +143,22 @@ __pthread_cond_wait (cond, mutex)
       /* Disable asynchronous cancellation.  */
       __pthread_disable_asynccancel (cbuffer.oldtype);
 
+      /* If a broadcast happened, we are done.  */
+      if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+       goto bc_out;
+
       /* We are going to look at shared data again, so get the lock.  */
       lll_mutex_lock (cond->__data.__lock);
 
       /* Check whether we are eligible for wakeup.  */
       val = cond->__data.__wakeup_seq;
     }
-  while (! (val > seq && cond->__data.__woken_seq < val));
+  while (val == seq || cond->__data.__woken_seq == val);
 
   /* Another thread woken up.  */
   ++cond->__data.__woken_seq;
 
+ bc_out:
   /* We are done with the condvar.  */
   lll_mutex_unlock (cond->__data.__lock);