about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--linuxthreads/ChangeLog9
-rw-r--r--linuxthreads/Versions6
-rw-r--r--linuxthreads/condvar.c52
-rw-r--r--linuxthreads/sysdeps/pthread/bits/pthreadtypes.h2
-rw-r--r--nptl/ChangeLog25
-rw-r--r--nptl/DESIGN-condvar.txt101
-rw-r--r--nptl/Makefile5
-rw-r--r--nptl/Versions5
-rw-r--r--nptl/old_pthread_cond_broadcast.c46
-rw-r--r--nptl/old_pthread_cond_destroy.c37
-rw-r--r--nptl/old_pthread_cond_init.c43
-rw-r--r--nptl/old_pthread_cond_signal.c46
-rw-r--r--nptl/old_pthread_cond_timedwait.c48
-rw-r--r--nptl/old_pthread_cond_wait.c47
-rw-r--r--nptl/pthreadP.h11
-rw-r--r--nptl/pthread_cond_destroy.c1
-rw-r--r--nptl/pthread_cond_init.c5
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h10
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S625
19 files changed, 941 insertions, 183 deletions
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index 20ee770f8f..a667e22ede 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,12 @@
+2003-01-02  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/pthread/bits/pthreadtypes.h (pthread_cond_t): Add padding.
+	* condvar.c: Add symbol versioning.  The compatibility versions
+	are the same as the change in the interface does not effect this
+	implementation.
+	* Versions [libpthread]: Add definitions for new pthread_cond_*
+	interfaces for version GLIBC_2.3.2.
+
 2002-12-31  Ulrich Drepper  <drepper@redhat.com>
 
 	* sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for
diff --git a/linuxthreads/Versions b/linuxthreads/Versions
index cf7f340f77..8dd40eec28 100644
--- a/linuxthreads/Versions
+++ b/linuxthreads/Versions
@@ -156,6 +156,12 @@ libpthread {
     # Cancellation wrapper
     __nanosleep;
   }
+  GLIBC_2.3.2 {
+    # Changed pthread_cond_t.
+    pthread_cond_init; pthread_cond_destroy;
+    pthread_cond_wait; pthread_cond_timedwait;
+    pthread_cond_signal; pthread_cond_broadcast;
+  }
   GLIBC_PRIVATE {
     # Internal libc interface to libpthread
     __pthread_kill_other_threads_np;
diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c
index a40ae49fab..6ab95b88ae 100644
--- a/linuxthreads/condvar.c
+++ b/linuxthreads/condvar.c
@@ -24,6 +24,7 @@
 #include "spinlock.h"
 #include "queue.h"
 #include "restart.h"
+#include <shlib-compat.h>
 
 int __pthread_cond_init(pthread_cond_t *cond,
                         const pthread_condattr_t *cond_attr)
@@ -32,14 +33,26 @@ int __pthread_cond_init(pthread_cond_t *cond,
   cond->__c_waiting = NULL;
   return 0;
 }
-strong_alias (__pthread_cond_init, pthread_cond_init)
+versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init,
+		  GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_init, __old_pthread_cond_init)
+compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init,
+	       GLIBC_2_0);
+#endif
 
 int __pthread_cond_destroy(pthread_cond_t *cond)
 {
   if (cond->__c_waiting != NULL) return EBUSY;
   return 0;
 }
-strong_alias (__pthread_cond_destroy, pthread_cond_destroy)
+versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy,
+		  GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_destroy, __old_pthread_cond_destroy)
+compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy,
+	       GLIBC_2_0);
+#endif
 
 /* Function called by pthread_cancel to remove the thread from
    waiting on a condition variable queue. */
@@ -134,7 +147,13 @@ int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
   pthread_mutex_lock(mutex);
   return 0;
 }
-strong_alias (__pthread_cond_wait, pthread_cond_wait)
+versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+		  GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_wait, __old_pthread_cond_wait)
+compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait,
+	       GLIBC_2_0);
+#endif
 
 static int
 pthread_cond_timedwait_relative(pthread_cond_t *cond,
@@ -230,12 +249,19 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
   return 0;
 }
 
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
-                           const struct timespec * abstime)
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+			     const struct timespec * abstime)
 {
   /* Indirect call through pointer! */
   return pthread_cond_timedwait_relative(cond, mutex, abstime);
 }
+versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
+		  GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_timedwait, __old_pthread_cond_timedwait)
+compat_symbol (libpthread, __old_pthread_cond_timedwait,
+	       pthread_cond_timedwait, GLIBC_2_0);
+#endif
 
 int __pthread_cond_signal(pthread_cond_t *cond)
 {
@@ -251,7 +277,13 @@ int __pthread_cond_signal(pthread_cond_t *cond)
   }
   return 0;
 }
-strong_alias (__pthread_cond_signal, pthread_cond_signal)
+versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
+		  GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_signal, __old_pthread_cond_signal)
+compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal,
+	       GLIBC_2_0);
+#endif
 
 int __pthread_cond_broadcast(pthread_cond_t *cond)
 {
@@ -270,7 +302,13 @@ int __pthread_cond_broadcast(pthread_cond_t *cond)
   }
   return 0;
 }
-strong_alias (__pthread_cond_broadcast, pthread_cond_broadcast)
+versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
+		  GLIBC_2_3_2);
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+strong_alias (__pthread_cond_broadcast, __old_pthread_cond_broadcast)
+compat_symbol (libpthread, __old_pthread_cond_broadcast,
+	       pthread_cond_broadcast, GLIBC_2_0);
+#endif
 
 int __pthread_condattr_init(pthread_condattr_t *attr)
 {
diff --git a/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
index 3ee5c48134..43d4f7dc00 100644
--- a/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
+++ b/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
@@ -57,6 +57,8 @@ typedef struct
 {
   struct _pthread_fastlock __c_lock; /* Protect against concurrent access */
   _pthread_descr __c_waiting;        /* Threads waiting on this condition */
+  char __padding[48 - sizeof (struct _pthread_fastlock)
+		 - sizeof (_pthread_descr)];
 } pthread_cond_t;
 
 
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 764ab23cd9..ec44dffa21 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,28 @@
+2003-01-02  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t):
+	New, larger type definition.
+	* sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: New condvar
+	implementation.
+	* Versions [libpthread]: Add definitions for new pthread_cond_*
+	interfaces for version GLIBC_2.3.2.
+	* pthread_cond_init.c: Update initialization for new type definition.
+	* Makefile (libpthread-routines): Remove pthread_cond_wait,
+	pthread_cond_timedwait, pthread_cond_signal, and
+	pthread_cond_broadcast.  Add old_pthread_cond_init,
+	old_pthread_cond_destroy, old_pthread_cond_wait,
+	old_pthread_cond_timedwait, old_pthread_cond_signal, and
+	old_pthread_cond_broadcast.
+	* old_pthread_cond_broadcast.c: New file.
+	* old_pthread_cond_destroy.c: New file.
+	* old_pthread_cond_init.c: New file.
+	* old_pthread_cond_signal.c: New file.
+	* old_pthread_cond_timedwait.c: New file.
+	* old_pthread_cond_wait.c: New file.
+	* pthreadP.h: Add prototypes for the compatibility interfaces.
+
+	* pthread_cond_destroy.c: Don't include <errno.h>.
+
 2003-01-01  Ulrich Drepper  <drepper@redhat.com>
 
 	* sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Avoid
diff --git a/nptl/DESIGN-condvar.txt b/nptl/DESIGN-condvar.txt
index 303807be6d..749180ed4b 100644
--- a/nptl/DESIGN-condvar.txt
+++ b/nptl/DESIGN-condvar.txt
@@ -7,49 +7,78 @@ Conditional Variable pseudocode.
 
 struct pthread_cond_t {
 
-   unsigned int lock:
+   unsigned int cond_lock;
 
          internal mutex
 
-   unsigned int nr_wakers:
+   uint64_t total_seq;
 
-         number of threads signalled to be woken up.
+     Total number of threads using the conditional variable.
 
-   unsigned int nr_sleepers:
+   uint64_t wakeup_seq;
 
-         number of threads waiting for the cv.
+     sequence number for next wakeup.
+
+   uint64_t woken_seq;
+
+     sequence number of last woken thread.
 
 }
 
-#define ALL_THREADS (1 << (BITS_PER_LONG-1))
 
-cond_wait_timeout(cv, mutex, timeout):
+
+cleanup_handler(cv)
+{
+  lll_lock(cv->lock);
+
+  ++cv->wakeup_seq;
+  ++cv->woken_seq;
+
+  lll_unlock(cv->lock);
+}
+
+
+cond_timedwait(cv, mutex, timeout):
 {
    lll_lock(cv->lock);
    mutex_unlock(mutex);
 
-   cv->nr_sleepers++;
-   for (;;) {
+   cleanup_push
+
+   ++cv->total_seq;
+   val = seq =  cv->wakeup_seq;
+
+   while (1) {
+
+     lll_unlock(cv->lock);
+
+     enable_async
 
-       if (cv->nr_wakers) {
-           cv->nr_wakers--;
-           break;
-       }
-       val = cv->nr_wakers;
+     ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
 
-       lll_unlock(cv->lock);
+     restore_async
 
-       ret = FUTEX WAIT (cv->nr_wakers, val, timeout)
+     lll_lock(cv->lock);
 
-       lll_lock(cv->lock);
+     val = cv->wakeup_seq;
 
-       if (ret == TIMEOUT)
-         break;
+     if (cv->woken_seq >= seq && cv->woken_seq < val) {
        ret = 0;
+       break;
+     }
+
+     if (ret == TIMEDOUT) {
+       ++cv->wakeup_seq;
+       break;
+     }
    }
-   if (!--cv->nr_sleepers)
-     cv->nr_wakers = 0; /* no memory of wakeups */
+
+   ++cv->woken_seq;
+
    lll_unlock(cv->lock);
+
+   cleanup_pop
+
    mutex_lock(mutex);
 
    return ret;
@@ -57,34 +86,24 @@ cond_wait_timeout(cv, mutex, timeout):
 
 cond_signal(cv)
 {
-   int do_wakeup = 0;
-
    lll_lock(cv->lock);
-   if (cv->nr_sleepers) {
-     if (!++cv->nr_wakers) /* overflow detection for the nutcase */
-       cv->nr_wakers = ALL_THREADS;
-     do_wakeup = 1;
+
+   if (cv->total_seq > cv->wakeup_seq) {
+     ++cv->wakeup_seq;
+     FUTEX_WAKE(cv->wakeup_seq, 1);
    }
+
    lll_unlock(cv->lock);
-   if (do_wakeup)
-     FUTEX WAKE (cv->nr_wakers, 1)
 }
 
 cond_broadcast(cv)
 {
-   int do_wakeup = 0;
-
    lll_lock(cv->lock);
-   if (cv->nr_sleepers) {
-     cv->nr_wakers |= ALL_THREADS;
-     do_wakeup = 1;
+
+   if (cv->total_seq > cv->wakeup_seq) {
+     cv->wakeup_seq = cv->total_seq;
+     FUTEX_WAKE(cv->wakeup_seq, ALL);
    }
+
    lll_unlock(cv->lock);
-   if (do_wakeup)
-     FUTEX WAKE (cv->nr_wakers, ALL_THREADS);
 }
-
-weaknesses of the implementation:
-
- it might generate spurious wakeups in the broadcast case, but those are
- allowed by POSIX.
diff --git a/nptl/Makefile b/nptl/Makefile
index f1aaf48475..274b1b2930 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -65,8 +65,9 @@ libpthread-routines = init events \
 		      pthread_rwlockattr_getkind_np \
 		      pthread_rwlockattr_setkind_np \
 		      pthread_cond_init pthread_cond_destroy \
-		      pthread_cond_wait pthread_cond_timedwait \
-		      pthread_cond_signal pthread_cond_broadcast \
+		      old_pthread_cond_init old_pthread_cond_destroy \
+		      old_pthread_cond_wait old_pthread_cond_timedwait \
+		      old_pthread_cond_signal old_pthread_cond_broadcast \
 		      pthread_condattr_init pthread_condattr_destroy \
 		      pthread_condattr_getpshared pthread_condattr_setpshared \
 		      pthread_spin_init pthread_spin_destroy \
diff --git a/nptl/Versions b/nptl/Versions
index b9de74afd9..26655f37c1 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -186,6 +186,11 @@ libpthread {
   }
 
   GLIBC_2.3.2 {
+    # Changed pthread_cond_t.
+    pthread_cond_init; pthread_cond_destroy;
+    pthread_cond_wait; pthread_cond_timedwait;
+    pthread_cond_signal; pthread_cond_broadcast;
+
     # Proposed API extensions.
     # XXX Adjust number for final release.
     pthread_tryjoin_np; pthread_timedjoin_np;
diff --git a/nptl/old_pthread_cond_broadcast.c b/nptl/old_pthread_cond_broadcast.c
new file mode 100644
index 0000000000..9d63af9a1d
--- /dev/null
+++ b/nptl/old_pthread_cond_broadcast.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+int
+__old_pthread_cond_broadcast (cond)
+     pthread_cond_t *cond;
+{
+  pthread_cond_t **realp = (pthread_cond_t **) cond;
+
+  if (*realp == NULL)
+    {
+      *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
+      if (*realp == NULL)
+	return ENOMEM;
+
+      **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER;
+    }
+
+  return __pthread_cond_broadcast (*realp);
+}
+compat_symbol (libpthread, __old_pthread_cond_broadcast,
+	       pthread_cond_broadcast, GLIBC_2_0);
+#endif
diff --git a/nptl/old_pthread_cond_destroy.c b/nptl/old_pthread_cond_destroy.c
new file mode 100644
index 0000000000..9afe7d323b
--- /dev/null
+++ b/nptl/old_pthread_cond_destroy.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+int
+__old_pthread_cond_destroy (cond)
+     pthread_cond_t *cond;
+{
+  /* Free the memory which was eventually allocated.  */
+  free (*(void **) cond);
+
+  return 0;
+}
+compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy,
+	       GLIBC_2_0);
+#endif
diff --git a/nptl/old_pthread_cond_init.c b/nptl/old_pthread_cond_init.c
new file mode 100644
index 0000000000..70275d94df
--- /dev/null
+++ b/nptl/old_pthread_cond_init.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+int
+__old_pthread_cond_init (cond, cond_attr)
+     pthread_cond_t *cond;
+     const pthread_condattr_t *cond_attr;
+{
+  /* Note that we don't need the COND-ATTR.  It contains only the
+     PSHARED flag which is unimportant here since conditional
+     variables are always usable in multiple processes.  */
+
+  /* The type of the first argument is actually that of the old, too
+     small pthread_cond_t.  We use only the first word of it, as a
+     pointer.  */
+  *((void **) cond) = NULL;
+
+  return 0;
+}
+compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init,
+	       GLIBC_2_0);
+#endif
diff --git a/nptl/old_pthread_cond_signal.c b/nptl/old_pthread_cond_signal.c
new file mode 100644
index 0000000000..467812eb4b
--- /dev/null
+++ b/nptl/old_pthread_cond_signal.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+int
+__old_pthread_cond_signal (cond)
+     pthread_cond_t *cond;
+{
+  pthread_cond_t **realp = (pthread_cond_t **) cond;
+
+  if (*realp == NULL)
+    {
+      *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
+      if (*realp == NULL)
+	return ENOMEM;
+
+      **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER;
+    }
+
+  return __pthread_cond_signal (*realp);
+}
+compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal,
+	       GLIBC_2_0);
+#endif
diff --git a/nptl/old_pthread_cond_timedwait.c b/nptl/old_pthread_cond_timedwait.c
new file mode 100644
index 0000000000..6f844346fd
--- /dev/null
+++ b/nptl/old_pthread_cond_timedwait.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+int
+__old_pthread_cond_timedwait (cond, mutex, abstime)
+     pthread_cond_t *cond;
+     pthread_mutex_t *mutex;
+     const struct timespec *abstime;
+{
+  pthread_cond_t **realp = (pthread_cond_t **) cond;
+
+  if (*realp == NULL)
+    {
+      *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
+      if (*realp == NULL)
+	return ENOMEM;
+
+      **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER;
+    }
+
+  return __pthread_cond_timedwait (*realp, mutex, abstime);
+}
+compat_symbol (libpthread, __old_pthread_cond_timedwait,
+	       pthread_cond_timedwait, GLIBC_2_0);
+#endif
diff --git a/nptl/old_pthread_cond_wait.c b/nptl/old_pthread_cond_wait.c
new file mode 100644
index 0000000000..4a7282f15f
--- /dev/null
+++ b/nptl/old_pthread_cond_wait.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+#include <shlib-compat.h>
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+int
+__old_pthread_cond_wait (cond, mutex)
+     pthread_cond_t *cond;
+     pthread_mutex_t *mutex;
+{
+  pthread_cond_t **realp = (pthread_cond_t **) cond;
+
+  if (*realp == NULL)
+    {
+      *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
+      if (*realp == NULL)
+	return ENOMEM;
+
+      **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER;
+    }
+
+  return __pthread_cond_wait (*realp, mutex);
+}
+compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait,
+	       GLIBC_2_0);
+#endif
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index eb5c6d4106..e4a90131d9 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -315,6 +315,17 @@ extern int __pthread_enable_asynccancel (void) attribute_hidden;
 extern void __pthread_disable_asynccancel (int oldtype)
      internal_function attribute_hidden;
 
+extern int __old_pthread_cond_broadcast (pthread_cond_t *cond);
+extern int __old_pthread_cond_destroy (pthread_cond_t *cond);
+extern int __old_pthread_cond_init (pthread_cond_t *cond,
+				    const pthread_condattr_t *cond_attr);
+extern int __old_pthread_cond_signal (pthread_cond_t *cond);
+extern int __old_pthread_cond_timedwait (pthread_cond_t *cond,
+					 pthread_mutex_t *mutex,
+					 const struct timespec *abstime);
+extern int __old_pthread_cond_wait (pthread_cond_t *cond,
+				    pthread_mutex_t *mutex);
+
 /* The two functions are in libc.so and not exported.  */
 extern int __libc_enable_asynccancel (void) attribute_hidden;
 extern void __libc_disable_asynccancel (int oldtype)
diff --git a/nptl/pthread_cond_destroy.c b/nptl/pthread_cond_destroy.c
index 750cd0cd4c..130cb21402 100644
--- a/nptl/pthread_cond_destroy.c
+++ b/nptl/pthread_cond_destroy.c
@@ -17,7 +17,6 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <errno.h>
 #include "pthreadP.h"
 
 
diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c
index 2b782c2929..cd762f2222 100644
--- a/nptl/pthread_cond_init.c
+++ b/nptl/pthread_cond_init.c
@@ -30,8 +30,9 @@ __pthread_cond_init (cond, cond_attr)
      variables are always usable in multiple processes.  */
 
   cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER;
-  cond->__data.__nr_wakers = 0;
-  cond->__data.__nr_sleepers = 0;
+  cond->__data.__total_seq = 0;
+  cond->__data.__wakeup_seq = 0;
+  cond->__data.__woken_seq = 0;
 
   return 0;
 }
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
index dbd477cca0..97b94a3074 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -23,7 +23,8 @@
 #define __SIZEOF_PTHREAD_ATTR_T 36
 #define __SIZEOF_PTHREAD_MUTEX_T 24
 #define __SIZEOF_PTHREAD_MUTEXATTR_T 4
-#define __SIZEOF_PTHREAD_COND_T 12
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
 #define __SIZEOF_PTHREAD_CONDATTR_T 4
 #define __SIZEOF_PTHREAD_RWLOCK_T 32
 #define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
@@ -74,11 +75,12 @@ typedef union
   struct
   {
     int __lock;
-    unsigned int __nr_wakers;
-    unsigned int __nr_sleepers;
+    unsigned long long int __total_seq;
+    unsigned long long int __wakeup_seq;
+    unsigned long long int __woken_seq;
   } __data;
   char __size[__SIZEOF_PTHREAD_COND_T];
-  long int __align;
+  long long int __align;
 } pthread_cond_t;
 
 typedef union
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
index e8c8d5d200..1cbf2ea97a 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
@@ -18,8 +18,7 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
-
-	.text
+#include <shlib-compat.h>
 
 #ifdef UP
 # define LOCK
@@ -32,248 +31,622 @@
 #define FUTEX_WAIT		0
 #define FUTEX_WAKE		1
 
-#define EWOULDBLOCK		11
-#define EINVAL			22
 #define ETIMEDOUT		110
 
-#define cond_lock	 0
-#define cond_nr_wakers	 4
-#define cond_nr_sleepers 8
+#define cond_lock	0
+#define total_seq	4
+#define wakeup_seq	12
+#define woken_seq	20
+
 
+	.text
 
-	.global	__lll_cond_wait
-	.type	__lll_cond_wait,@function
-	.hidden	__lll_cond_wait
 	.align	16
-__lll_cond_wait:
+	.type	condvar_cleanup, @function
+condvar_cleanup:
+	pushl	%ebx
+	movl	4(%esp), %ebx
+#if cond_lock != 0
+	addl	$cond_lock, %ebx
+#endif
+
+	/* Get internal lock.  */
+	movl	$1, %eax
+	LOCK
+#if cond_lock == 0
+	xaddl	%eax, (%ebx)
+#else
+	xaddl	%eax, cond_lock(%ebx)
+#endif
+	testl	%eax, %eax
+	je	1f
+
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
+	call	__lll_mutex_lock_wait
+
+1:	addl	$1, wakeup_seq(%ebx)
+	adcl	$0, wakeup_seq+4(%ebx)
+
+	addl	$1, woken_seq(%ebx)
+	adcl	$0, woken_seq+4(%ebx)
+
+	LOCK
+	decl	(%ebx)
+	je	2f
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
+	call	__lll_mutex_unlock_wake
+
+2:	popl	%ebx
+	ret
+	.size	condvar_cleanup, .-condvar_cleanup
+
+
+/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)  */
+	.globl	__pthread_cond_wait
+	.type	__pthread_cond_wait, @function
+	.align	16
+__pthread_cond_wait:
+
+	pushl	%edi
 	pushl	%esi
 	pushl	%ebx
 
 	xorl	%esi, %esi
+	movl	16(%esp), %ebx
+#if cond_lock != 0
+	addl	$cond_lock, %ebx
+#endif
 
-	leal	cond_nr_wakers(%eax), %ebx
-
-4:	movl	(%ebx), %edx
-	testl	%edx, %edx
+	/* Get internal lock.  */
+	movl	$1, %eax
+	LOCK
+#if cond_lock == 0
+	xaddl	%eax, (%ebx)
+#else
+	xaddl	%eax, cond_lock(%ebx)
+#endif
+	testl	%eax, %eax
 	jne	1f
 
-	LOCK
-	decl	cond_lock-cond_nr_wakers(%ebx)
-	jne	2f
+	/* Unlock the mutex.  */
+2:	pushl	20(%esp)
+	call	__pthread_mutex_unlock_internal
+
+	addl	$1, total_seq(%ebx)
+	adcl	$0, total_seq+4(%ebx)
 
-3:	xorl	%ecx, %ecx
+	/* Install cancellation handler.  */
+#ifdef PIC
+	call	__i686.get_pc_thunk.cx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ecx
+	leal	condvar_cleanup@GOTOFF(%ecx), %eax
+#else
+	leal	condvar_cleanup, %eax
+#endif
+	subl	$24, %esp
+	leal	12(%esp), %edx
+	movl	%ebx, 8(%esp)
+	movl	%eax, 4(%esp)
+	movl	%edx, (%esp)
+	call	_GI_pthread_cleanup_push
+
+	/* Get and store current wakeup_seq value.  */
+	movl	wakeup_seq(%ebx), %edi
+	movl	wakeup_seq+4(%ebx), %edx
+	movl	%edi, (%esp)
+	movl	%edx, 4(%esp)
+
+	/* Unlock.  */
+8:	LOCK
+#if cond_lock == 0
+	decl	(%ebx)
+#else
+	decl	cond_lock(%ebx)
+#endif
+	jne	3f
+
+4:	call	__pthread_enable_asynccancel
+	movl	%eax, (%esp)
+
+	movl	%esi, %ecx	/* movl $FUTEX_WAIT, %ecx */
+	movl	%edi, %edx
+	addl	$wakeup_seq-cond_lock, %ebx
 	movl	$SYS_futex, %eax
 	ENTER_KERNEL
+	subl	$wakeup_seq-cond_lock, %ebx
+
+	call	__pthread_disable_asynccancel
 
+	/* Lock.  */
 	movl	$1, %eax
 	LOCK
-	xaddl	%eax, cond_lock-cond_nr_wakers(%ebx)
+#if cond_lock == 0
+	xaddl	%eax, (%ebx)
+#else
+	xaddl	%eax, cond_lock(%ebx)
+#endif
 	testl	%eax, %eax
-	je	4b
+	jne	5f
 
-	leal	cond_lock-cond_nr_wakers(%ebx), %ecx
-	/* Preserves %ebx, %edx, %edi, %esi.  */
-	call	__lll_mutex_lock_wait
-	jmp	4b
+6:	movl	woken_seq(%ebx), %eax
+	movl	woken_seq+4(%ebx), %ecx
+
+	movl	wakeup_seq(%ebx), %edi
+	movl	wakeup_seq+4(%ebx), %edx
 
-1:	decl	(%ebx)
+	cmpl	4(%esp), %ecx
+	ja	7f
+	jb	8b
+	cmpl	(%esp), %eax
+	jb	8b
+
+7:	cmpl	%ecx, %edx
+	ja	9f
+	jb	8b
+	cmp	%eax, %edi
+	jna	8b
+
+9:	addl	$1, woken_seq(%ebx)
+	adcl	$0, woken_seq+4(%ebx)
+
+	LOCK
+#if cond_lock == 0
+	decl	(%ebx)
+#else
+	decl	cond_lock(%ebx)
+#endif
+	jne	10f
+
+	/* Remove cancellation handler.  */
+11:	leal	12(%esp), %edx
+	movl	$0, 4(%esp)
+	movl	%edx, (%esp)
+	call	_GI_pthread_cleanup_pop
+
+	movl	48(%esp), %eax
+	movl	%eax, (%esp)
+	call	__pthread_mutex_lock_internal
+	addl	$28, %esp
 
 	popl	%ebx
 	popl	%esi
+	popl	%edi
+
+	/* We return the result of the mutex_lock operation.  */
 	ret
 
-2:	leal	cond_lock-cond_nr_wakers(%ebx), %eax
-	/* Preserves %ebx, %ecx, %edx, %edi, %esi.  */
+	/* Initial locking failed.  */
+1:
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
+	call	__lll_mutex_lock_wait
+	jmp	2b
+
+	/* Unlock in loop requires waekup.  */
+3:
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
+	call	__lll_mutex_unlock_wake
+	jmp	4b
+
+	/* Locking in loop failed.  */
+5:
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
+	call	__lll_mutex_lock_wait
+	jmp	6b
+
+	/* Unlock after loop requires waekup.  */
+10:
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
 	call	__lll_mutex_unlock_wake
-	jmp	3b
-	.size	__lll_cond_wait,.-__lll_cond_wait
+	jmp	11b
+	.size	__pthread_cond_wait, .-__pthread_cond_wait
+versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
+		  GLIBC_2_3_2)
 
 
-	.global	__lll_cond_timedwait
-	.type	__lll_cond_timedwait,@function
-	.hidden	__lll_cond_timedwait
+/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex,
+			       const struct timespec *abstime)  */
+	.globl	__pthread_cond_timedwait
+	.type	__pthread_cond_timedwait, @function
 	.align	16
-__lll_cond_timedwait:
-	/* Check for a valid timeout value.  */
-	cmpl	$1000000000, 4(%edx)
-	jae	1f
+__pthread_cond_timedwait:
 
 	pushl	%ebp
 	pushl	%edi
 	pushl	%esi
 	pushl	%ebx
 
-	/* Stack frame for the timespec and timeval structs.  */
-	subl	$8, %esp
+	movl	20(%esp), %ebx
+	movl	28(%esp), %ebp
+#if cond_lock != 0
+	addl	$cond_lock, %ebx
+#endif
 
-	leal	cond_nr_wakers(%eax), %ebp	/* cond */
-	movl	%edx, %edi			/* timeout */
+	/* Get internal lock.  */
+	movl	$1, %eax
+	LOCK
+#if cond_lock == 0
+	xaddl	%eax, (%ebx)
+#else
+	xaddl	%eax, cond_lock(%ebx)
+#endif
+	testl	%eax, %eax
+	jne	1f
 
-9:	movl	(%ebp), %esi
-	testl	%esi, %esi
-	jne	5f
+	/* Unlock the mutex.  */
+2:	pushl	24(%esp)
+	call	__pthread_mutex_unlock_internal
 
-	LOCK
-	decl	cond_lock-cond_nr_wakers(%ebp)
-	jne	6f
+	addl	$1, total_seq(%ebx)
+	adcl	$0, total_seq+4(%ebx)
+
+	/* Install cancellation handler.  */
+#ifdef PIC
+	call	__i686.get_pc_thunk.cx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ecx
+	leal	condvar_cleanup@GOTOFF(%ecx), %eax
+#else
+	leal	condvar_cleanup, %eax
+#endif
+	subl	$32, %esp
+	leal	16(%esp), %edx
+	movl	%ebx, 8(%esp)
+	movl	%eax, 4(%esp)
+	movl	%edx, (%esp)
+	call	_GI_pthread_cleanup_push
+
+	/* Get and store current wakeup_seq value.  */
+	movl	wakeup_seq(%ebx), %edi
+	movl	wakeup_seq+4(%ebx), %edx
+	movl	%edi, 12(%esp)
+	movl	%edx, 16(%esp)
+
+	/* Unlock.  */
+8:	LOCK
+#if cond_lock == 0
+	decl	(%ebx)
+#else
+	decl	cond_lock(%ebx)
+#endif
+	jne	3f
+
+4:	call	__pthread_enable_asynccancel
+	movl	%eax, (%esp)
 
-	/* Get current time.  */
-7:	movl	%esp, %ebx
+	/* Get the current time.  */
+	movl	%ebx, %edx
+	leal	4(%esp), %ebx
 	xorl	%ecx, %ecx
 	movl	$SYS_gettimeofday, %eax
 	ENTER_KERNEL
+	movl	%edx, %ebx
 
 	/* Compute relative timeout.  */
-	movl	4(%esp), %eax
+	movl	8(%esp), %eax
 	movl	$1000, %edx
 	mul	%edx		/* Milli seconds to nano seconds.  */
-	movl	(%edi), %ecx
-	movl	4(%edi), %edx
-	subl	(%esp), %ecx
+	movl	(%ebp), %ecx
+	movl	4(%ebp), %edx
+	subl	4(%esp), %ecx
 	subl	%eax, %edx
-	jns	3f
+	jns	12f
 	addl	$1000000000, %edx
 	decl	%ecx
-3:	testl	%ecx, %ecx
-	js	4f		/* Time is already up.  */
+12:	testl	%ecx, %ecx
+	js	13f
 
-	movl	%ecx, (%esp)	/* Store relative timeout.  */
-	movl	%edx, 4(%esp)
-	movl	%esi, %edx
-	movl	%esp, %esi
+	/* Store relative timeout.  */
+	movl	%ecx, 4(%esp)
+	movl	%edx, 8(%esp)
+	leal	4(%esp), %esi
 	xorl	%ecx, %ecx	/* movl $FUTEX_WAIT, %ecx */
-	movl	%ebp, %ebx
+	movl	%edi, %edx
+	addl	$wakeup_seq-cond_lock, %ebx
 	movl	$SYS_futex, %eax
 	ENTER_KERNEL
+	subl	$wakeup_seq-cond_lock, %ebx
+	movl	%eax, %esi
 
-	movl	%eax, %edx
+	call	__pthread_disable_asynccancel
 
+	/* Lock.  */
 	movl	$1, %eax
 	LOCK
-	xaddl	%eax, cond_lock-cond_nr_wakers(%ebp)
+#if cond_lock == 0
+	xaddl	%eax, (%ebx)
+#else
+	xaddl	%eax, cond_lock(%ebx)
+#endif
 	testl	%eax, %eax
-	jne	8f
+	jne	5f
+
+6:	movl	woken_seq(%ebx), %eax
+	movl	woken_seq+4(%ebx), %ecx
+
+	movl	wakeup_seq(%ebx), %edi
+	movl	wakeup_seq+4(%ebx), %edx
+
+	cmpl	16(%esp), %ecx
+	ja	7f
+	jb	15f
+	cmpl	12(%esp), %eax
+	jb	15f
+
+7:	cmpl	%ecx, %edx
+	ja	9f
+	jb	15f
+	cmp	%eax, %edi
+	ja	9f
+
+15:	cmpl	$-ETIMEDOUT, %esi
+	jne	8b
+
+13:	addl	$1, wakeup_seq(%ebx)
+	adcl	$0, wakeup_seq+4(%ebx)
+	movl	$ETIMEDOUT, %esi
+	jmp	14f
+
+9:	xorl	%esi, %esi
+14:	addl	$1, woken_seq(%ebx)
+	adcl	$0, woken_seq+4(%ebx)
+
+	LOCK
+#if cond_lock == 0
+	decl	(%ebx)
+#else
+	decl	cond_lock(%ebx)
+#endif
+	jne	10f
 
-	cmpl	$-ETIMEDOUT, %edx
-	jne	9b
+	/* Remove cancellation handler.  */
+11:	leal	20(%esp), %edx
+	movl	$0, 4(%esp)
+	movl	%edx, (%esp)
+	call	_GI_pthread_cleanup_pop
 
-4:	movl	$ETIMEDOUT, %eax
-	jmp	2f
+	movl	60(%esp), %ecx
+	movl	%ecx, (%esp)
+	call	__pthread_mutex_lock_internal
+	addl	$36, %esp
 
-5:	decl	(%ebp)
-	xorl	%eax, %eax
+	movl	%esi, %eax
 
-2:	addl	$8, %esp
 	popl	%ebx
 	popl	%esi
 	popl	%edi
 	popl	%ebp
+
+	/* We return the result of the mutex_lock operation.  */
 	ret
 
-6:	leal	cond_lock-cond_nr_wakers(%ebp), %eax
-	/* Preserves %ebx, %ecx, %edx, %edi, %esi.  */
+	/* Initial locking failed.  */
+1:
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
+	call	__lll_mutex_lock_wait
+	jmp	2b
+
+	/* Unlock in loop requires waekup.  */
+3:
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
 	call	__lll_mutex_unlock_wake
-	jmp	7b
+	jmp	4b
 
-8:	leal	cond_lock-cond_nr_wakers(%ebp), %ecx
-	/* Preserves %ebx, %edx, %edi, %esi.  */
+	/* Locking in loop failed.  */
+5:
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
 	call	__lll_mutex_lock_wait
-	jmp	5b
+	jmp	6b
 
-1:	movl	$EINVAL, %eax
-	ret
-	.size	__lll_cond_timedwait,.-__lll_cond_timedwait
+	/* Unlock after loop requires waekup.  */
+10:
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
+	call	__lll_mutex_unlock_wake
+	jmp	11b
+	.size	__pthread_cond_timedwait, .-__pthread_cond_timedwait
+versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
+		  GLIBC_2_3_2)
 
 
-	.global	__lll_cond_wake
-	.type	__lll_cond_wake,@function
-	.hidden	__lll_cond_wake
+	/* int pthread_cond_signal (pthread_cond_t *cond) */
+	.globl	__pthread_cond_signal
+	.type	__pthread_cond_signal, @function
 	.align	16
-__lll_cond_wake:
+__pthread_cond_signal:
+
 	pushl	%esi
 	pushl	%ebx
+#if cond_lock != 0
+	addl	$cond_lock, %ebx
+#endif
 
-	movl	%eax, %ebx
+	movl	12(%esp), %ebx
 
+	/* Get internal lock.  */
 	movl	$1, %eax
 	LOCK
-	xaddl	%eax, (%ebx)
+	xaddl	%eax, cond_lock(%ebx)
 	testl	%eax, %eax
 	jne	1f
 
-2:	leal	cond_nr_wakers(%ebx), %ebx
-	cmpl	$0, cond_nr_sleepers-cond_nr_wakers(%ebx)
-	je	3f
-
-	incl	(%ebx)
-	jz	5f
-
-6:	movl	$FUTEX_WAKE, %ecx
+2:	movl	total_seq+4(%ebx), %eax
+	movl	total_seq(%ebx), %ecx
+	cmpl	wakeup_seq+4(%ebx), %eax
+	ja	3f
+	jb	4f
+	cmpl	wakeup_seq(%ebx), %ecx
+	jbe	4f
+
+	/* Bump the wakeup number.  */
+3:	addl	$1, wakeup_seq(%ebx)
+	adcl	$0, wakeup_seq+4(%ebx)
+
+	/* Wake up one thread.  */
+	addl	$wakeup_seq-cond_lock, %ebx
+	movl	$FUTEX_WAKE, %ecx
 	xorl	%esi, %esi
-	movl	%ecx, %edx	/* movl $1, %edx */
 	movl	$SYS_futex, %eax
+	movl	%ecx, %edx	/* movl $1, %edx */
 	ENTER_KERNEL
 
-3:	LOCK
-	decl	cond_lock-cond_nr_wakers(%ebx)
-	je,pt	4f
+	subl	$wakeup_seq-cond_lock, %ebx
 
-	leal	cond_lock-cond_nr_wakers(%ebx), %eax
-	call	__lll_mutex_unlock_wake
+	/* Unlock.  */
+4:	LOCK
+	decl	cond_lock(%ebx)
+	jne	5f
 
-4:	popl	%ebx
+6:	xorl	%eax, %eax
+	popl	%ebx
 	popl	%esi
 	ret
 
-1:	movl	%ebx, %ecx
+	/* Initial locking failed.  */
+1:
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
 	call	__lll_mutex_lock_wait
 	jmp	2b
 
-5:	movl	$0x80000000, (%ebx)
+	/* Unlock in loop requires waekup.  */
+5:
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
+	call	__lll_mutex_unlock_wake
 	jmp	6b
-	.size	__lll_cond_wake,.-__lll_cond_wake
+	.size	__pthread_cond_signal, .-__pthread_cond_signal
+versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal,
+		  GLIBC_2_3_2)
 
 
-	.global	__lll_cond_broadcast
-	.type	__lll_cond_broadcast,@function
-	.hidden	__lll_cond_broadcast
+	/* int pthread_cond_broadcast (pthread_cond_t *cond) */
+	.globl	__pthread_cond_broadcast
+	.type	__pthread_cond_broadcast, @function
 	.align	16
-__lll_cond_broadcast:
+__pthread_cond_broadcast:
+
 	pushl	%esi
 	pushl	%ebx
 
-	movl	%eax, %ebx
-	movl	$0x8000000, %edx
+	movl	12(%esp), %ebx
+#if cond_lock != 0
+	addl	$cond_lock, %ebx
+#endif
 
+	/* Get internal lock.  */
 	movl	$1, %eax
 	LOCK
-	xaddl	%eax, (%ebx)
+	xaddl	%eax, cond_lock(%ebx)
 	testl	%eax, %eax
 	jne	1f
 
-2:	leal	cond_nr_wakers(%ebx), %ebx
-	cmpl	$0, cond_nr_sleepers-cond_nr_wakers(%ebx)
-	je	3f
-
-	orl	%edx, (%ebx)
-
-6:	movl	$FUTEX_WAKE, %ecx
+2:	movl	total_seq+4(%ebx), %eax
+	movl	total_seq(%ebx), %ecx
+	cmpl	wakeup_seq+4(%ebx), %eax
+	ja	3f
+	jb	4f
+	cmpl	wakeup_seq(%ebx), %ecx
+	jna	4f
+
+	/* Case all currently waiting threads to wake up.  */
+3:	movl	%ecx, wakeup_seq(%ebx)
+	movl	%eax, wakeup_seq+4(%ebx)
+
+	/* Wake up all threads.  */
+	addl	$wakeup_seq-cond_lock, %ebx
+	movl	$FUTEX_WAKE, %ecx
 	xorl	%esi, %esi
 	movl	$SYS_futex, %eax
+	movl	$0x7fffffff, %edx
 	ENTER_KERNEL
 
-3:	LOCK
-	decl	cond_lock-cond_nr_wakers(%ebx)
-	je,pt	4f
+	subl	$wakeup_seq-cond_lock, %ebx
 
-	leal	cond_lock-cond_nr_wakers(%ebx), %eax
-	call	__lll_mutex_unlock_wake
+	/* Unlock.  */
+4:	LOCK
+	decl	cond_lock(%ebx)
+	jne	5f
 
-4:	popl	%ebx
+6:	xorl	%eax, %eax
+	popl	%ebx
 	popl	%esi
 	ret
 
-1:	movl	%ebx, %ecx
+	/* Initial locking failed.  */
+1:
+#if cond_lock == 0
+	movl	%ebx, %ecx
+#else
+	leal	cond_lock(%ebx), %ecx
+#endif
 	call	__lll_mutex_lock_wait
 	jmp	2b
-	.size	__lll_cond_broadcast,.-__lll_cond_broadcast
+
+	/* Unlock in loop requires waekup.  */
+5:
+#if cond_lock == 0
+	movl	%ebx, %eax
+#else
+	leal	cond_lock(%ebx), %eax
+#endif
+	call	__lll_mutex_unlock_wake
+	jmp	6b
+	.size	__pthread_cond_broadcast, .-__pthread_cond_broadcast
+versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast,
+		  GLIBC_2_3_2)
+
+
+#ifdef PIC
+	.section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
+	.globl	__i686.get_pc_thunk.cx
+	.hidden	__i686.get_pc_thunk.cx
+	.type	__i686.get_pc_thunk.cx,@function
+__i686.get_pc_thunk.cx:
+	movl (%esp), %ecx;
+	ret
+	.size	__i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
+#endif