[BZ #357]
authorUlrich Drepper <drepper@redhat.com>
Thu, 2 Sep 2004 18:59:24 +0000 (18:59 +0000)
committerUlrich Drepper <drepper@redhat.com>
Thu, 2 Sep 2004 18:59:24 +0000 (18:59 +0000)
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.

28 files changed:
ChangeLog
nptl/ChangeLog
nptl/Makefile
nptl/pthread_cond_destroy.c
nptl/pthread_cond_init.c
nptl/pthread_condattr_getclock.c
nptl/pthread_condattr_setclock.c
nptl/sysdeps/pthread/pthread_cond_timedwait.c
nptl/sysdeps/pthread/pthread_cond_wait.c
nptl/sysdeps/unix/sysv/linux/alpha/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S
nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S
nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/internaltypes.h
nptl/sysdeps/unix/sysv/linux/lowlevelcond.sym
nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/sparc/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h
nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S
nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S
nptl/tst-cond20.c [new file with mode: 0644]
nptl/tst-cond21.c [new file with mode: 0644]
stdlib/tst-setcontext.c
sysdeps/unix/sysv/linux/powerpc/powerpc32/getcontext.S
sysdeps/unix/sysv/linux/powerpc/powerpc32/swapcontext.S

index 30afaf5..d5a2c90 100644 (file)
--- a/ChangeLog
+++ b/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
index 2aa77d9..6306a7b 100644 (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
index e797f4d..e75752f 100644 (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 \
index 5ade3e6..0208d18 100644 (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,
index f5fbd64..03ac59d 100644 (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;
index f8be655..84de918 100644 (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;
 }
index 0f1829c..04e246b 100644 (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;
 }
index 7de2b29..c6606c9 100644 (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);
 
index 45187b5..8666945 100644 (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);
 
index 62c853c..fd20d57 100644 (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];
index 8d7858a..fb62c0d 100644 (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];
index eecec8a..699c2cb 100644 (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)
index 3fe7f8c..d282785 100644 (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)
index 958af47..5b442cb 100644 (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];
index 43b6856..1dec19e 100644 (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
 {
index 2e193e6..c5e7978 100644 (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
index 5a000d3..a493821 100644 (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];
index 1422864..17cfaa9 100644 (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];
index b8afbc5..5bf3aff 100644 (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];
index e86dd00..34d3df7 100644 (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];
index a7bc581..e5cc605 100644 (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];
index 95f8aab..67bec6c 100644 (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
index 9e7da30..f5de0a2 100644 (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
diff --git a/nptl/tst-cond20.c b/nptl/tst-cond20.c
new file mode 100644 (file)
index 0000000..ba50d58
--- /dev/null
@@ -0,0 +1,170 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define N 10
+#define ROUNDS 1000
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+static pthread_barrier_t b;
+static int count;
+
+static void *
+tf (void *p)
+{
+  int i;
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      pthread_mutex_lock (&mut);
+
+      if (++count == N)
+       pthread_cond_signal (&cond2);
+
+#ifdef TIMED
+      struct timeval tv;
+      gettimeofday (&tv, NULL);
+      struct timespec ts;
+      /* Wait three second.  */
+      ts.tv_sec = tv.tv_sec + 3;
+      ts.tv_nsec = tv.tv_usec * 1000;
+      pthread_cond_timedwait (&cond, &mut, &ts);
+#else
+      pthread_cond_wait (&cond, &mut);
+#endif
+
+      pthread_mutex_unlock (&mut);
+
+      int err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("child: barrier_wait failed");
+         exit (1);
+       }
+
+      err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("child: barrier_wait failed");
+         exit (1);
+       }
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, N + 1) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_mutex_lock (&mut);
+
+  int i, j, err;
+  pthread_t th[N];
+  for (i = 0; i < N; ++i)
+    if ((err = pthread_create (&th[i], NULL, tf, NULL)) != 0)
+      {
+       printf ("cannot create thread %d: %s\n", i, strerror (err));
+       return 1;
+      }
+
+  for (i = 0; i < ROUNDS; ++i)
+    {
+      pthread_cond_wait (&cond2, &mut);
+
+      if (i & 1)
+        pthread_mutex_unlock (&mut);
+
+      if (i & 2)
+       pthread_cond_broadcast (&cond);
+      else if (i & 4)
+       for (j = 0; j < N; ++j)
+         pthread_cond_signal (&cond);
+      else
+       {
+         for (j = 0; j < (i / 8) % N; ++j)
+           pthread_cond_signal (&cond);
+         pthread_cond_broadcast (&cond);
+       }
+
+      if ((i & 1) == 0)
+        pthread_mutex_unlock (&mut);
+
+      err = pthread_cond_destroy (&cond);
+      if (err)
+       {
+         printf ("pthread_cond_destroy failed: %s\n", strerror (err));
+         return 1;
+       }
+
+      /* Now clobber the cond variable which has been successfully
+         destroyed above.  */
+      memset (&cond, (char) i, sizeof (cond));
+
+      err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("parent: barrier_wait failed");
+         return 1;
+       }
+
+      pthread_mutex_lock (&mut);
+
+      err = pthread_barrier_wait (&b);
+      if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
+       {
+         puts ("parent: barrier_wait failed");
+         return 1;
+       }
+
+      count = 0;
+      err = pthread_cond_init (&cond, NULL);
+      if (err)
+       {
+         printf ("pthread_cond_init failed: %s\n", strerror (err));
+         return 1;
+       }
+    }
+
+  for (i = 0; i < N; ++i)
+    if ((err = pthread_join (th[i], NULL)) != 0)
+      {
+       printf ("failed to join thread %d: %s\n", i, strerror (err));
+       return 1;
+      }
+
+  puts ("done");
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-cond21.c b/nptl/tst-cond21.c
new file mode 100644 (file)
index 0000000..89cb771
--- /dev/null
@@ -0,0 +1,3 @@
+#include <sys/time.h>
+#define TIMED 1
+#include "tst-cond20.c"
index 89b8cdf..c8f7fdb 100644 (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)
index 6e4bc63..4c75354 100644 (file)
 
        .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
index af54e18..c4f0fad 100644 (file)
 
        .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