[glibc] Take mutex in cleanup only if it is not already taken (pr#14652)

Siddhesh Poyarekar siddhesh at fedoraproject.org
Thu Oct 4 06:30:00 UTC 2012


commit 080a305bf212ac02d501388c2f5e9f7fae4a2c24
Author: Siddhesh Poyarekar <siddhesh.poyarekar at gmail.com>
Date:   Thu Oct 4 11:57:51 2012 +0530

    Take mutex in cleanup only if it is not already taken (pr#14652)

 glibc-rh552960-2.patch |  443 ++++++++++++++++++++++++++++++++++++++++++++++++
 glibc.spec             |   11 +-
 2 files changed, 452 insertions(+), 2 deletions(-)
---
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 at 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
++   <http://www.gnu.org/licenses/>.  */
++
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/syscall.h>
++#include <unistd.h>
++#include <sys/time.h>
++#include <time.h>
++
++#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 <law at redhat.com> - 2.16.90-20
+* Thu Oct 4 2012 Siddhesh Poyarekar <siddhesh at redhat.com> - 2.16.90-21
+  - Take mutex in cleanup only if it is not already taken.
+
+* Tue Oct 2 2012 Jeff Law <law at redhat.com> - 2.16.90-20
   - Resync with upstream sources.
   - Repack patchlist.
 


More information about the scm-commits mailing list