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.
This commit is contained in:
Ulrich Drepper 2004-09-02 18:59:24 +00:00
parent 86aca5ac58
commit 73f7c32c47
28 changed files with 643 additions and 96 deletions

View File

@ -1,3 +1,14 @@
2004-09-02 Steven Munroe <sjmunroe@us.ibm.com>
[BZ #357]
* stdlib/tst-setcontext.c (test_stack): Added test for stack clobber.
(main): Call test_stack.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S
(__getcontext): Push stack frame then save parms in local frame.
Improve instruction scheduling.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S
(__swapcontext): Likewise.
2004-09-01 Andreas Schwab <schwab@suse.de>
* sysdeps/unix/sysv/linux/ia64/sys/ucontext.h [g++ >= 3.5]: Use

View File

@ -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

View File

@ -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 \

View File

@ -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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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];

View File

@ -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];

View File

@ -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)

View File

@ -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)

View File

@ -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];

View File

@ -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
{

View File

@ -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

View File

@ -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];

View File

@ -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];

View File

@ -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];

View File

@ -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];

View File

@ -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];

View File

@ -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

View File

@ -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

170
nptl/tst-cond20.c Normal file
View File

@ -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"

3
nptl/tst-cond21.c Normal file
View File

@ -0,0 +1,3 @@
#include <sys/time.h>
#define TIMED 1
#include "tst-cond20.c"

View File

@ -72,6 +72,55 @@ f2 (void)
was_in_f2 = 1;
}
void
test_stack(volatile int a, volatile int b,
volatile int c, volatile int d)
{
volatile int e = 5;
volatile int f = 6;
ucontext_t uc;
/* Test for cases where getcontext is clobbering the callers
stack, including parameters. */
getcontext(&uc);
if (a != 1)
{
printf ("%s: getcontext clobbers parm a\n", __FUNCTION__);
exit (1);
}
if (b != 2)
{
printf ("%s: getcontext clobbers parm b\n", __FUNCTION__);
exit (1);
}
if (c != 3)
{
printf ("%s: getcontext clobbers parm c\n", __FUNCTION__);
exit (1);
}
if (d != 4)
{
printf ("%s: getcontext clobbers parm d\n", __FUNCTION__);
exit (1);
}
if (e != 5)
{
printf ("%s: getcontext clobbers varible e\n", __FUNCTION__);
exit (1);
}
if (f != 6)
{
printf ("%s: getcontext clobbers variable f\n", __FUNCTION__);
exit (1);
}
}
volatile int global;
int
@ -88,6 +137,8 @@ main (void)
printf ("%s: getcontext: %m\n", __FUNCTION__);
exit (1);
}
test_stack (1, 2, 3, 4);
/* Play some tricks with this context. */
if (++global == 1)

View File

@ -27,18 +27,22 @@
.machine "altivec"
ENTRY(__getcontext)
stwu r1,-16(r1)
/* Insure that the _UC_REGS start on a quadword boundary. */
stw r3,_FRAME_PARM_SAVE1(r1)
addi r3,r3,_UC_REG_SPACE+12
clrrwi r3,r3,4
/* Save the general purpose registers */
stw r0,_UC_GREGS+(PT_R0*4)(r3)
mflr r0
stw r1,_UC_GREGS+(PT_R1*4)(r3)
stwu r1,-16(r1)
stw r2,_UC_GREGS+(PT_R2*4)(r3)
stw r4,_UC_GREGS+(PT_R4*4)(r3)
/* Set the callers LR_SAVE, and the ucontext LR and NIP to the callers
return address. */
stw r0,_UC_GREGS+(PT_LNK*4)(r3)
stw r0,_UC_GREGS+(PT_NIP*4)(r3)
stw r0,_FRAME_LR_SAVE+16(r1)
stw r2,_UC_GREGS+(PT_R2*4)(r3)
stw r4,_UC_GREGS+(PT_R4*4)(r3)
stw r5,_UC_GREGS+(PT_R5*4)(r3)
stw r6,_UC_GREGS+(PT_R6*4)(r3)
stw r7,_UC_GREGS+(PT_R7*4)(r3)
@ -66,23 +70,28 @@ ENTRY(__getcontext)
stw r29,_UC_GREGS+(PT_R29*4)(r3)
stw r30,_UC_GREGS+(PT_R30*4)(r3)
stw r31,_UC_GREGS+(PT_R31*4)(r3)
mfctr r0
stw r0,_UC_GREGS+(PT_CTR*4)(r3)
mfxer r0
stw r0,_UC_GREGS+(PT_XER*4)(r3)
mfcr r0
stw r0,_UC_GREGS+(PT_CCR*4)(r3)
/* Set the return value of getcontext to "success". R3 is the only
register whose value is not preserved in the saved context. */
/* Save the value of R1. We had to push the stack before we
had the address of uc_reg_space. So compute the address of
the callers stack pointer and save it as R1. */
addi r8,r1,16
li r0,0
/* Save the count, exception and condition registers. */
mfctr r11
mfxer r10
mfcr r9
stw r8,_UC_GREGS+(PT_R1*4)(r3)
stw r11,_UC_GREGS+(PT_CTR*4)(r3)
stw r10,_UC_GREGS+(PT_XER*4)(r3)
stw r9,_UC_GREGS+(PT_CCR*4)(r3)
/* Set the return value of getcontext to "success". R3 is the only
register whose value is not preserved in the saved context. */
stw r0,_UC_GREGS+(PT_R3*4)(r3)
/* Zero fill fields that can't be set in user state. */
/* Zero fill fields that can't be set in user state. */
stw r0,_UC_GREGS+(PT_MSR*4)(r3)
stw r0,_UC_GREGS+(PT_MQ*4)(r3)
/* Save the floating-point registers */
/* Save the floating-point registers */
stfd fp0,_UC_FREGS+(0*8)(r3)
stfd fp1,_UC_FREGS+(1*8)(r3)
stfd fp2,_UC_FREGS+(2*8)(r3)
@ -136,21 +145,31 @@ ENTRY(__getcontext)
lwz r7,_dl_hwcap@l(r7)
#endif
andis. r7,r7,(PPC_FEATURE_HAS_ALTIVEC >> 16)
beq L(no_vec)
la r10,(_UC_VREGS)(r3)
la r9,(_UC_VREGS+16)(r3)
beq L(no_vec)
/* address of the combined VSCR/VSAVE quadword. */
la r8,(_UC_VREGS+512)(r3)
/* Save the vector registers */
stvx v0,0,r10
stvx v1,0,r9
addi r10,r10,32
addi r9,r9,32
/* We need to get the Vector Status and Control Register early to avoid
store order problems later with the VSAVE register that shares the
same quadword. */
mfvscr v0
stvx v2,0,r10
stvx v3,0,r9
addi r10,r10,32
addi r9,r9,32
stvx v0,0,r8
stvx v4,0,r10
stvx v5,0,r9
addi r10,r10,32
@ -216,20 +235,18 @@ ENTRY(__getcontext)
addi r10,r10,32
addi r9,r9,32
mfspr r0,VRSAVE
stvx v30,0,r10
stvx v31,0,r9
addi r10,r10,32
addi r9,r9,32
mfvscr v0
mfspr r0,VRSAVE
stvx v0,0,r10
sync
stw r0,0(r10)
stw r0,0(r8)
L(no_vec):
/* Restore ucontext (parm1) from stack. */
lwz r12,_FRAME_PARM_SAVE1+16(r1)
/* We need to set up parms and call sigprocmask which will clobber
volatile registers. So before the call we need to retrieve the
original ucontext ptr (parm1) from stack and store the UC_REGS_PTR
(current R3). */
lwz r12,_FRAME_PARM_SAVE1(r1)
li r4,0
stw r3,_UC_REGS_PTR(r12)
addi r5,r12,_UC_SIGMASK

View File

@ -27,22 +27,23 @@
.machine "altivec"
ENTRY(__swapcontext)
/* Save the current context */
stwu r1,-16(r1)
/* Insure that the _UC_REGS start on a quadword boundary. */
stw r3,_FRAME_PARM_SAVE1(r1)
addi r3,r3,_UC_REG_SPACE+12
stw r4,_FRAME_PARM_SAVE2(r1) /* new context pointer */
clrrwi r3,r3,4
/* Save the general purpose registers */
stw r0,_UC_GREGS+(PT_R0*4)(r3)
stw r1,_UC_GREGS+(PT_R1*4)(r3)
mflr r0
stwu r1,-16(r1)
stw r0,20(r1)
stw r31,12(r1)
stw r31,_UC_GREGS+(PT_R31*4)(r3)
mr r31,r4 /* new context pointer */
stw r2,_UC_GREGS+(PT_R2*4)(r3)
stw r4,_UC_GREGS+(PT_R4*4)(r3)
/* Set the callers LR_SAVE, and the ucontext LR and NIP to the callers
return address. */
stw r0,_UC_GREGS+(PT_LNK*4)(r3)
stw r0,_UC_GREGS+(PT_NIP*4)(r3)
stw r2,_UC_GREGS+(PT_R2*4)(r3)
stw r4,_UC_GREGS+(PT_R4*4)(r3)
stw r0,_FRAME_LR_SAVE+16(r1)
stw r5,_UC_GREGS+(PT_R5*4)(r3)
stw r6,_UC_GREGS+(PT_R6*4)(r3)
stw r7,_UC_GREGS+(PT_R7*4)(r3)
@ -69,16 +70,23 @@ ENTRY(__swapcontext)
stw r28,_UC_GREGS+(PT_R28*4)(r3)
stw r29,_UC_GREGS+(PT_R29*4)(r3)
stw r30,_UC_GREGS+(PT_R30*4)(r3)
mfctr r0
stw r0,_UC_GREGS+(PT_CTR*4)(r3)
mfxer r0
stw r0,_UC_GREGS+(PT_XER*4)(r3)
mfcr r0
stw r0,_UC_GREGS+(PT_CCR*4)(r3)
/* Set the return value of swapcontext to "success". R3 is the only
register whose value is not preserved in the saved context. */
stw r31,_UC_GREGS+(PT_R31*4)(r3)
/* Save the value of R1. We had to push the stack before we
had the address of uc_reg_space. So compute the address of
the callers stack pointer and save it as R1. */
addi r8,r1,16
li r0,0
/* Save the count, exception and condition registers. */
mfctr r11
mfxer r10
mfcr r9
stw r8,_UC_GREGS+(PT_R1*4)(r3)
stw r11,_UC_GREGS+(PT_CTR*4)(r3)
stw r10,_UC_GREGS+(PT_XER*4)(r3)
stw r9,_UC_GREGS+(PT_CCR*4)(r3)
/* Set the return value of getcontext to "success". R3 is the only
register whose value is not preserved in the saved context. */
stw r0,_UC_GREGS+(PT_R3*4)(r3)
/* Zero fill fields that can't be set in user state. */
@ -138,20 +146,30 @@ ENTRY(__swapcontext)
lwz r7,_dl_hwcap@l(r7)
#endif
andis. r7,r7,(PPC_FEATURE_HAS_ALTIVEC >> 16)
beq L(no_vec)
la r10,(_UC_VREGS)(r3)
la r9,(_UC_VREGS+16)(r3)
beq L(no_vec)
/* address of the combined VSCR/VSAVE quadword. */
la r8,(_UC_VREGS+512)(r3)
/* Save the vector registers */
stvx v0,0,r10
stvx v1,0,r9
addi r10,r10,32
addi r9,r9,32
/* We need to get the Vector Status and Control Register early to avoid
store order problems later with the VSAVE register that shares the
same quadword. */
mfvscr v0
stvx v2,0,r10
stvx v3,0,r9
addi r10,r10,32
addi r9,r9,32
stvx v0,0,r8
stvx v4,0,r10
stvx v5,0,r9
@ -218,20 +236,15 @@ ENTRY(__swapcontext)
addi r10,r10,32
addi r9,r9,32
mfvscr v0
stvx v30,0,r10
stvx v31,0,r9
addi r10,r10,32
addi r9,r9,32
mfvscr v0
mfspr r0,VRSAVE
stvx v0,0,r10
sync
stw r0,0(r10)
stw r0,0(r8)
L(no_vec):
/* Restore ucontext (parm1) from stack. */
lwz r12,_FRAME_PARM_SAVE1+16(r1)
lwz r12,_FRAME_PARM_SAVE1(r1)
li r4,0
stw r3,_UC_REGS_PTR(r12)
addi r5,r12,_UC_SIGMASK
@ -251,8 +264,8 @@ L(no_vec):
* r0, xer, ctr. We don't restore r2 since it will be used as
* the TLS pointer.
*/
mr r4,r31
lwz r31,_UC_REGS_PTR(r31)
lwz r4,_FRAME_PARM_SAVE2(r1)
lwz r31,_UC_REGS_PTR(r4)
lwz r0,_UC_GREGS+(PT_MSR*4)(r31)
cmpwi r0,0
bne L(do_sigret)
@ -451,8 +464,7 @@ L(has_no_vec):
bctr
L(error_exit):
lwz r31,12(r1)
lwz r0,20(r1)
lwz r0,_FRAME_LR_SAVE+16(r1)
addi r1,r1,16
mtlr r0
blr