summaryrefslogtreecommitdiff
path: root/nptl
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-05-18 20:18:14 +0000
committerUlrich Drepper <drepper@redhat.com>2004-05-18 20:18:14 +0000
commit893a351195a2997133892ffac80573a9984ba4cf (patch)
treead1b9f1a9e7d55b25353c57f9fbd5f76c4804054 /nptl
parentd40eb37aad4145ae4d047b6d7f633f740bf3a610 (diff)
downloadglibc-893a351195a2997133892ffac80573a9984ba4cf.tar.gz
[BZ #163]
Update. 2004-05-18 Petter Reinholdtsen <pere@hungry.com> * locales/sl_SI [LC_TIME]: Correct d_fmt date format from '22.06.2003' to '22. 06. 2003'. Change requested from Aleks Reinhardt, and approved by the locale author Borka Jerman-Blazic. [BZ #163]
Diffstat (limited to 'nptl')
-rw-r--r--nptl/ChangeLog45
-rw-r--r--nptl/DESIGN-condvar.txt30
-rw-r--r--nptl/Makefile7
-rw-r--r--nptl/pthread_cond_init.c3
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_broadcast.c5
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_timedwait.c15
-rw-r--r--nptl/sysdeps/pthread/pthread_cond_wait.c19
-rw-r--r--nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S5
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S31
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S21
-rw-r--r--nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S8
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S35
-rw-r--r--nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S33
-rw-r--r--nptl/tst-cond16.c105
-rw-r--r--nptl/tst-cond17.c2
-rw-r--r--nptl/tst-cond18.c117
24 files changed, 441 insertions, 48 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 534f585f52..592f73b095 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,48 @@
+2004-05-18 Jakub Jelinek <jakub@redhat.com>
+
+ * Makefile (.NOTPARALLEL): Only serialize make check/xcheck, not
+ compilation.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
+ (__pthread_cond_timedwait): Avoid returning -ETIMEDOUT.
+ * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+ (pthread_cond_t): Add __data.__broadcast_seq field.
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
+ (FRAME_SIZE): Define.
+ (__pthread_cond_timedwait): Use it. Store/check broadcast_seq.
+ Comment typo fixes.
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S (FRAME_SIZE):
+ Define.
+ (__pthread_cond_wait): Use it. Store/check broadcast_seq. Comment
+ typo fixes.
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+ (__pthread_cond_broadcast): Increment broadcast_seq. Comment typo
+ fixes.
+
+2004-05-18 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/lowlevelcond.sym: Add broadcast_seq entry.
+ * sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h (pthread_cond_t):
+ Add __broadcast_seq field.
+ * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise.
+ * sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h: Likewise.
+ * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h: Likewise.
+ * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S: Mark
+ all waiters as woken with woken_seq and bump broadcast counter.
+ * sysdeps/pthread/pthread_cond_broadcast.c: Likewise.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Use new
+ __broadcast_seq field.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+ * sysdeps/pthread/pthread_cond_wait.c: Likewise.
+ * sysdeps/pthread/pthread_cond_timedwait.c: Likewise.
+ * pthread_cond_init.c: Initialize __broadcast_seq field.
+ * Makefile (tests): Add tst-cond17 and tst-cond18.
+ Add .NOTPARALLEL goal.
+ * tst-cond16.c: New file. From Jakub.
+ * tst-cond17.c: New file. From Jakub.
+ * tst-cond18.c: New file. From Jakub.
+
2004-05-16 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S: Correct some
diff --git a/nptl/DESIGN-condvar.txt b/nptl/DESIGN-condvar.txt
index cb0f59c823..4845251c75 100644
--- a/nptl/DESIGN-condvar.txt
+++ b/nptl/DESIGN-condvar.txt
@@ -23,16 +23,30 @@ struct pthread_cond_t {
sequence number of last woken thread.
+ uint32_t broadcast_seq;
+
+}
+
+
+struct cv_data {
+
+ pthread_cond_t *cv;
+
+ uint32_t bc_seq
+
}
-cleanup_handler(cv)
+cleanup_handler(cv_data)
{
+ cv = cv_data->cv;
lll_lock(cv->lock);
- ++cv->wakeup_seq;
- ++cv->woken_seq;
+ if (cv_data->bc_seq == cv->broadcast_seq) {
+ ++cv->wakeup_seq;
+ ++cv->woken_seq;
+ }
/* make sure no signal gets lost. */
FUTEX_WAKE(cv->wakeup_seq, ALL);
@@ -50,12 +64,14 @@ cond_timedwait(cv, mutex, timeout):
++cv->total_seq;
val = seq = cv->wakeup_seq;
+ cv_data.bc = cv->broadcast_seq;
+ cv_data.cv = cv;
while (1) {
lll_unlock(cv->lock);
- enable_async
+ enable_async(&cv_data);
ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout);
@@ -63,6 +79,9 @@ cond_timedwait(cv, mutex, timeout):
lll_lock(cv->lock);
+ if (bc != cv->broadcast_seq)
+ goto bc_out;
+
val = cv->wakeup_seq;
if (val != seq && cv->woken_seq != val) {
@@ -78,6 +97,7 @@ cond_timedwait(cv, mutex, timeout):
++cv->woken_seq;
+ bc_out:
lll_unlock(cv->lock);
cleanup_pop
@@ -105,6 +125,8 @@ cond_broadcast(cv)
if (cv->total_seq > cv->wakeup_seq) {
cv->wakeup_seq = cv->total_seq;
+ cv->woken_seq = cv->total_seq;
+ ++cv->broadcast_seq;
FUTEX_WAKE(cv->wakeup_seq, ALL);
}
diff --git a/nptl/Makefile b/nptl/Makefile
index a90c4ad2d7..687a6a0cfc 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -194,7 +194,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
tst-spin1 tst-spin2 tst-spin3 \
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-cond14 tst-cond15 tst-cond17 tst-cond18 \
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 \
@@ -576,3 +576,8 @@ tst-exec4-ARGS = $(built-program-cmd)
$(objpfx)tst-execstack: $(libdl)
$(objpfx)tst-execstack.out: $(objpfx)tst-execstack-mod.so
LDFLAGS-tst-execstack = -Wl,-z,noexecstack
+
+# The tests here better do not run in parallel
+ifneq ($(filter %tests,$(MAKECMDGOALS)),)
+.NOTPARALLEL:
+endif
diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c
index bb7c6d6ca1..d059da2315 100644
--- a/nptl/pthread_cond_init.c
+++ b/nptl/pthread_cond_init.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.
@@ -38,6 +38,7 @@ __pthread_cond_init (cond, cond_attr)
cond->__data.__woken_seq = 0;
cond->__data.__mutex = (icond_attr == NULL || (icond_attr->value & 1) == 0
? NULL : (void *) ~0l);
+ cond->__data.__broadcast_seq = 0;
return 0;
}
diff --git a/nptl/sysdeps/pthread/pthread_cond_broadcast.c b/nptl/sysdeps/pthread/pthread_cond_broadcast.c
index 44c3fe6d5f..a42c579658 100644
--- a/nptl/sysdeps/pthread/pthread_cond_broadcast.c
+++ b/nptl/sysdeps/pthread/pthread_cond_broadcast.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 Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
@@ -40,6 +40,9 @@ __pthread_cond_broadcast (cond)
{
/* Yes. Mark them all as woken. */
cond->__data.__wakeup_seq = cond->__data.__total_seq;
+ cond->__data.__woken_seq = cond->__data.__total_seq;
+ /* Signal that a broadcast happened. */
+ ++cond->__data.__broadcast_seq;
/* We are done. */
lll_mutex_unlock (cond->__data.__lock);
diff --git a/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/nptl/sysdeps/pthread/pthread_cond_timedwait.c
index a03f51e0f0..96b1029cf5 100644
--- a/nptl/sysdeps/pthread/pthread_cond_timedwait.c
+++ b/nptl/sysdeps/pthread/pthread_cond_timedwait.c
@@ -36,6 +36,7 @@ struct _condvar_cleanup_buffer
int oldtype;
pthread_cond_t *cond;
pthread_mutex_t *mutex;
+ unsigned int bc_seq;
};
int
@@ -85,6 +86,8 @@ __pthread_cond_timedwait (cond, mutex, abstime)
unsigned long long int val;
unsigned long long int seq;
val = seq = cond->__data.__wakeup_seq;
+ /* Remember the broadcast counter. */
+ cbuffer.bc_seq = cond->__data.__broadcast_seq;
/* The futex syscall operates on a 32-bit word. That is fine, we
just use the low 32 bits of the sequence counter. */
@@ -139,7 +142,12 @@ __pthread_cond_timedwait (cond, mutex, abstime)
}
/* Did we already time out? */
if (__builtin_expect (rt.tv_sec < 0, 0))
- goto timeout;
+ {
+ if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+ goto bc_out;
+
+ goto timeout;
+ }
/* Prepare to wait. Release the condvar futex. */
lll_mutex_unlock (cond->__data.__lock);
@@ -157,6 +165,10 @@ __pthread_cond_timedwait (cond, mutex, abstime)
/* We are going to look at shared data again, so get the lock. */
lll_mutex_lock(cond->__data.__lock);
+ /* If a broadcast happened, we are done. */
+ if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+ goto bc_out;
+
/* Check whether we are eligible for wakeup. */
val = cond->__data.__wakeup_seq;
if (val != seq && cond->__data.__woken_seq != val)
@@ -178,6 +190,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
/* Another thread woken up. */
++cond->__data.__woken_seq;
+ bc_out:
/* 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 01415bf051..a05060a107 100644
--- a/nptl/sysdeps/pthread/pthread_cond_wait.c
+++ b/nptl/sysdeps/pthread/pthread_cond_wait.c
@@ -32,6 +32,7 @@ struct _condvar_cleanup_buffer
int oldtype;
pthread_cond_t *cond;
pthread_mutex_t *mutex;
+ unsigned int bc_seq;
};
@@ -45,10 +46,13 @@ __condvar_cleanup (void *arg)
/* We are going to modify shared data. */
lll_mutex_lock (cbuffer->cond->__data.__lock);
- /* This thread is not waiting anymore. Adjust the sequence counters
- appropriately. */
- ++cbuffer->cond->__data.__wakeup_seq;
- ++cbuffer->cond->__data.__woken_seq;
+ if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
+ {
+ /* This thread is not waiting anymore. Adjust the sequence counters
+ appropriately. */
+ ++cbuffer->cond->__data.__wakeup_seq;
+ ++cbuffer->cond->__data.__woken_seq;
+ }
/* We are done. */
lll_mutex_unlock (cbuffer->cond->__data.__lock);
@@ -111,6 +115,8 @@ __pthread_cond_wait (cond, mutex)
unsigned long long int val;
unsigned long long int seq;
val = seq = cond->__data.__wakeup_seq;
+ /* Remember the broadcast counter. */
+ cbuffer.bc_seq = cond->__data.__broadcast_seq;
/* The futex syscall operates on a 32-bit word. That is fine, we
just use the low 32 bits of the sequence counter. */
@@ -137,6 +143,10 @@ __pthread_cond_wait (cond, mutex)
/* Disable asynchronous cancellation. */
__pthread_disable_asynccancel (cbuffer.oldtype);
+ /* If a broadcast happened, we are done. */
+ if (cbuffer.bc_seq != cond->__data.__broadcast_seq)
+ goto bc_out;
+
/* We are going to look at shared data again, so get the lock. */
lll_mutex_lock (cond->__data.__lock);
@@ -148,6 +158,7 @@ __pthread_cond_wait (cond, mutex)
/* Another thread woken up. */
++cond->__data.__woken_seq;
+ bc_out:
/* 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 0fed5cc918..1bb2968120 100644
--- a/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
@@ -81,6 +81,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
index f998138d7e..9da84c66d6 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -81,6 +81,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
index 8d09e22afd..456f3dbfb1 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_broadcast.S
@@ -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.
@@ -74,6 +74,9 @@ __pthread_cond_broadcast:
woken up. */
3: movl %ecx, (%ebx)
movl %eax, 4(%ebx)
+ movl %ecx, woken_seq-wakeup_seq(%ebx)
+ movl %eax, woken_seq-wakeup_seq+4(%ebx)
+ addl $1, broadcast_seq-wakeup_seq(%ebx)
/* Get the address of the mutex used. */
movl dep_mutex-wakeup_seq(%ebx), %edi
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 acc5a6a5f6..c0fd1a99a8 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
@@ -83,15 +83,17 @@ __pthread_cond_timedwait:
addl $1, total_seq(%ebx)
adcl $0, total_seq+4(%ebx)
-#define FRAME_SIZE 20
+#define FRAME_SIZE 24
subl $FRAME_SIZE, %esp
.Lsubl:
/* Get and store current wakeup_seq value. */
movl wakeup_seq(%ebx), %edi
movl wakeup_seq+4(%ebx), %edx
+ movl broadcast_seq(%ebx), %eax
movl %edi, 12(%esp)
movl %edx, 16(%esp)
+ movl %eax, 20(%esp)
/* Get the current time. */
8: movl %ebx, %edx
@@ -139,7 +141,8 @@ __pthread_cond_timedwait:
addl $1000000000, %edx
subl $1, %ecx
12: testl %ecx, %ecx
- js 13f
+ movl $-ETIMEDOUT, %esi
+ js 6f
/* Store relative timeout. */
21: movl %ecx, 4(%esp)
@@ -184,7 +187,11 @@ __pthread_cond_timedwait:
#endif
jnz 5f
-6: movl woken_seq(%ebx), %eax
+6: movl broadcast_seq(%ebx), %eax
+ cmpl 20(%esp), %eax
+ jne 23f
+
+ movl woken_seq(%ebx), %eax
movl woken_seq+4(%ebx), %ecx
movl wakeup_seq(%ebx), %edi
@@ -203,16 +210,19 @@ __pthread_cond_timedwait:
15: cmpl $-ETIMEDOUT, %esi
jne 8b
-13: addl $1, wakeup_seq(%ebx)
+ addl $1, wakeup_seq(%ebx)
adcl $0, wakeup_seq+4(%ebx)
movl $ETIMEDOUT, %esi
jmp 14f
+23: xorl %esi, %esi
+ jmp 24f
+
9: xorl %esi, %esi
14: addl $1, woken_seq(%ebx)
adcl $0, woken_seq+4(%ebx)
- LOCK
+24: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
@@ -332,7 +342,8 @@ __pthread_cond_timedwait:
addl $1000000000, %edx
subl $1, %ecx
20: testl %ecx, %ecx
- js 13b
+ movl $-ETIMEDOUT, %esi
+ js 6b
jmp 21b
#endif
.size __pthread_cond_timedwait, .-__pthread_cond_timedwait
@@ -372,13 +383,17 @@ __condvar_tw_cleanup:
#endif
call __lll_mutex_lock_wait
-1: addl $1, wakeup_seq(%ebx)
+1: movl broadcast_seq(%ebx), %eax
+ cmpl 12(%esp), %eax
+ jne 3f
+
+ addl $1, wakeup_seq(%ebx)
adcl $0, wakeup_seq+4(%ebx)
addl $1, woken_seq(%ebx)
adcl $0, woken_seq+4(%ebx)
- LOCK
+3: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
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 08a0588910..74e3172ab0 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,15 +80,17 @@ __pthread_cond_wait:
addl $1, total_seq(%ebx)
adcl $0, total_seq+4(%ebx)
-#define FRAME_SIZE 12
+#define FRAME_SIZE 16
subl $FRAME_SIZE, %esp
.Lsubl:
/* Get and store current wakeup_seq value. */
movl wakeup_seq(%ebx), %edi
movl wakeup_seq+4(%ebx), %edx
+ movl broadcast_seq(%ebx), %eax
movl %edi, 4(%esp)
movl %edx, 8(%esp)
+ movl %eax, 12(%esp)
/* Unlock. */
8: LOCK
@@ -127,7 +129,11 @@ __pthread_cond_wait:
#endif
jnz 5f
-6: movl woken_seq(%ebx), %eax
+6: movl broadcast_seq(%ebx), %eax
+ cmpl 12(%esp), %eax
+ jne 16f
+
+ movl woken_seq(%ebx), %eax
movl woken_seq+4(%ebx), %ecx
movl wakeup_seq(%ebx), %edi
@@ -146,7 +152,8 @@ __pthread_cond_wait:
9: addl $1, woken_seq(%ebx)
adcl $0, woken_seq+4(%ebx)
- LOCK
+ /* Unlock */
+16: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
@@ -264,13 +271,17 @@ __condvar_w_cleanup:
#endif
call __lll_mutex_lock_wait
-1: addl $1, wakeup_seq(%ebx)
+1: movl broadcast_seq(%ebx), %eax
+ cmpl 12(%esp), %eax
+ jne 3f
+
+ addl $1, wakeup_seq(%ebx)
adcl $0, wakeup_seq+4(%ebx)
addl $1, woken_seq(%ebx)
adcl $0, woken_seq+4(%ebx)
- LOCK
+3: LOCK
#if cond_lock == 0
subl $1, (%ebx)
#else
diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
index e4c15d1e20..bdf3ee741b 100644
--- a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
@@ -81,6 +81,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym b/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
index 1463e0810e..d0559da86f 100644
--- a/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
+++ b/nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
@@ -9,3 +9,4 @@ 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)
diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
index d6d94cda24..794d888a13 100644
--- a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
@@ -101,6 +101,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
index e2606aff8e..02b061b05c 100644
--- a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
@@ -100,6 +100,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
index d123fd059f..b0c1372bba 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
@@ -101,6 +101,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long long int __align;
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 1b4820eb0c..e29c77529e 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
@@ -81,6 +81,7 @@ typedef union
unsigned long long int __wakeup_seq;
unsigned long long int __woken_seq;
void *__mutex;
+ unsigned int __broadcast_seq;
} __data;
char __size[__SIZEOF_PTHREAD_COND_T];
long int __align;
diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
index 8e26681b3b..6d29d761fa 100644
--- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
+++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_broadcast.S
@@ -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.
@@ -63,6 +63,8 @@ __pthread_cond_broadcast:
/* Cause all currently waiting threads to recognize they are
woken up. */
movq %rcx, (%rdi)
+ movq %rcx, woken_seq-wakeup_seq(%rdi)
+ incl broadcast_seq-wakeup_seq(%rdi)
/* Get the address of the mutex used. */
movq dep_mutex-wakeup_seq(%rdi), %r8
@@ -110,12 +112,12 @@ __pthread_cond_broadcast:
#endif
jmp 2b
- /* Unlock in loop requires waekup. */
+ /* Unlock in loop requires wakeup. */
5: addq $cond_lock-wakeup_seq, %rdi
callq __lll_mutex_unlock_wake
jmp 6b
- /* Unlock in loop requires waekup. */
+ /* Unlock in loop requires wakeup. */
7: addq $cond_lock-wakeup_seq, %rdi
callq __lll_mutex_unlock_wake
subq $cond_lock-wakeup_seq, %rdi
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 f6b6ab246c..80cbf7e430 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
@@ -51,7 +51,8 @@ __pthread_cond_timedwait:
.Lpush_r13:
pushq %r14
.Lpush_r14:
- subq $80, %rsp
+#define FRAME_SIZE 80
+ subq $FRAME_SIZE, %rsp
.Lsubq:
/* Stack frame:
@@ -67,6 +68,8 @@ __pthread_cond_timedwait:
+--------------------------+
rsp + 8 | condvar pointer |
+--------------------------+
+ rsp + 4 | old broadcast_seq value |
+ +--------------------------+
rsp + 0 | old cancellation mode |
+--------------------------+
*/
@@ -116,7 +119,9 @@ __pthread_cond_timedwait:
/* Get and store current wakeup_seq value. */
movq 8(%rsp), %rdi
movq wakeup_seq(%rdi), %r12
+ movl broadcast_seq(%rdi), %edx
movq %r12, 40(%rsp)
+ movl %edx, 4(%rsp)
/* Get the current time. */
8:
@@ -160,7 +165,8 @@ __pthread_cond_timedwait:
decq %rcx
12: testq %rcx, %rcx
movq 8(%rsp), %rdi
- js 13f
+ movq $-ETIMEDOUT, %r14
+ js 6f
/* Store relative timeout. */
21: movq %rcx, 24(%rsp)
@@ -201,10 +207,15 @@ __pthread_cond_timedwait:
#endif
jne 5f
-6: movq woken_seq(%rdi), %rax
+6: movl broadcast_seq(%rdi), %edx
+
+ movq woken_seq(%rdi), %rax
movq wakeup_seq(%rdi), %r12
+ cmpl 4(%rsp), %edx
+ jne 23f
+
cmpq 40(%rsp), %r12
jbe 15f
@@ -218,10 +229,13 @@ __pthread_cond_timedwait:
movq $ETIMEDOUT, %r14
jmp 14f
+23: xorq %r14, %r14
+ jmp 24f
+
9: xorq %r14, %r14
14: incq woken_seq(%rdi)
- LOCK
+24: LOCK
#if cond_lock == 0
decl (%rdi)
#else
@@ -239,7 +253,7 @@ __pthread_cond_timedwait:
testq %rax, %rax
cmoveq %r14, %rax
-18: addq $80, %rsp
+18: addq $FRAME_SIZE, %rsp
.Laddq:
popq %r14
.Lpop_r14:
@@ -259,7 +273,7 @@ __pthread_cond_timedwait:
callq __lll_mutex_lock_wait
jmp 2b
- /* Unlock in loop requires waekup. */
+ /* Unlock in loop requires wakeup. */
3:
#if cond_lock != 0
addq $cond_lock, %rdi
@@ -278,7 +292,7 @@ __pthread_cond_timedwait:
#endif
jmp 6b
- /* Unlock after loop requires waekup. */
+ /* Unlock after loop requires wakeup. */
10:
#if cond_lock != 0
addq $cond_lock, %rdi
@@ -325,7 +339,8 @@ __pthread_cond_timedwait:
decq %rcx
20: testq %rcx, %rcx
movq 8(%rsp), %rdi
- js 13b
+ movq $-ETIMEDOUT, %r14
+ js 6b
jmp 21b
#endif
.LENDCODE:
@@ -394,7 +409,7 @@ versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
.uleb128 4
.byte 0x40+.Lsubq-.Lpush_r14 # DW_CFA_advance_loc+N
.byte 14 # DW_CFA_def_cfa_offset
- .uleb128 112
+ .uleb128 32+FRAME_SIZE
.byte 3 # DW_CFA_advance_loc2
.2byte .Laddq-.Lsubq
.byte 14 # DW_CFA_def_cfa_offset
@@ -413,7 +428,7 @@ versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait,
.byte 0xcc # DW_CFA_restore %r12
.byte 0x40+.LSbl1-.Lpop_r12 # DW_CFA_advance_loc+N
.byte 14 # DW_CFA_def_cfa_offset
- .uleb128 112
+ .uleb128 32+FRAME_SIZE
.byte 0x8c # DW_CFA_offset %r12
.uleb128 2
.byte 0x8d # DW_CFA_offset %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 e572874d7a..065eb11813 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
@@ -61,11 +61,15 @@ __condvar_cleanup:
subq $cond_lock, %rdi
#endif
-1: incq wakeup_seq(%rdi)
+1: movl broadcast_seq(%rdi), %edx
+ cmpl 4(%r8), %edx
+ jne 3f
+
+ incq wakeup_seq(%rdi)
incq woken_seq(%rdi)
- LOCK
+3: LOCK
#if cond_lock == 0
decl (%rdi)
#else
@@ -99,20 +103,23 @@ __pthread_cond_wait:
.LSTARTCODE:
pushq %r12
.Lpush_r12:
- subq $64, %rsp
+#define FRAME_SIZE 64
+ subq $FRAME_SIZE, %rsp
.Lsubq:
/* Stack frame:
rsp + 64
+--------------------------+
rsp + 32 | cleanup buffer |
- +--------------------------+
+ +--------------------------+
rsp + 24 | old wake_seq value |
+--------------------------+
rsp + 16 | mutex pointer |
+--------------------------+
rsp + 8 | condvar pointer |
+--------------------------+
+ rsp + 4 | old broadcast_seq value |
+ +--------------------------+
rsp + 0 | old cancellation mode |
+--------------------------+
*/
@@ -161,7 +168,9 @@ __pthread_cond_wait:
/* Get and store current wakeup_seq value. */
movq 8(%rsp), %rdi
movq wakeup_seq(%rdi), %r12
+ movl broadcast_seq(%rdi), %edx
movq %r12, 24(%rsp)
+ movl %edx, 4(%rsp)
/* Unlock. */
8: LOCK
@@ -198,10 +207,15 @@ __pthread_cond_wait:
#endif
jnz 5f
-6: movq woken_seq(%rdi), %rax
+6: movl broadcast_seq(%rdi), %edx
+
+ movq woken_seq(%rdi), %rax
movq wakeup_seq(%rdi), %r12
+ cmpl 4(%rsp), %edx
+ jne 16f
+
cmpq 24(%rsp), %r12
jbe 8b
@@ -210,7 +224,8 @@ __pthread_cond_wait:
incq woken_seq(%rdi)
- LOCK
+ /* Unlock */
+16: LOCK
#if cond_lock == 0
decl (%rdi)
#else
@@ -224,7 +239,7 @@ __pthread_cond_wait:
movq 16(%rsp), %rdi
callq __pthread_mutex_cond_lock
-14: addq $64, %rsp
+14: addq $FRAME_SIZE, %rsp
.Laddq:
popq %r12
@@ -242,7 +257,7 @@ __pthread_cond_wait:
callq __lll_mutex_lock_wait
jmp 2b
- /* Unlock in loop requires waekup. */
+ /* Unlock in loop requires wakeup. */
3:
#if cond_lock != 0
addq $cond_lock, %rdi
@@ -343,7 +358,7 @@ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait,
.uleb128 2
.byte 0x40+.Lsubq-.Lpush_r12 # DW_CFA_advance_loc+N
.byte 14 # DW_CFA_def_cfa_offset
- .uleb128 80
+ .uleb128 16+FRAME_SIZE
.byte 2 # DW_CFA_advance_loc1
.byte .Laddq-.Lsubq
.byte 14 # DW_CFA_def_cfa_offset
diff --git a/nptl/tst-cond16.c b/nptl/tst-cond16.c
new file mode 100644
index 0000000000..00c27eced6
--- /dev/null
+++ b/nptl/tst-cond16.c
@@ -0,0 +1,105 @@
+/* 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 <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+bool n, exiting;
+FILE *f;
+int count;
+
+void *
+tf (void *dummy)
+{
+ bool loop = true;
+
+ while (loop)
+ {
+ pthread_mutex_lock (&lock);
+ while (n && !exiting)
+ pthread_cond_wait (&cv, &lock);
+ n = true;
+ pthread_mutex_unlock (&lock);
+
+ fputs (".", f);
+
+ pthread_mutex_lock (&lock);
+ n = false;
+ if (exiting)
+ loop = false;
+#ifdef UNLOCK_AFTER_BROADCAST
+ pthread_cond_broadcast (&cv);
+ pthread_mutex_unlock (&lock);
+#else
+ pthread_mutex_unlock (&lock);
+ pthread_cond_broadcast (&cv);
+#endif
+ }
+
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ f = fopen ("/dev/null", "w");
+ if (f == NULL)
+ {
+ printf ("couldn't open /dev/null, %m\n");
+ return 1;
+ }
+
+ count = sysconf (_SC_NPROCESSORS_ONLN);
+ if (count <= 0)
+ count = 1;
+ count *= 4;
+
+ pthread_t th[count];
+ int i, ret;
+ for (i = 0; i < count; ++i)
+ if ((ret = pthread_create (&th[i], NULL, tf, NULL)) != 0)
+ {
+ errno = ret;
+ printf ("pthread_create %d failed: %m\n", i);
+ return 1;
+ }
+
+ struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 };
+ while (nanosleep (&ts, &ts) != 0);
+
+ pthread_mutex_lock (&lock);
+ exiting = true;
+ pthread_mutex_unlock (&lock);
+
+ for (i = 0; i < count; ++i)
+ pthread_join (th[i], NULL);
+
+ fclose (f);
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 40
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond17.c b/nptl/tst-cond17.c
new file mode 100644
index 0000000000..0586fa59ac
--- /dev/null
+++ b/nptl/tst-cond17.c
@@ -0,0 +1,2 @@
+#define UNLOCK_AFTER_BROADCAST 1
+#include "tst-cond16.c"
diff --git a/nptl/tst-cond18.c b/nptl/tst-cond18.c
new file mode 100644
index 0000000000..9fd81d2988
--- /dev/null
+++ b/nptl/tst-cond18.c
@@ -0,0 +1,117 @@
+/* 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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+bool exiting;
+int fd, count, spins, nn;
+
+void *
+tf (void *id)
+{
+ pthread_mutex_lock (&lock);
+
+ if ((long) id == 0)
+ {
+ while (!exiting)
+ {
+ if ((spins++ % 1000) == 0)
+ write (fd, ".", 1);
+ pthread_mutex_unlock (&lock);
+
+ pthread_mutex_lock (&lock);
+ int njobs = rand () % (count + 1);
+ nn = njobs;
+ if ((rand () % 30) == 0)
+ pthread_cond_broadcast (&cv);
+ else
+ while (njobs--)
+ pthread_cond_signal (&cv);
+ }
+
+ pthread_cond_broadcast (&cv);
+ }
+ else
+ {
+ while (!exiting)
+ {
+ while (!nn && !exiting)
+ pthread_cond_wait (&cv, &lock);
+ --nn;
+ pthread_mutex_unlock (&lock);
+
+ pthread_mutex_lock (&lock);
+ }
+ }
+
+ pthread_mutex_unlock (&lock);
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd < 0)
+ {
+ printf ("couldn't open /dev/null, %m\n");
+ return 1;
+ }
+
+ count = sysconf (_SC_NPROCESSORS_ONLN);
+ if (count <= 0)
+ count = 1;
+ count *= 8;
+
+ pthread_t th[count + 1];
+ int i, ret;
+
+ for (i = 0; i <= count; ++i)
+ if ((ret = pthread_create (&th[i], NULL, tf, (void *) (long) i)) != 0)
+ {
+ errno = ret;
+ printf ("pthread_create %d failed: %m\n", i);
+ return 1;
+ }
+
+ struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 };
+ while (nanosleep (&ts, &ts) != 0);
+
+ pthread_mutex_lock (&lock);
+ exiting = true;
+ pthread_mutex_unlock (&lock);
+
+ for (i = 0; i < count; ++i)
+ pthread_join (th[i], NULL);
+
+ close (fd);
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 40
+#include "../test-skeleton.c"