diff --git a/glibc-rh552960-2.patch b/glibc-rh552960-2.patch
new file mode 100644
index 0000000..79842d5
--- /dev/null
+++ b/glibc-rh552960-2.patch
@@ -0,0 +1,443 @@
+diff --git a/nptl/Makefile b/nptl/Makefile
+index f21276c..de324fa 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -206,7 +206,8 @@ tests = tst-typesizes \
+ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
+ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
+ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
+- tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond-except \
++ tst-cond20 tst-cond21 tst-cond22 tst-cond23 tst-cond24 tst-cond25 \
++ tst-cond-except \
+ tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \
+ tst-robust6 tst-robust7 tst-robust8 tst-robust9 \
+ tst-robustpi1 tst-robustpi2 tst-robustpi3 tst-robustpi4 tst-robustpi5 \
+@@ -276,6 +276,7 @@ gen-as-const-headers = pthread-errnos.sym
+ LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
+
+ LDFLAGS-tst-cond24 = -lrt
++LDFLAGS-tst-cond25 = -lrt
+
+ include ../Makeconfig
+
+diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+index 6761c13..884987c 100644
+--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
++++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+@@ -649,10 +649,24 @@ __condvar_tw_cleanup:
+ movl $0x7fffffff, %edx
+ ENTER_KERNEL
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movl 24+FRAME_SIZE(%esp), %eax
+- call __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%eax), %ebx
++ andl $(ROBUST_BIT|PI_BIT), %ebx
++ cmpl $PI_BIT, %ebx
++ jne 8f
++
++ movl (%eax), %ebx
++ andl $TID_MASK, %ebx
++ cmpl %ebx, %gs:TID
++ je 9f
++
++8: call __pthread_mutex_cond_lock
+
+- movl %esi, (%esp)
++9: movl %esi, (%esp)
+ .LcallUR:
+ call _Unwind_Resume
+ hlt
+diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+index 0af06ac..bf1e5fe 100644
+--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
++++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
+@@ -566,10 +566,24 @@ __condvar_w_cleanup:
+ movl $0x7fffffff, %edx
+ ENTER_KERNEL
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movl 24+FRAME_SIZE(%esp), %eax
+- call __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%eax), %ebx
++ andl $(ROBUST_BIT|PI_BIT), %ebx
++ cmpl $PI_BIT, %ebx
++ jne 8f
++
++ movl (%eax), %ebx
++ andl $TID_MASK, %ebx
++ cmpl %ebx, %gs:TID
++ je 9f
++
++8: call __pthread_mutex_cond_lock
+
+- movl %esi, (%esp)
++9: movl %esi, (%esp)
+ .LcallUR:
+ call _Unwind_Resume
+ hlt
+diff --git a/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym b/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
+index 46fbd0d..0ac51db 100644
+--- a/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
++++ b/nptl/sysdeps/unix/sysv/linux/pthread-pi-defines.sym
+@@ -6,3 +6,4 @@ MUTEX_KIND offsetof (pthread_mutex_t, __data.__kind)
+ ROBUST_BIT PTHREAD_MUTEX_ROBUST_NORMAL_NP
+ PI_BIT PTHREAD_MUTEX_PRIO_INHERIT_NP
+ PS_BIT PTHREAD_MUTEX_PSHARED_BIT
++TID_MASK FUTEX_TID_MASK
+diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+index b669abb..eb13326 100644
+--- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
++++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+@@ -771,10 +771,24 @@ __condvar_cleanup2:
+ movl $SYS_futex, %eax
+ syscall
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movq 16(%rsp), %rdi
+- callq __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%rdi), %eax
++ andl $(ROBUST_BIT|PI_BIT), %eax
++ cmpl $PI_BIT, %eax
++ jne 7f
++
++ movl (%rdi), %eax
++ andl $TID_MASK, %eax
++ cmpl %eax, %fs:TID
++ je 8f
++
++7: callq __pthread_mutex_cond_lock
+
+- movq 24(%rsp), %rdi
++8: movq 24(%rsp), %rdi
+ movq FRAME_SIZE(%rsp), %r15
+ movq FRAME_SIZE+8(%rsp), %r14
+ movq FRAME_SIZE+16(%rsp), %r13
+diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+index ec403cd..6c6dc0e 100644
+--- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
++++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
+@@ -495,10 +495,24 @@ __condvar_cleanup1:
+ movl $SYS_futex, %eax
+ syscall
+
++ /* Lock the mutex only if we don't own it already. This only happens
++ in case of PI mutexes, if we got cancelled after a successful
++ return of the futex syscall and before disabling async
++ cancellation. */
+ 5: movq 16(%rsp), %rdi
+- callq __pthread_mutex_cond_lock
++ movl MUTEX_KIND(%rdi), %eax
++ andl $(ROBUST_BIT|PI_BIT), %eax
++ cmpl $PI_BIT, %eax
++ jne 7f
++
++ movl (%rdi), %eax
++ andl $TID_MASK, %eax
++ cmpl %eax, %fs:TID
++ je 8f
++
++7: callq __pthread_mutex_cond_lock
+
+- movq 24(%rsp), %rdi
++8: movq 24(%rsp), %rdi
+ .LcallUR:
+ call _Unwind_Resume@PLT
+ hlt
+diff --git a/nptl/tst-cond25.c b/nptl/tst-cond25.c
+new file mode 100644
+index 0000000..4488e74
+--- /dev/null
++++ b/nptl/tst-cond25.c
+@@ -0,0 +1,282 @@
++/* Verify that condition variables synchronized by PI mutexes don't hang on
++ on cancellation.
++ Copyright (C) 2012 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ 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, see
++ . */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++#define NUM 5
++#define ITERS 10000
++#define COUNT 100
++
++typedef void *(*thr_func) (void *);
++
++pthread_mutex_t mutex;
++pthread_cond_t cond;
++
++void cleanup (void *u)
++{
++ /* pthread_cond_wait should always return with the mutex locked. */
++ if (pthread_mutex_unlock (&mutex))
++ abort ();
++}
++
++void *
++signaller (void *u)
++{
++ int i, ret = 0;
++ void *tret = NULL;
++
++ for (i = 0; i < ITERS; i++)
++ {
++ if ((ret = pthread_mutex_lock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("signaller:mutex_lock failed: %s\n", strerror (ret));
++ goto out;
++ }
++ if ((ret = pthread_cond_signal (&cond)) != 0)
++ {
++ tret = (void *)1;
++ printf ("signaller:signal failed: %s\n", strerror (ret));
++ goto unlock_out;
++ }
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("signaller:mutex_unlock failed: %s\n", strerror (ret));
++ goto out;
++ }
++ pthread_testcancel ();
++ }
++
++out:
++ return tret;
++
++unlock_out:
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret));
++ goto out;
++}
++
++void *
++waiter (void *u)
++{
++ int i, ret = 0;
++ void *tret = NULL;
++ int seq = (int)u;
++
++ for (i = 0; i < ITERS / NUM; i++)
++ {
++ if ((ret = pthread_mutex_lock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_push (cleanup, NULL);
++
++ if ((ret = pthread_cond_wait (&cond, &mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret));
++ goto unlock_out;
++ }
++
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_pop (0);
++ }
++
++out:
++ puts ("waiter tests done");
++ return tret;
++
++unlock_out:
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret));
++ goto out;
++}
++
++void *
++timed_waiter (void *u)
++{
++ int i, ret;
++ void *tret = NULL;
++ int seq = (int)u;
++
++ for (i = 0; i < ITERS / NUM; i++)
++ {
++ struct timespec ts;
++
++ if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0)
++ {
++ tret = (void *)1;
++ printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno));
++ goto out;
++ }
++ ts.tv_sec += 20;
++
++ if ((ret = pthread_mutex_lock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_push (cleanup, NULL);
++
++ /* We should not time out either. */
++ if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0)
++ {
++ tret = (void *)1;
++ printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret));
++ goto unlock_out;
++ }
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ {
++ tret = (void *)1;
++ printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret));
++ goto out;
++ }
++ pthread_cleanup_pop (0);
++ }
++
++out:
++ puts ("timed_waiter tests done");
++ return tret;
++
++unlock_out:
++ if ((ret = pthread_mutex_unlock (&mutex)) != 0)
++ printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret));
++ goto out;
++}
++
++int
++do_test_wait (thr_func f)
++{
++ pthread_t w[NUM];
++ pthread_t s;
++ pthread_mutexattr_t attr;
++ int i, j, ret = 0;
++ void *thr_ret;
++
++ for (i = 0; i < COUNT; i++)
++ {
++ if ((ret = pthread_mutexattr_init (&attr)) != 0)
++ {
++ printf ("mutexattr_init failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_mutexattr_setprotocol (&attr, PTHREAD_PRIO_INHERIT)) != 0)
++ {
++ printf ("mutexattr_setprotocol failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_cond_init (&cond, NULL)) != 0)
++ {
++ printf ("cond_init failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_mutex_init (&mutex, &attr)) != 0)
++ {
++ printf ("mutex_init failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ for (j = 0; j < NUM; j++)
++ if ((ret = pthread_create (&w[j], NULL, f, (void *)j)) != 0)
++ {
++ printf ("waiter[%d]: create failed: %s\n", j, strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0)
++ {
++ printf ("signaller: create failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ for (j = 0; j < NUM; j++)
++ {
++ if ((ret = pthread_cancel (w[j])) != 0)
++ {
++ printf ("waiter[%d]: cancel failed: %s\n", j, strerror (ret));
++ goto out;
++ }
++
++ if ((ret = pthread_join (w[j], &thr_ret)) != 0)
++ {
++ printf ("waiter[%d]: join failed: %s\n", j, strerror (ret));
++ goto out;
++ }
++
++ if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
++ {
++ ret = 1;
++ goto out;
++ }
++ }
++
++ /* The signalling thread could have ended before it was cancelled. */
++ pthread_cancel (s);
++
++ if ((ret = pthread_join (s, &thr_ret)) != 0)
++ {
++ printf ("signaller: join failed: %s\n", strerror (ret));
++ goto out;
++ }
++
++ if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED)
++ {
++ ret = 1;
++ goto out;
++ }
++ }
++
++out:
++ return ret;
++}
++
++int
++do_test (int argc, char **argv)
++{
++ int ret = do_test_wait (waiter);
++
++ if (ret)
++ return ret;
++
++ return do_test_wait (timed_waiter);
++}
++
++#define TIMEOUT 5
++#include "../test-skeleton.c"
diff --git a/glibc.spec b/glibc.spec
index a3e8bf6..46921cc 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -27,7 +27,7 @@
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
-Release: 20%{?dist}
+Release: 21%{?dist}
# GPLv2+ is used in a bunch of programs, LGPLv2+ is used for libraries.
# Things that are linked directly into dynamically linked programs
# and shared libraries (e.g. crt files, lib*_nonshared.a) have an additional
@@ -188,6 +188,9 @@ Patch2028: %{name}-rh767693-2.patch
# Upstream BZ 14417
Patch2061: %{name}-rh552960.patch
+# Upstream BZ 14652
+Patch2062: %{name}-rh552960-2.patch
+
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Obsoletes: glibc-profile < 2.4
Obsoletes: nss_db
@@ -472,6 +475,7 @@ package or when debugging this package.
%patch0059 -p1
%patch0060 -p1
%patch2061 -p1
+%patch2062 -p1
# On powerpc32, hp timing is only available in power4/power6
# libs, not in base, so pre-power4 dynamic linker is incompatible
@@ -1266,7 +1270,10 @@ rm -f *.filelist*
%endif
%changelog
-* Mon Oct 2 2012 Jeff Law - 2.16.90-20
+* Thu Oct 4 2012 Siddhesh Poyarekar - 2.16.90-21
+ - Take mutex in cleanup only if it is not already taken.
+
+* Tue Oct 2 2012 Jeff Law - 2.16.90-20
- Resync with upstream sources.
- Repack patchlist.