diff options
author | Ulrich Drepper <drepper@redhat.com> | 2004-05-18 20:18:14 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2004-05-18 20:18:14 +0000 |
commit | 893a351195a2997133892ffac80573a9984ba4cf (patch) | |
tree | ad1b9f1a9e7d55b25353c57f9fbd5f76c4804054 /nptl | |
parent | d40eb37aad4145ae4d047b6d7f633f740bf3a610 (diff) | |
download | glibc-893a351195a2997133892ffac80573a9984ba4cf.tar glibc-893a351195a2997133892ffac80573a9984ba4cf.tar.gz glibc-893a351195a2997133892ffac80573a9984ba4cf.tar.bz2 glibc-893a351195a2997133892ffac80573a9984ba4cf.zip |
[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')
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" |