about summary refs log tree commit diff
path: root/nptl/sysdeps/unix
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/unix')
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h16
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c (renamed from nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c)60
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sem_post.c69
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sem_timedwait.c112
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sem_wait.c117
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c51
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c100
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c16
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c127
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c2
-rw-r--r--nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c2
13 files changed, 588 insertions, 87 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h
index 4d0ea51723..4f400a3fe3 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/internaltypes.h
@@ -15,4 +15,20 @@ union sparc_pthread_barrier
     } s;
 };
 
+struct sparc_new_sem
+{
+  unsigned int value;
+  unsigned char lock;
+  unsigned char private;
+  unsigned char pad[2];
+  unsigned long int nwaiters;
+};
+
+struct sparc_old_sem
+{
+  unsigned int value;
+  unsigned char lock;
+  unsigned char private;
+};
+
 #endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c b/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c
index dffd8c7efa..840032a08c 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_init.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sem_init.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
 
@@ -18,20 +18,50 @@
    02111-1307 USA.  */
 
 #include <errno.h>
+#include <string.h>
 #include <semaphore.h>
 #include <lowlevellock.h>
 #include <shlib-compat.h>
 #include "semaphoreP.h"
+#include <kernel-features.h>
 
-struct sparc_sem
+
+int
+__new_sem_init (sem, pshared, value)
+     sem_t *sem;
+     int pshared;
+     unsigned int value;
 {
-  struct sem s;
-  unsigned char lock;
-};
+  /* Parameter sanity check.  */
+  if (__builtin_expect (value > SEM_VALUE_MAX, 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
 
+  /* Map to the internal type.  */
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
 
+  /* Use the values the user provided.  */
+  memset (isem, '\0', sizeof (*isem));
+  isem->value = value;
+#ifdef __ASSUME_PRIVATE_FUTEX
+  isem->private = pshared ? 0 : FUTEX_PRIVATE_FLAG;
+#else
+  isem->private = pshared ? 0 : THREAD_GETMEM (THREAD_SELF,
+					       header.private_futex);
+#endif
+
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
+
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
 int
-__new_sem_init (sem, pshared, value)
+attribute_compat_text_section
+__old_sem_init (sem, pshared, value)
      sem_t *sem;
      int pshared;
      unsigned int value;
@@ -44,20 +74,20 @@ __new_sem_init (sem, pshared, value)
     }
 
   /* Map to the internal type.  */
-  struct sparc_sem *isem = (struct sparc_sem *) sem;
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
 
   /* Use the value the user provided.  */
-  isem->s.count = value;
-
-  isem->lock = 0;
+  memset (isem, '\0', sizeof (*isem));
+  isem->value = value;
 
-  /* We can completely ignore the PSHARED parameter since inter-process
-     use needs no special preparation.  */
+#ifdef __ASSUME_PRIVATE_FUTEX
+  isem->private = pshared ? 0 : FUTEX_PRIVATE_FLAG;
+#else
+  isem->private = pshared ? 0 : THREAD_GETMEM (THREAD_SELF,
+					       header.private_futex);
+#endif
 
   return 0;
 }
-versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
-#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
-strong_alias (__new_sem_init, __old_sem_init)
 compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0);
 #endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sem_post.c b/nptl/sysdeps/unix/sysv/linux/sparc/sem_post.c
new file mode 100644
index 0000000000..95964d0744
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sem_post.c
@@ -0,0 +1,69 @@
+/* sem_post -- post to a POSIX semaphore.  SPARC version.
+   Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <shlib-compat.h>
+
+int
+__new_sem_post (sem_t *sem)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+
+  int nr = atomic_increment_val (&isem->value);
+  atomic_full_barrier ();
+  if (isem->nwaiters > 0)
+    {
+      int err = lll_futex_wake (&isem->value, 1,
+				isem->private ^ FUTEX_PRIVATE_FLAG);
+      if (__builtin_expect (err, 0) < 0)
+	{
+	  __set_errno (-err);
+	  return -1;
+	}
+    }
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
+
+
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+attribute_compat_text_section
+__old_sem_post (sem_t *sem)
+{
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
+
+  int nr = atomic_increment_val (&isem->value);
+  int err = lll_futex_wake (&isem->value, 1,
+			    isem->private ^ FUTEX_PRIVATE_FLAG);
+  if (__builtin_expect (err, 0) < 0)
+    {
+      __set_errno (-err);
+      return -1;
+    }
+  return 0;
+}
+compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sem_timedwait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sem_timedwait.c
new file mode 100644
index 0000000000..01952f3f9a
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sem_timedwait.c
@@ -0,0 +1,112 @@
+/* sem_timedwait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <pthreadP.h>
+#include <shlib-compat.h>
+
+
+extern void __sem_wait_cleanup (void *arg) attribute_hidden;
+
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *abstime)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int err;
+
+  if (atomic_decrement_if_positive (&isem->value) > 0)
+    return 0;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  atomic_increment (&isem->nwaiters);
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      struct timeval tv;
+      struct timespec rt;
+      int sec, nsec;
+
+      /* Get the current time.  */
+      __gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      sec = abstime->tv_sec - tv.tv_sec;
+      nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+      if (nsec < 0)
+	{
+	  nsec += 1000000000;
+	  --sec;
+	}
+
+      /* Already timed out?  */
+      err = -ETIMEDOUT;
+      if (sec < 0)
+	{
+	  __set_errno (ETIMEDOUT);
+	  err = -1;
+	  break;
+	}
+
+      /* Do wait.  */
+      rt.tv_sec = sec;
+      rt.tv_nsec = nsec;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_timed_wait (&isem->value, 0, &rt,
+				  isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+	{
+	  __set_errno (-err);
+	  err = -1;
+	  break;
+	}
+
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+	{
+	  err = 0;
+	  break;
+	}
+    }
+
+  pthread_cleanup_pop (0);
+
+  atomic_decrement (&isem->nwaiters);
+
+  return err;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sem_wait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sem_wait.c
new file mode 100644
index 0000000000..a846f20601
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sem_wait.c
@@ -0,0 +1,117 @@
+/* sem_wait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <pthreadP.h>
+#include <shlib-compat.h>
+
+
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) arg;
+
+  atomic_decrement (&isem->nwaiters);
+}
+
+
+int
+__new_sem_wait (sem_t *sem)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int err;
+
+  if (atomic_decrement_if_positive (&isem->value) > 0)
+    return 0;
+
+  atomic_increment (&isem->nwaiters);
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (&isem->value, 0,
+			    isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+	{
+	  __set_errno (-err);
+	  err = -1;
+	  break;
+	}
+
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+	{
+	  err = 0;
+	  break;
+	}
+    }
+
+  pthread_cleanup_pop (0);
+
+  atomic_decrement (&isem->nwaiters);
+
+  return err;
+}
+versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
+
+
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+attribute_compat_text_section
+__old_sem_wait (sem_t *sem)
+{
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
+  int err;
+
+  do
+    {
+      if (atomic_decrement_if_positive (&isem->value) > 0)
+	return 0;
+
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (&isem->value, 0,
+			    isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+    }
+  while (err == 0 || err == -EWOULDBLOCK);
+
+  __set_errno (-err);
+  return -1;
+}
+
+compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c
index 527aedfdc7..dbd34f2210 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_post.c
@@ -29,19 +29,51 @@
 int
 __new_sem_post (sem_t *sem)
 {
-  int *futex = (int *) sem, nr;
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int nr;
 
   if (__atomic_is_v9)
-    nr = atomic_increment_val (futex);
+    nr = atomic_increment_val (&isem->value);
   else
     {
-      __sparc32_atomic_do_lock24 (futex + 1);
-      nr = ++*futex;
-      __sparc32_atomic_do_unlock24 (futex + 1);
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      nr = ++(isem->value);
+      __sparc32_atomic_do_unlock24 (&isem->lock);
     }
-  int err = lll_futex_wake (futex, nr,
-			    // XYZ check mutex flag
-			    LLL_SHARED);
+  atomic_full_barrier ();
+  if (isem->nwaiters > 0)
+    {
+      int err = lll_futex_wake (&isem->value, 1,
+				isem->private ^ FUTEX_PRIVATE_FLAG);
+      if (__builtin_expect (err, 0) < 0)
+	{
+	  __set_errno (-err);
+	  return -1;
+	}
+    }
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
+
+
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+attribute_compat_text_section
+__old_sem_post (sem_t *sem)
+{
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
+  int nr;
+
+  if (__atomic_is_v9)
+    nr = atomic_increment_val (&isem->value);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      nr = ++(isem->value);
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+  int err = lll_futex_wake (&isem->value, 1,
+			    isem->private ^ FUTEX_PRIVATE_FLAG);
   if (__builtin_expect (err, 0) < 0)
     {
       __set_errno (-err);
@@ -49,8 +81,5 @@ __new_sem_post (sem_t *sem)
     }
   return 0;
 }
-versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
-strong_alias (__new_sem_post, __old_sem_post)
 compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
 #endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c
index efcc9e9aa8..55f3e2e075 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_timedwait.c
@@ -1,5 +1,5 @@
 /* sem_timedwait -- wait on a semaphore.  SPARC version.
-   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
 
@@ -28,37 +28,48 @@
 #include <shlib-compat.h>
 
 
+extern void __sem_wait_cleanup (void *arg) attribute_hidden;
+
+
 int
 sem_timedwait (sem_t *sem, const struct timespec *abstime)
 {
-  /* First check for cancellation.  */
-  CANCELLATION_P (THREAD_SELF);
-
-  int *futex = (int *) sem;
-  int val;
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
   int err;
+  int val;
 
-  if (*futex > 0)
+  if (__atomic_is_v9)
+    val = atomic_decrement_if_positive (&isem->value);
+  else
     {
-      if (__atomic_is_v9)
-	val = atomic_decrement_if_positive (futex);
-      else
-	{
-	  __sparc32_atomic_do_lock24 (futex + 1);
-	  val = *futex;
-	  if (val > 0)
-	    *futex = val - 1;
-	  __sparc32_atomic_do_unlock24 (futex + 1);
-	}
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      val = isem->value;
       if (val > 0)
-	return 0;
+        isem->value = val - 1;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
     }
 
-  err = -EINVAL;
+  if (val > 0)
+    return 0;
+
   if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
-    goto error_return;
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (__atomic_is_v9)
+    atomic_increment (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters++;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
 
-  do
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
     {
       struct timeval tv;
       struct timespec rt;
@@ -79,7 +90,11 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
       /* Already timed out?  */
       err = -ETIMEDOUT;
       if (sec < 0)
-	goto error_return;
+	{
+	  __set_errno (ETIMEDOUT);
+	  err = -1;
+	  break;
+	}
 
       /* Do wait.  */
       rt.tv_sec = sec;
@@ -88,30 +103,47 @@ sem_timedwait (sem_t *sem, const struct timespec *abstime)
       /* Enable asynchronous cancellation.  Required by the standard.  */
       int oldtype = __pthread_enable_asynccancel ();
 
-      err = lll_futex_timed_wait (futex, 0, &rt);
+      err = lll_futex_timed_wait (&isem->value, 0, &rt,
+				  isem->private ^ FUTEX_PRIVATE_FLAG);
 
       /* Disable asynchronous cancellation.  */
       __pthread_disable_asynccancel (oldtype);
 
       if (err != 0 && err != -EWOULDBLOCK)
-	goto error_return;
+	{
+	  __set_errno (-err);
+	  err = -1;
+	  break;
+	}
 
       if (__atomic_is_v9)
-	val = atomic_decrement_if_positive (futex);
+	val = atomic_decrement_if_positive (&isem->value);
       else
 	{
-	  __sparc32_atomic_do_lock24 (futex + 1);
-	  val = *futex;
+	  __sparc32_atomic_do_lock24 (&isem->lock);
+	  val = isem->value;
 	  if (val > 0)
-	    *futex = val - 1;
-	  __sparc32_atomic_do_unlock24 (futex + 1);
+	    isem->value = val - 1;
+	  __sparc32_atomic_do_unlock24 (&isem->lock);
+	}
+
+      if (val > 0)
+	{
+	  err = 0;
+	  break;
 	}
     }
-  while (val <= 0);
 
-  return 0;
+  pthread_cleanup_pop (0);
+
+  if (__atomic_is_v9)
+    atomic_decrement (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters--;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
 
- error_return:
-  __set_errno (-err);
-  return -1;
+  return err;
 }
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c
index 429494e257..4db89727a7 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_trywait.c
@@ -1,5 +1,5 @@
 /* sem_trywait -- wait on a semaphore.  SPARC version.
-   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
 
@@ -30,20 +30,20 @@
 int
 __new_sem_trywait (sem_t *sem)
 {
-  int *futex = (int *) sem;
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
   int val;
 
-  if (*futex > 0)
+  if (isem->value > 0)
     {
       if (__atomic_is_v9)
-	val = atomic_decrement_if_positive (futex);
+	val = atomic_decrement_if_positive (&isem->value);
       else
 	{
-	  __sparc32_atomic_do_lock24 (futex + 1);
-	  val = *futex;
+	  __sparc32_atomic_do_lock24 (&isem->lock);
+	  val = isem->value;
 	  if (val > 0)
-	    *futex = val - 1;
-	  __sparc32_atomic_do_unlock24 (futex + 1);
+	    isem->value = val - 1;
+	  __sparc32_atomic_do_unlock24 (&isem->lock);
 	}
       if (val > 0)
 	return 0;
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c
index d9fcdcd4ee..3c71c969b8 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c
@@ -1,5 +1,5 @@
-/* sem_wait -- wait on a semaphore.  SPARC version.
-   Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+/* sem_wait -- wait on a semaphore.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
 
@@ -28,35 +28,135 @@
 #include <shlib-compat.h>
 
 
+void
+attribute_hidden
+__sem_wait_cleanup (void *arg)
+{
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) arg;
+
+  if (__atomic_is_v9)
+    atomic_decrement (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters--;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+}
+
+
 int
 __new_sem_wait (sem_t *sem)
 {
-  /* First check for cancellation.  */
-  CANCELLATION_P (THREAD_SELF);
+  struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
+  int err;
+  int val;
+
+  if (__atomic_is_v9)
+    val = atomic_decrement_if_positive (&isem->value);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      val = isem->value;
+      if (val > 0)
+	isem->value = val - 1;
+      else
+	isem->nwaiters++;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  if (val > 0)
+    return 0;
+
+  if (__atomic_is_v9)
+    atomic_increment (&isem->nwaiters);
+  else
+    /* Already done above while still holding isem->lock.  */;
+
+  pthread_cleanup_push (__sem_wait_cleanup, isem);
+
+  while (1)
+    {
+      /* Enable asynchronous cancellation.  Required by the standard.  */
+      int oldtype = __pthread_enable_asynccancel ();
+
+      err = lll_futex_wait (&isem->value, 0,
+			    isem->private ^ FUTEX_PRIVATE_FLAG);
+
+      /* Disable asynchronous cancellation.  */
+      __pthread_disable_asynccancel (oldtype);
+
+      if (err != 0 && err != -EWOULDBLOCK)
+	{
+	  __set_errno (-err);
+	  err = -1;
+	  break;
+	}
+
+      if (__atomic_is_v9)
+	val = atomic_decrement_if_positive (&isem->value);
+      else
+	{
+	  __sparc32_atomic_do_lock24 (&isem->lock);
+	  val = isem->value;
+	  if (val > 0)
+	    isem->value = val - 1;
+	  __sparc32_atomic_do_unlock24 (&isem->lock);
+	}
+
+      if (val > 0)
+	{
+	  err = 0;
+	  break;
+	}
+    }
+
+  pthread_cleanup_pop (0);
 
-  int *futex = (int *) sem;
+  if (__atomic_is_v9)
+    atomic_decrement (&isem->nwaiters);
+  else
+    {
+      __sparc32_atomic_do_lock24 (&isem->lock);
+      isem->nwaiters--;
+      __sparc32_atomic_do_unlock24 (&isem->lock);
+    }
+
+  return err;
+}
+versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
+
+
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+attribute_compat_text_section
+__old_sem_wait (sem_t *sem)
+{
+  struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
   int err;
+  int val;
 
   do
     {
-      int val;
       if (__atomic_is_v9)
-	val = atomic_decrement_if_positive (futex);
+	val = atomic_decrement_if_positive (&isem->value);
       else
 	{
-	  __sparc32_atomic_do_lock24 (futex + 1);
-	  val = *futex;
+	  __sparc32_atomic_do_lock24 (&isem->lock);
+	  val = isem->value;
 	  if (val > 0)
-	    *futex = val - 1;
-	  __sparc32_atomic_do_unlock24 (futex + 1);
+	    isem->value = val - 1;
+	  __sparc32_atomic_do_unlock24 (&isem->lock);
 	}
+
       if (val > 0)
 	return 0;
 
       /* Enable asynchronous cancellation.  Required by the standard.  */
       int oldtype = __pthread_enable_asynccancel ();
 
-      err = lll_futex_wait (futex, 0);
+      err = lll_futex_wait (futex, 0,
+			    isem->private ^ FUTEX_PRIVATE_FLAG);
 
       /* Disable asynchronous cancellation.  */
       __pthread_disable_asynccancel (oldtype);
@@ -67,8 +167,5 @@ __new_sem_wait (sem_t *sem)
   return -1;
 }
 
-versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
-#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
-strong_alias (__new_sem_wait, __old_sem_wait)
 compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
 #endif
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c
deleted file mode 100644
index b2ebc4cbb5..0000000000
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_init.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "../../../../../../../sem_init.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c
index 4a6eac88f5..73d7c56675 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_post.c
@@ -1 +1 @@
-#include "../../../sem_post.c"
+#include "../../sem_post.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c
index b2526db02c..03945b7279 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_timedwait.c
@@ -1 +1 @@
-#include "../../../sem_timedwait.c"
+#include "../../sem_timedwait.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c
index 31157f636f..a5dbc5a4b8 100644
--- a/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c
+++ b/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sparcv9/sem_wait.c
@@ -1 +1 @@
-#include "../../../sem_wait.c"
+#include "../../sem_wait.c"