From 55a051c985c3e7965a2f5dd5f762ac2737adae01 Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Mon, 1 Oct 2012 23:20:42 +0530 Subject: Fix exception table for i386 pthread_cond_wait [BZ #14477] Add an additional entry in the exception table to jump to __condvar_w_cleanup2 instead of __condvar_w_cleanup for PI mutexes when %ebx contains the address of the futex instead of the condition variable. --- nptl/ChangeLog | 16 +++ nptl/Makefile | 2 +- .../sysv/linux/i386/i486/pthread_cond_timedwait.S | 12 ++- .../unix/sysv/linux/i386/i486/pthread_cond_wait.S | 12 ++- nptl/tst-cond-except.c | 108 +++++++++++++++++++++ 5 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 nptl/tst-cond-except.c (limited to 'nptl') diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 2176932501..7c673c0edb 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,19 @@ +2012-10-01 Siddhesh Poyarekar + + [BZ #14477] + * Makefile (tests): Add tst-cond-except. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S + (__pthread_cond_timedwait): Mark instructions where %ebx is + incremented in PI case. + (.gcc_except_table): Add entry to jump to __condvar_tw_cleanup2 + for the marked PI case instructions. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S + (__pthread_cond_wait): Mark instructions where %ebx is + incremented in PI case. + (.gcc_except_table): Add entry to jump to __condvar_w_cleanup2 + for the marked PI case instructions. + * tst-cond-except.c: New test case. + 2012-09-24 Dmitry V. Levin * tst-tls6.sh: Add "set -e". diff --git a/nptl/Makefile b/nptl/Makefile index b081b07955..b9c73b3898 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -206,7 +206,7 @@ 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-cond20 tst-cond21 tst-cond22 tst-cond23 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 \ 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 5f1fd5ddc6..d14d7deb28 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 @@ -200,9 +200,11 @@ __pthread_cond_timedwait: 42: leal (%ebp), %esi movl 28(%esp), %edx addl $cond_futex, %ebx +.Ladd_cond_futex_pi: movl $SYS_futex, %eax ENTER_KERNEL subl $cond_futex, %ebx +.Lsub_cond_futex_pi: movl %eax, %esi /* Set the pi-requeued flag only if the kernel has returned 0. The kernel does not hold the mutex on ETIMEDOUT or any other error. */ @@ -638,7 +640,15 @@ __condvar_tw_cleanup: .uleb128 .Lcstend-.Lcstbegin .Lcstbegin: .long .LcleanupSTART-.LSTARTCODE - .long .Ladd_cond_futex-.LcleanupSTART + .long .Ladd_cond_futex_pi-.LcleanupSTART + .long __condvar_tw_cleanup-.LSTARTCODE + .uleb128 0 + .long .Ladd_cond_futex_pi-.LSTARTCODE + .long .Lsub_cond_futex_pi-.Ladd_cond_futex_pi + .long __condvar_tw_cleanup2-.LSTARTCODE + .uleb128 0 + .long .Lsub_cond_futex_pi-.LSTARTCODE + .long .Ladd_cond_futex-.Lsub_cond_futex_pi .long __condvar_tw_cleanup-.LSTARTCODE .uleb128 0 .long .Ladd_cond_futex-.LSTARTCODE 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 2ae7af2613..366de6938a 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 @@ -141,9 +141,11 @@ __pthread_cond_wait: movl %ebp, %edx xorl %esi, %esi addl $cond_futex, %ebx +.Ladd_cond_futex_pi: movl $SYS_futex, %eax ENTER_KERNEL subl $cond_futex, %ebx +.Lsub_cond_futex_pi: /* Set the pi-requeued flag only if the kernel has returned 0. The kernel does not hold the mutex on error. */ cmpl $0, %eax @@ -630,7 +632,15 @@ __condvar_w_cleanup: .uleb128 .Lcstend-.Lcstbegin .Lcstbegin: .long .LcleanupSTART-.LSTARTCODE - .long .Ladd_cond_futex-.LcleanupSTART + .long .Ladd_cond_futex_pi-.LcleanupSTART + .long __condvar_w_cleanup-.LSTARTCODE + .uleb128 0 + .long .Ladd_cond_futex_pi-.LSTARTCODE + .long .Lsub_cond_futex_pi-.Ladd_cond_futex_pi + .long __condvar_w_cleanup2-.LSTARTCODE + .uleb128 0 + .long .Lsub_cond_futex_pi-.LSTARTCODE + .long .Ladd_cond_futex-.Lsub_cond_futex_pi .long __condvar_w_cleanup-.LSTARTCODE .uleb128 0 .long .Ladd_cond_futex-.LSTARTCODE diff --git a/nptl/tst-cond-except.c b/nptl/tst-cond-except.c new file mode 100644 index 0000000000..b9871ba864 --- /dev/null +++ b/nptl/tst-cond-except.c @@ -0,0 +1,108 @@ +/* Verify that exception table for pthread_cond_wait is correct. + 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 + +pthread_mutex_t mutex; +pthread_cond_t cond; + +#define CHECK_RETURN_VAL_OR_FAIL(ret,str) \ + ({ if ((ret) != 0) \ + { \ + printf ("%s failed: %s\n", (str), strerror (ret)); \ + ret = 1; \ + goto out; \ + } \ + }) + + +void +clean (void *arg) +{ + puts ("clean: Unlocking mutex..."); + pthread_mutex_unlock ((pthread_mutex_t *) arg); + puts ("clean: Mutex unlocked..."); +} + +void * +thr (void *arg) +{ + int ret = 0; + pthread_mutexattr_t mutexAttr; + ret = pthread_mutexattr_init (&mutexAttr); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_init"); + + ret = pthread_mutexattr_setprotocol (&mutexAttr, PTHREAD_PRIO_INHERIT); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_setprotocol"); + + ret = pthread_mutex_init (&mutex, &mutexAttr); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_init"); + + ret = pthread_cond_init (&cond, 0); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_init"); + + puts ("th: Init done, entering wait..."); + + pthread_cleanup_push (clean, (void *) &mutex); + ret = pthread_mutex_lock (&mutex); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_lock"); + while (1) + { + ret = pthread_cond_wait (&cond, &mutex); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_wait"); + } + pthread_cleanup_pop (1); + +out: + return (void *)ret; +} + +int +do_test () +{ + pthread_t thread; + int ret = 0; + void *thr_ret = 0; + ret = pthread_create (&thread, 0, thr, &thr_ret); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_create"); + + puts ("main: Thread created, waiting a bit..."); + sleep (2); + + puts ("main: Cancelling thread..."); + ret = pthread_cancel (thread); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cancel"); + + puts ("main: Joining th..."); + ret = pthread_join (thread, NULL); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_join"); + + if (thr_ret != NULL) + return 1; + + puts ("main: Joined thread, done!"); + +out: + return ret; +} + +#define TIMEOUT 5 +#include "../test-skeleton.c" -- cgit 1.4.1