summaryrefslogtreecommitdiff
path: root/nptl
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-09-02 18:59:24 +0000
committerUlrich Drepper <drepper@redhat.com>2004-09-02 18:59:24 +0000
commit73f7c32c47ab2397935d9fc2aeaa594794b38c7e (patch)
tree1a0f7d20c9009fbd67c33495f9db0a5d665092b3 /nptl
parent86aca5ac58e152336e676bc1231acac6adc32068 (diff)
[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.
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog59
-rw-r--r--nptl/Makefile1
-rw-r--r--nptl/pthread_cond_destroy.c32
-rw-r--r--nptl/pthread_cond_init.c5
-rw-r--r--nptl/pthread_condattr_getclock.c6
-rw-r--r--nptl/pthread_condattr_setclock.c13
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_timedwait.c14
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_wait.c28
-rw-r--r--nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S54
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S49
-rw-r--r--nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/internaltypes.h6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym5
-rw-r--r--nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S24
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S51
-rw-r--r--nptl/tst-cond20.c170
-rw-r--r--nptl/tst-cond21.c3
24 files changed, 496 insertions, 40 deletions
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
+ subl $cond_nwaiters, %ebx
+
+25: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
@@ -394,7 +414,27 @@ __condvar_tw_cleanup:
addl $1, woken_seq(%ebx)
adcl $0, woken_seq+4(%ebx)
-3: LOCK
+3: subl $(1 << clock_bits), cond_nwaiters(%ebx)
+
+ /* Wake up a thread which wants to destroy the condvar object. */
+ xorl %edi, %edi
+ movl total_seq(%ebx), %eax
+ andl total_seq+4(%ebx), %eax
+ cmpl $0xffffffff, %eax
+ jne 4f
+ movl cond_nwaiters(%ebx), %eax
+ andl $~((1 << clock_bits) - 1), %eax
+ jne 4f
+
+ addl $cond_nwaiters, %ebx
+ movl $SYS_futex, %eax
+ movl $FUTEX_WAKE, %ecx
+ movl $1, %edx
+ ENTER_KERNEL
+ subl $cond_nwaiters, %ebx
+ movl $1, %edi
+
+4: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
@@ -410,13 +450,15 @@ __condvar_tw_cleanup:
call __lll_mutex_unlock_wake
/* Wake up all waiters to make sure no signal gets lost. */
-2: addl $cond_futex, %ebx
+2: testl %edi, %edi
+ jnz 5f
+ addl $cond_futex, %ebx
movl $FUTEX_WAKE, %ecx
movl $SYS_futex, %eax
movl $0x7fffffff, %edx
ENTER_KERNEL
- movl 24+FRAME_SIZE(%esp), %eax
+5: movl 24+FRAME_SIZE(%esp), %eax
call __pthread_mutex_cond_lock
movl %esi, (%esp)
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 3fe7f8c17a..d282785151 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
@@ -80,6 +80,7 @@ __pthread_cond_wait:
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 16
subl $FRAME_SIZE, %esp
@@ -156,7 +157,25 @@ __pthread_cond_wait:
adcl $0, woken_seq+4(%ebx)
/* Unlock */
-16: LOCK
+16: 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 17f
+ movl cond_nwaiters(%ebx), %eax
+ andl $~((1 << clock_bits) - 1), %eax
+ jne 17f
+
+ addl $cond_nwaiters, %ebx
+ movl $SYS_futex, %eax
+ movl $FUTEX_WAKE, %ecx
+ movl $1, %edx
+ ENTER_KERNEL
+ subl $cond_nwaiters, %ebx
+
+17: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
@@ -286,7 +305,27 @@ __condvar_w_cleanup:
addl $1, woken_seq(%ebx)
adcl $0, woken_seq+4(%ebx)
-3: LOCK
+3: subl $(1 << clock_bits), cond_nwaiters(%ebx)
+
+ /* Wake up a thread which wants to destroy the condvar object. */
+ xorl %edi, %edi
+ movl total_seq(%ebx), %eax
+ andl total_seq+4(%ebx), %eax
+ cmpl $0xffffffff, %eax
+ jne 4f
+ movl cond_nwaiters(%ebx), %eax
+ andl $~((1 << clock_bits) - 1), %eax
+ jne 4f
+
+ addl $cond_nwaiters, %ebx
+ movl $SYS_futex, %eax
+ movl $FUTEX_WAKE, %ecx
+ movl $1, %edx
+ ENTER_KERNEL
+ subl $cond_nwaiters, %ebx
+ movl $1, %edi
+
+4: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
@@ -302,13 +341,15 @@ __condvar_w_cleanup:
call __lll_mutex_unlock_wake
/* Wake up all waiters to make sure no signal gets lost. */
-2: addl $cond_futex, %ebx
+2: testl %edi, %edi
+ jnz 5f
+ addl $cond_futex, %ebx
movl $FUTEX_WAKE, %ecx
movl $SYS_futex, %eax
movl $0x7fffffff, %edx
ENTER_KERNEL
- movl 20+FRAME_SIZE(%esp), %eax
+5: movl 20+FRAME_SIZE(%esp), %eax
call __pthread_mutex_cond_lock
movl %esi, (%esp)
diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
index 958af47162..5b442cbca7 100644
--- a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/ia64/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/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
index 43b6856bbf..1dec19e57d 100644
--- a/nptl/sysdeps/unix/sysv/linux/internaltypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
@@ -75,6 +75,12 @@ struct pthread_condattr
};
+/* The __NWAITERS field is used as a counter and to house the number
+ of bits which represent the clock. COND_CLOCK_BITS is the number
+ of bits reserved for the clock. */
+#define COND_CLOCK_BITS 1
+
+
/* Read-write lock variable attribute data structure. */
struct pthread_rwlockattr
{
diff --git a/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym b/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
index 2e193e6d2e..c5e7978069 100644
--- a/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
+++ b/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
@@ -1,13 +1,16 @@
#include <stddef.h>
+#include <sched.h>
#include <bits/pthreadtypes.h>
+#include <internaltypes.h>
--
cond_lock offsetof (pthread_cond_t, __data.__lock)
cond_futex offsetof (pthread_cond_t, __data.__futex)
-cond_clock offsetof (pthread_cond_t, __data.__clock)
+cond_nwaiters offsetof (pthread_cond_t, __data.__nwaiters)
total_seq offsetof (pthread_cond_t, __data.__total_seq)
wakeup_seq offsetof (pthread_cond_t, __data.__wakeup_seq)
woken_seq offsetof (pthread_cond_t, __data.__woken_seq)
dep_mutex offsetof (pthread_cond_t, __data.__mutex)
broadcast_seq offsetof (pthread_cond_t, __data.__broadcast_seq)
+clock_bits COND_CLOCK_BITS
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
index 5a000d30af..a493821c07 100644
--- a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
@@ -101,7 +101,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/s390/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
index 142286451c..17cfaa981d 100644
--- a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
@@ -100,7 +100,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/sh/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
index b8afbc50b5..5bf3aff46a 100644
--- a/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
@@ -82,7 +82,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/sparc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
index e86dd000a1..34d3df7abb 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
@@ -101,7 +101,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/x86_64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
index a7bc5816cc..e5cc605f24 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
@@ -100,7 +100,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
- int __clock;
+ int __nwaiters;
unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
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 95f8aabd11..67bec6caa7 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
@@ -111,6 +111,7 @@ __pthread_cond_timedwait:
movq 8(%rsp), %rdi
incq total_seq(%rdi)
incl cond_futex(%rdi)
+ addl $(1 << clock_bits), cond_nwaiters(%rdi)
/* Install cancellation handler. */
#ifdef PIC
@@ -135,8 +136,9 @@ __pthread_cond_timedwait:
/* Get the clock number. Note that the field in the condvar
structure stores the number minus 1. */
movq 8(%rsp), %rdi
- movl cond_clock(%rdi), %edi
- /* Only clocks 0 and 1 are allowed. Both are handled in the
+ movl cond_nwaiters(%rdi), %edi
+ andl $((1 << clock_bits) - 1), %edi
+ /* Only clocks 0 and 1 are allowed so far. Both are handled in the
kernel. */
leaq 24(%rsp), %rsi
movq $__NR_clock_gettime, %rax
@@ -244,7 +246,23 @@ __pthread_cond_timedwait:
9: xorq %r14, %r14
14: incq woken_seq(%rdi)
-24: LOCK
+24: subl $(1 << clock_bits), cond_nwaiters(%rdi)
+
+ /* Wake up a thread which wants to destroy the condvar object. */
+ cmpq $0xffffffffffffffff, total_seq(%rdi)
+ jne 25f
+ movl cond_nwaiters(%rdi), %eax
+ andl $~((1 << clock_bits) - 1), %eax
+ jne 25f
+
+ addq $cond_nwaiters, %rdi
+ movq $SYS_futex, %rax
+ movq $FUTEX_WAKE, %rsi
+ movl $1, %edx
+ syscall
+ subq $cond_nwaiters, %rdi
+
+25: LOCK
#if cond_lock == 0
decl (%rdi)
#else
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 9e7da301d3..f5de0a280c 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
@@ -40,6 +40,8 @@
.globl __condvar_cleanup
.hidden __condvar_cleanup
__condvar_cleanup:
+ pushq %r12
+
/* Get internal lock. */
movq %rdi, %r8
movq 8(%rdi), %rdi
@@ -66,12 +68,28 @@ __condvar_cleanup:
jne 3f
incq wakeup_seq(%rdi)
-
incq woken_seq(%rdi)
-
incl cond_futex(%rdi)
-3: LOCK
+3: subl $(1 << clock_bits), cond_nwaiters(%rdi)
+
+ /* Wake up a thread which wants to destroy the condvar object. */
+ xorq %r12, %r12
+ cmpq $0xffffffffffffffff, total_seq(%rdi)
+ jne 4f
+ movl cond_nwaiters(%rdi), %eax
+ andl $~((1 << clock_bits) - 1), %eax
+ jne 4f
+
+ addq $cond_nwaiters, %rdi
+ movq $SYS_futex, %rax
+ movq $FUTEX_WAKE, %rsi
+ movl $1, %edx
+ syscall
+ subq $cond_nwaiters, %rdi
+ movq $1, %r12
+
+4: LOCK
#if cond_lock == 0
decl (%rdi)
#else
@@ -84,15 +102,19 @@ __condvar_cleanup:
callq __lll_mutex_unlock_wake
/* Wake up all waiters to make sure no signal gets lost. */
-2: addq $cond_futex, %rdi
+2: testq %r12, %r12
+ jnz 5f
+ addq $cond_futex, %rdi
movq $FUTEX_WAKE, %rsi
movl $0x7fffffff, %edx
movq $SYS_futex, %rax
syscall
- movq 16(%r8), %rdi
+5: movq 16(%r8), %rdi
callq __pthread_mutex_cond_lock
+ popq %r12
+
retq
.size __condvar_cleanup, .-__condvar_cleanup
@@ -157,6 +179,7 @@ __pthread_cond_wait:
movq 8(%rsp), %rdi
incq total_seq(%rdi)
incl cond_futex(%rdi)
+ addl $(1 << clock_bits), cond_nwaiters(%rdi)
/* Install cancellation handler. */
#ifdef PIC
@@ -229,7 +252,23 @@ __pthread_cond_wait:
incq woken_seq(%rdi)
/* Unlock */
-16: LOCK
+16: subl $(1 << clock_bits), cond_nwaiters(%rdi)
+
+ /* Wake up a thread which wants to destroy the condvar object. */
+ cmpq $0xffffffffffffffff, total_seq(%rdi)
+ jne 17f
+ movl cond_nwaiters(%rdi), %eax
+ andl $~((1 << clock_bits) - 1), %eax
+ jne 17f
+
+ addq $cond_nwaiters, %rdi
+ movq $SYS_futex, %rax
+ movq $FUTEX_WAKE, %rsi
+ movl $1, %edx
+ syscall
+ subq $cond_nwaiters, %rdi
+
+17: LOCK
#if cond_lock == 0
decl (%rdi)
#else
diff --git a/nptl/tst-cond20.c b/nptl/tst-cond20.c
new file mode 100644
index 0000000000..ba50d58534
--- /dev/null
+++ b/nptl/tst-cond20.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+ 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 <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define N 10
+#define ROUNDS 1000
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t b;
+static int count;
+
+static void *
+tf (void *p)
+{
+ int i;
+ for (i = 0; i < ROUNDS; ++i)
+ {
+ pthread_mutex_lock (&mut);
+
+ if (++count == N)
+ pthread_cond_signal (&cond2);
+
+#ifdef TIMED
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ struct timespec ts;
+ /* Wait three second. */
+ ts.tv_sec = tv.tv_sec + 3;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ pthread_cond_timedwait (&cond, &mut, &ts);
+#else
+ pthread_cond_wait (&cond, &mut);
+#endif
+
+ pthread_mutex_unlock (&mut);
+
+ int err = pthread_barrier_wait (&b);
+ if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("child: barrier_wait failed");
+ exit (1);
+ }
+
+ err = pthread_barrier_wait (&b);
+ if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("child: barrier_wait failed");
+ exit (1);
+ }
+ }
+
+ return NULL;
+}
+
+
+static int
+do_test (void)
+{
+ if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+ {
+ puts ("barrier_init failed");
+ return 1;
+ }
+
+ pthread_mutex_lock (&mut);
+
+ int i, j, err;
+ pthread_t th[N];
+ for (i = 0; i < N; ++i)
+ if ((err = pthread_create (&th[i], NULL, tf, NULL)) != 0)
+ {
+ printf ("cannot create thread %d: %s\n", i, strerror (err));
+ return 1;
+ }
+
+ for (i = 0; i < ROUNDS; ++i)
+ {
+ pthread_cond_wait (&cond2, &mut);
+
+ if (i & 1)
+ pthread_mutex_unlock (&mut);
+
+ if (i & 2)
+ pthread_cond_broadcast (&cond);
+ else if (i & 4)
+ for (j = 0; j < N; ++j)
+ pthread_cond_signal (&cond);
+ else
+ {
+ for (j = 0; j < (i / 8) % N; ++j)
+ pthread_cond_signal (&cond);
+ pthread_cond_broadcast (&cond);
+ }
+
+ if ((i & 1) == 0)
+ pthread_mutex_unlock (&mut);
+
+ err = pthread_cond_destroy (&cond);
+ if (err)
+ {
+ printf ("pthread_cond_destroy failed: %s\n", strerror (err));
+ return 1;
+ }
+
+ /* Now clobber the cond variable which has been successfully
+ destroyed above. */
+ memset (&cond, (char) i, sizeof (cond));
+
+ err = pthread_barrier_wait (&b);
+ if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("parent: barrier_wait failed");
+ return 1;
+ }
+
+ pthread_mutex_lock (&mut);
+
+ err = pthread_barrier_wait (&b);
+ if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("parent: barrier_wait failed");
+ return 1;
+ }
+
+ count = 0;
+ err = pthread_cond_init (&cond, NULL);
+ if (err)
+ {
+ printf ("pthread_cond_init failed: %s\n", strerror (err));
+ return 1;
+ }
+ }
+
+ for (i = 0; i < N; ++i)
+ if ((err = pthread_join (th[i], NULL)) != 0)
+ {
+ printf ("failed to join thread %d: %s\n", i, strerror (err));
+ return 1;
+ }
+
+ puts ("done");
+
+ return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond21.c b/nptl/tst-cond21.c
new file mode 100644
index 0000000000..89cb771b57
--- /dev/null
+++ b/nptl/tst-cond21.c
@@ -0,0 +1,3 @@
+#include <sys/time.h>
+#define TIMED 1
+#include "tst-cond20.c"