Update.
authorUlrich Drepper <drepper@redhat.com>
Thu, 2 Jan 2003 11:01:30 +0000 (11:01 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 2 Jan 2003 11:01:30 +0000 (11:01 +0000)
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.

19 files changed:
linuxthreads/ChangeLog
linuxthreads/Versions
linuxthreads/condvar.c
linuxthreads/sysdeps/pthread/bits/pthreadtypes.h
nptl/ChangeLog
nptl/DESIGN-condvar.txt
nptl/Makefile
nptl/Versions
nptl/old_pthread_cond_broadcast.c [new file with mode: 0644]
nptl/old_pthread_cond_destroy.c [new file with mode: 0644]
nptl/old_pthread_cond_init.c [new file with mode: 0644]
nptl/old_pthread_cond_signal.c [new file with mode: 0644]
nptl/old_pthread_cond_timedwait.c [new file with mode: 0644]
nptl/old_pthread_cond_wait.c [new file with mode: 0644]
nptl/pthreadP.h
nptl/pthread_cond_destroy.c
nptl/pthread_cond_init.c
nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S

index 20ee770..a667e22 100644 (file)
@@ -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
index cf7f340..8dd40ee 100644 (file)
@@ -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;
index a40ae49..6ab95b8 100644 (file)
@@ -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)
 {
index 3ee5c48..43d4f7d 100644 (file)
@@ -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;
 
 
index 764ab23..ec44dff 100644 (file)
@@ -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
index 303807b..749180e 100644 (file)
@@ -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.
index f1aaf48..274b1b2 100644 (file)
@@ -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 \
index b9de74a..26655f3 100644 (file)
@@ -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 (file)
index 0000000..9d63af9
--- /dev/null
@@ -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 (file)
index 0000000..9afe7d3
--- /dev/null
@@ -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 (file)
index 0000000..70275d9
--- /dev/null
@@ -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 (file)
index 0000000..467812e
--- /dev/null
@@ -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 (file)
index 0000000..6f84434
--- /dev/null
@@ -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 (file)
index 0000000..4a7282f
--- /dev/null
@@ -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
index eb5c6d4..e4a9013 100644 (file)
@@ -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)
index 750cd0c..130cb21 100644 (file)
@@ -17,7 +17,6 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-#include <errno.h>
 #include "pthreadP.h"
 
 
index 2b782c2..cd762f2 100644 (file)
@@ -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;
 }
index dbd477c..97b94a3 100644 (file)
@@ -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
index e8c8d5d..1cbf2ea 100644 (file)
@@ -18,8 +18,7 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
-
-       .text
+#include <shlib-compat.h>
 
 #ifdef UP
 # define LOCK
 #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