diff options
| author | Ulrich Drepper <drepper@redhat.com> | 2004-09-02 18:59:24 +0000 |
|---|---|---|
| committer | Ulrich Drepper <drepper@redhat.com> | 2004-09-02 18:59:24 +0000 |
| commit | 73f7c32c47ab2397935d9fc2aeaa594794b38c7e (patch) | |
| tree | 1a0f7d20c9009fbd67c33495f9db0a5d665092b3 | |
| parent | 86aca5ac58e152336e676bc1231acac6adc32068 (diff) | |
| download | glibc-73f7c32c47ab2397935d9fc2aeaa594794b38c7e.tar.xz glibc-73f7c32c47ab2397935d9fc2aeaa594794b38c7e.zip | |
[BZ #357]
Update.
2004-09-02 Steven Munroe <sjmunroe@us.ibm.com>
[BZ #357]
* stdlib/tst-setcontext.c (test_stack): Added test for stack clobber.
(main): Call test_stack.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S
(__getcontext): Push stack frame then save parms in local frame.
Improve instruction scheduling.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S
(__swapcontext): Likewise.
28 files changed, 643 insertions, 96 deletions
@@ -1,3 +1,14 @@ +2004-09-02 Steven Munroe <sjmunroe@us.ibm.com> + + [BZ #357] + * stdlib/tst-setcontext.c (test_stack): Added test for stack clobber. + (main): Call test_stack. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S + (__getcontext): Push stack frame then save parms in local frame. + Improve instruction scheduling. + * sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S + (__swapcontext): Likewise. + 2004-09-01 Andreas Schwab <schwab@suse.de> * sysdeps/unix/sysv/linux/ia64/sys/ucontext.h [g++ >= 3.5]: Use diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 2aa77d9133..6306a7b0c6 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,62 @@ +2004-09-02 Ulrich Drepper <drepper@redhat.com> + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + Rename __data.__clock to __data.__nwaiters, make it unsigned int. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: + Decrement __nwaiters. If pthread_cond_destroy has been called and + this is the last waiter, signal pthread_cond_destroy caller and + avoid using the pthread_cond_t structure after unlock. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + Read clock type from the least significant bits of __nwaiters instead + of __clock. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/internaltypes.h: Define COND_CLOCK_BITS. + +2004-08-31 Jakub Jelinek <jakub@redhat.com> + + [BZ #342] + * Makefile (tests): Add tst-cond20 and tst-cond21. + * tst-cond20.c: New test. + * tst-cond21.c: New test. + * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h + (pthread_cond_t): Rename __data.__clock to __data.__nwaiters, make + it unsigned int. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h + (pthread_cond_t): Likewise. + * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h (pthread_cond_t): + Likewise. + * sysdeps/unix/sysv/linux/lowlevelcond.sym (cond_clock): Remove. + (cond_nwaiters): New. + (clock_bits): New. + * pthread_cond_destroy.c (__pthread_cond_destroy): Return EBUSY + if there are waiters not signalled yet. + Wait until all already signalled waiters wake up. + * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Decrement + __nwaiters. If pthread_cond_destroy has been called and this is the + last waiter, signal pthread_cond_destroy caller and avoid using + the pthread_cond_t structure after unlock. + (__pthread_cond_wait): Increment __nwaiters in the beginning, + decrement it when leaving. If pthread_cond_destroy has been called + and this is the last waiter, signal pthread_cond_destroy caller. + * sysdeps/pthread/pthread_cond_timedwait.c (__pthread_cond_timedwait): + Likewise. Read clock type from the least significant bits of + __nwaiters instead of __clock. + * pthread_condattr_setclock.c (pthread_condattr_setclock): Check + whether clock ID can be encoded in COND_CLOCK_BITS bits. + * pthread_condattr_getclock.c (pthread_condattr_getclock): Decode + clock type just from the last COND_CLOCK_BITS bits of value. + * pthread_cond_init.c (__pthread_cond_init): Initialize __nwaiters + instead of __clock, just from second bit of condattr's value. + 2004-08-30 Jakub Jelinek <jakub@redhat.com> * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Include diff --git a/nptl/Makefile b/nptl/Makefile index e797f4d486..e75752f801 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -193,6 +193,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \ 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-rwlock1 tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 \ tst-rwlock6 tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 \ tst-rwlock11 tst-rwlock12 tst-rwlock13 tst-rwlock14 \ diff --git a/nptl/pthread_cond_destroy.c b/nptl/pthread_cond_destroy.c index 5ade3e63db..0208d18ce4 100644 --- a/nptl/pthread_cond_destroy.c +++ b/nptl/pthread_cond_destroy.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -17,6 +17,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <errno.h> #include <shlib-compat.h> #include "pthreadP.h" @@ -25,6 +26,35 @@ int __pthread_cond_destroy (cond) pthread_cond_t *cond; { + /* Make sure we are alone. */ + lll_mutex_lock (cond->__data.__lock); + + if (cond->__data.__total_seq > cond->__data.__wakeup_seq) + { + /* If there are still some waiters which have not been + woken up, this is an application bug. */ + lll_mutex_unlock (cond->__data.__lock); + return EBUSY; + } + + /* Tell pthread_cond_*wait that this condvar is being destroyed. */ + cond->__data.__total_seq = -1ULL; + + /* If there are waiters which have been already signalled or + broadcasted, but still are using the pthread_cond_t structure, + pthread_cond_destroy needs to wait for them. */ + unsigned int nwaiters = cond->__data.__nwaiters; + while (nwaiters >= (1 << COND_CLOCK_BITS)) + { + lll_mutex_unlock (cond->__data.__lock); + + lll_futex_wait (&cond->__data.__nwaiters, nwaiters); + + lll_mutex_lock (cond->__data.__lock); + + nwaiters = cond->__data.__nwaiters; + } + return 0; } versioned_symbol (libpthread, __pthread_cond_destroy, diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c index f5fbd64e96..03ac59dbd2 100644 --- a/nptl/pthread_cond_init.c +++ b/nptl/pthread_cond_init.c @@ -32,8 +32,9 @@ __pthread_cond_init (cond, cond_attr) cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER; cond->__data.__futex = 0; - cond->__data.__clock = (icond_attr == NULL - ? CLOCK_REALTIME : (icond_attr->value & 0xfe) >> 1); + cond->__data.__nwaiters = (icond_attr != NULL + && ((icond_attr->value & (COND_CLOCK_BITS << 1)) + >> 1)); cond->__data.__total_seq = 0; cond->__data.__wakeup_seq = 0; cond->__data.__woken_seq = 0; diff --git a/nptl/pthread_condattr_getclock.c b/nptl/pthread_condattr_getclock.c index f8be655bf9..84de918a54 100644 --- a/nptl/pthread_condattr_getclock.c +++ b/nptl/pthread_condattr_getclock.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -25,7 +25,7 @@ pthread_condattr_getclock (attr, clock_id) const pthread_condattr_t *attr; clockid_t *clock_id; { - *clock_id = ((((const struct pthread_condattr *) attr)->value) & 0xfe) >> 1; - + *clock_id = (((((const struct pthread_condattr *) attr)->value) >> 1) + & ((1 << COND_CLOCK_BITS) - 1)); return 0; } diff --git a/nptl/pthread_condattr_setclock.c b/nptl/pthread_condattr_setclock.c index 0f1829c502..04e246b74d 100644 --- a/nptl/pthread_condattr_setclock.c +++ b/nptl/pthread_condattr_setclock.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. @@ -17,6 +17,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <assert.h> #include <errno.h> #include <stdbool.h> #include <time.h> @@ -45,8 +46,7 @@ pthread_condattr_setclock (attr, clock_id) INTERNAL_SYSCALL_DECL (err); int val; - val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, - &ts); + val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1; } @@ -57,11 +57,16 @@ pthread_condattr_setclock (attr, clock_id) #endif } else if (clock_id != CLOCK_REALTIME) + /* If more clocks are allowed some day the storing of the clock ID + in the pthread_cond_t structure needs to be adjusted. */ return EINVAL; + /* Make sure the value fits in the bits we reserved. */ + assert (clock_id < (1 << COND_CLOCK_BITS)); + int *valuep = &((struct pthread_condattr *) attr)->value; - *valuep = (*valuep & ~0xfe) | (clock_id << 1); + *valuep = (*valuep & ~(1 << (COND_CLOCK_BITS + 1)) & ~1) | (clock_id << 1); return 0; } diff --git a/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/nptl/sysdeps/pthread/pthread_cond_timedwait.c index 7de2b2936f..c6606c9bf9 100644 --- a/nptl/sysdeps/pthread/pthread_cond_timedwait.c +++ b/nptl/sysdeps/pthread/pthread_cond_timedwait.c @@ -67,6 +67,7 @@ __pthread_cond_timedwait (cond, mutex, abstime) /* We have one new user of the condvar. */ ++cond->__data.__total_seq; ++cond->__data.__futex; + cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; /* Remember the mutex we are using here. If there is already a different address store this is a bad user bug. Do not store @@ -98,7 +99,8 @@ __pthread_cond_timedwait (cond, mutex, abstime) INTERNAL_SYSCALL_DECL (err); int ret; ret = INTERNAL_SYSCALL (clock_gettime, err, 2, - cond->__data.__clock, &rt); + cond->__data.__nwaiters & COND_CLOCK_BITS, + &rt); # ifndef __ASSUME_POSIX_TIMERS if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (ret, err), 0)) { @@ -185,6 +187,16 @@ __pthread_cond_timedwait (cond, mutex, abstime) ++cond->__data.__woken_seq; bc_out: + + cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* If pthread_cond_destroy was called on this variable already, + notify the pthread_cond_destroy caller all waiters have left + and it can be successfully destroyed. */ + if (cond->__data.__total_seq == -1ULL + && cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) + lll_futex_wake (&cond->__data.__nwaiters, 1); + /* We are done with the condvar. */ lll_mutex_unlock (cond->__data.__lock); diff --git a/nptl/sysdeps/pthread/pthread_cond_wait.c b/nptl/sysdeps/pthread/pthread_cond_wait.c index 45187b5240..86669458a0 100644 --- a/nptl/sysdeps/pthread/pthread_cond_wait.c +++ b/nptl/sysdeps/pthread/pthread_cond_wait.c @@ -42,6 +42,7 @@ __condvar_cleanup (void *arg) { struct _condvar_cleanup_buffer *cbuffer = (struct _condvar_cleanup_buffer *) arg; + unsigned int destroying; /* We are going to modify shared data. */ lll_mutex_lock (cbuffer->cond->__data.__lock); @@ -55,11 +56,25 @@ __condvar_cleanup (void *arg) ++cbuffer->cond->__data.__futex; } + cbuffer->cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* If pthread_cond_destroy was called on this variable already, + notify the pthread_cond_destroy caller all waiters have left + and it can be successfully destroyed. */ + destroying = 0; + if (cbuffer->cond->__data.__total_seq == -1ULL + && cbuffer->cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) + { + lll_futex_wake (&cbuffer->cond->__data.__nwaiters, 1); + destroying = 1; + } + /* We are done. */ lll_mutex_unlock (cbuffer->cond->__data.__lock); /* Wake everybody to make sure no condvar signal gets lost. */ - lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX); + if (! destroying) + lll_futex_wake (&cbuffer->cond->__data.__futex, INT_MAX); /* Get the mutex before returning unless asynchronous cancellation is in effect. */ @@ -90,6 +105,7 @@ __pthread_cond_wait (cond, mutex) /* We have one new user of the condvar. */ ++cond->__data.__total_seq; ++cond->__data.__futex; + cond->__data.__nwaiters += 1 << COND_CLOCK_BITS; /* Remember the mutex we are using here. If there is already a different address store this is a bad user bug. Do not store @@ -145,6 +161,16 @@ __pthread_cond_wait (cond, mutex) ++cond->__data.__woken_seq; bc_out: + + cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS; + + /* If pthread_cond_destroy was called on this varaible already, + notify the pthread_cond_destroy caller all waiters have left + and it can be successfully destroyed. */ + if (cond->__data.__total_seq == -1ULL + && cond->__data.__nwaiters < (1 << COND_CLOCK_BITS)) + lll_futex_wake (&cond->__data.__nwaiters, 1); + /* We are done with the condvar. */ lll_mutex_unlock (cond->__data.__lock); diff --git a/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h index 62c853cee9..fd20d572af 100644 --- a/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h @@ -81,7 +81,7 @@ typedef union unsigned long long int __wakeup_seq; unsigned long long int __woken_seq; void *__mutex; - int __clock; + unsigned int __nwaiters; unsigned int __broadcast_seq; } __data; char __size[__SIZEOF_PTHREAD_COND_T]; diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h index 8d7858a071..fb62c0d99b 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -81,7 +81,7 @@ typedef union unsigned long long int __wakeup_seq; unsigned long long int __woken_seq; void *__mutex; - int __clock; + unsigned int __nwaiters; unsigned int __broadcast_seq; } __data; char __size[__SIZEOF_PTHREAD_COND_T]; 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 eecec8aee3..699c2cb227 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 @@ -87,6 +87,7 @@ __pthread_cond_timedwait: addl $1, total_seq(%ebx) adcl $0, total_seq+4(%ebx) addl $1, cond_futex(%ebx) + addl $(1 << clock_bits), cond_nwaiters(%ebx) #define FRAME_SIZE 24 subl $FRAME_SIZE, %esp @@ -104,8 +105,9 @@ __pthread_cond_timedwait: 8: movl %ebx, %edx #ifdef __NR_clock_gettime /* Get the clock number. */ - movl cond_clock(%ebx), %ebx - /* Only clocks 0 and 1 are allowed. Both are handled in the + movl cond_nwaiters(%ebx), %ebx + andl $((1 << clock_bits) - 1), %ebx + /* Only clocks 0 and 1 are allowed so far. Both are handled in the kernel. */ leal 4(%esp), %ecx movl $__NR_clock_gettime, %eax @@ -226,7 +228,25 @@ __pthread_cond_timedwait: 14: addl $1, woken_seq(%ebx) adcl $0, woken_seq+4(%ebx) -24: LOCK +24: subl $(1 << clock_bits), cond_nwaiters(%ebx) + + /* Wake up a thread which wants to destroy the condvar object. */ + movl total_seq(%ebx), %eax + andl total_seq+4(%ebx), %eax + cmpl $0xffffffff, %eax + jne 25f + movl cond_nwaiters(%ebx), %eax + andl $~((1 << clock_bits) - 1), %eax + jne 25f + + addl $cond_nwaiters, %ebx + movl $SYS_futex, %eax + movl $FUTEX_WAKE, %ecx + movl $1, %edx + ENTER_KERNEL + |
