mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-09 23:00:07 +00:00
[BZ #357]
Update. 2004-09-02 Steven Munroe <sjmunroe@us.ibm.com> [BZ #357] * stdlib/tst-setcontext.c (test_stack): Added test for stack clobber. (main): Call test_stack. * sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S (__getcontext): Push stack frame then save parms in local frame. Improve instruction scheduling. * sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S (__swapcontext): Likewise.
This commit is contained in:
parent
86aca5ac58
commit
73f7c32c47
11
ChangeLog
11
ChangeLog
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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
170
nptl/tst-cond20.c
Normal 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
3
nptl/tst-cond21.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include <sys/time.h>
|
||||
#define TIMED 1
|
||||
#include "tst-cond20.c"
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user