aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/sparc
diff options
context:
space:
mode:
authorRoland McGrath <roland@hack.frob.com>2014-06-20 17:13:47 -0700
committerRoland McGrath <roland@hack.frob.com>2014-06-20 17:13:47 -0700
commit4b88139b6f22b70048793725a6c3f67bddc7baee (patch)
treec686a38eb7cb9540d217a077a258713f3bf8304f /sysdeps/sparc
parent9bc6103d0460686a92105410a306252238d952d8 (diff)
downloadglibc-4b88139b6f22b70048793725a6c3f67bddc7baee.zip
glibc-4b88139b6f22b70048793725a6c3f67bddc7baee.tar.gz
glibc-4b88139b6f22b70048793725a6c3f67bddc7baee.tar.bz2
Move remaining SPARC code out of nptl/.
Diffstat (limited to 'sysdeps/sparc')
-rw-r--r--sysdeps/sparc/nptl/internaltypes.h35
-rw-r--r--sysdeps/sparc/nptl/pthread_barrier_destroy.c44
-rw-r--r--sysdeps/sparc/nptl/pthread_barrier_init.c54
-rw-r--r--sysdeps/sparc/nptl/pthread_barrier_wait.c77
-rw-r--r--sysdeps/sparc/nptl/sem_init.c92
-rw-r--r--sysdeps/sparc/nptl/sem_post.c69
-rw-r--r--sysdeps/sparc/nptl/sem_timedwait.c116
-rw-r--r--sysdeps/sparc/nptl/sem_wait.c122
-rw-r--r--sysdeps/sparc/sparc32/nptl/lowlevellock.c131
-rw-r--r--sysdeps/sparc/sparc32/nptl/pthread_barrier_wait.c93
-rw-r--r--sysdeps/sparc/sparc32/nptl/sem_post.c84
-rw-r--r--sysdeps/sparc/sparc32/nptl/sem_timedwait.c153
-rw-r--r--sysdeps/sparc/sparc32/nptl/sem_trywait.c58
-rw-r--r--sysdeps/sparc/sparc32/nptl/sem_wait.c176
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/Makefile4
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/nptl/cpu_relax.S1
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/nptl/pthread_barrier_wait.c1
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/nptl/sem_post.c1
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/nptl/sem_timedwait.c1
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/nptl/sem_trywait.c1
-rw-r--r--sysdeps/sparc/sparc32/sparcv9/nptl/sem_wait.c1
-rw-r--r--sysdeps/sparc/sparc64/nptl/cpu_relax.S67
22 files changed, 1381 insertions, 0 deletions
diff --git a/sysdeps/sparc/nptl/internaltypes.h b/sysdeps/sparc/nptl/internaltypes.h
new file mode 100644
index 0000000..e5c2740
--- /dev/null
+++ b/sysdeps/sparc/nptl/internaltypes.h
@@ -0,0 +1,35 @@
+#ifndef _INTERNALTYPES_H
+
+#include_next <internaltypes.h>
+
+union sparc_pthread_barrier
+{
+ struct pthread_barrier b;
+ struct sparc_pthread_barrier_s
+ {
+ unsigned int curr_event;
+ int lock;
+ unsigned int left;
+ unsigned int init_count;
+ unsigned char left_lock;
+ unsigned char pshared;
+ } 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/sysdeps/sparc/nptl/pthread_barrier_destroy.c b/sysdeps/sparc/nptl/pthread_barrier_destroy.c
new file mode 100644
index 0000000..2221a27
--- /dev/null
+++ b/sysdeps/sparc/nptl/pthread_barrier_destroy.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+int
+pthread_barrier_destroy (barrier)
+ pthread_barrier_t *barrier;
+{
+ union sparc_pthread_barrier *ibarrier;
+ int result = EBUSY;
+
+ ibarrier = (union sparc_pthread_barrier *) barrier;
+
+ int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE;
+
+ lll_lock (ibarrier->b.lock, private);
+
+ if (__glibc_likely (ibarrier->b.left == ibarrier->b.init_count))
+ /* The barrier is not used anymore. */
+ result = 0;
+ else
+ /* Still used, return with an error. */
+ lll_unlock (ibarrier->b.lock, private);
+
+ return result;
+}
diff --git a/sysdeps/sparc/nptl/pthread_barrier_init.c b/sysdeps/sparc/nptl/pthread_barrier_init.c
new file mode 100644
index 0000000..6af6863
--- /dev/null
+++ b/sysdeps/sparc/nptl/pthread_barrier_init.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+int
+pthread_barrier_init (barrier, attr, count)
+ pthread_barrier_t *barrier;
+ const pthread_barrierattr_t *attr;
+ unsigned int count;
+{
+ union sparc_pthread_barrier *ibarrier;
+
+ if (__glibc_unlikely (count == 0))
+ return EINVAL;
+
+ struct pthread_barrierattr *iattr = (struct pthread_barrierattr *) attr;
+ if (iattr != NULL)
+ {
+ if (iattr->pshared != PTHREAD_PROCESS_PRIVATE
+ && __builtin_expect (iattr->pshared != PTHREAD_PROCESS_SHARED, 0))
+ /* Invalid attribute. */
+ return EINVAL;
+ }
+
+ ibarrier = (union sparc_pthread_barrier *) barrier;
+
+ /* Initialize the individual fields. */
+ ibarrier->b.lock = LLL_LOCK_INITIALIZER;
+ ibarrier->b.left = count;
+ ibarrier->b.init_count = count;
+ ibarrier->b.curr_event = 0;
+ ibarrier->s.left_lock = 0;
+ ibarrier->s.pshared = (iattr && iattr->pshared == PTHREAD_PROCESS_SHARED);
+
+ return 0;
+}
diff --git a/sysdeps/sparc/nptl/pthread_barrier_wait.c b/sysdeps/sparc/nptl/pthread_barrier_wait.c
new file mode 100644
index 0000000..ed5c1f7
--- /dev/null
+++ b/sysdeps/sparc/nptl/pthread_barrier_wait.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Martin Schwidefsky <schwidefsky@de.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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthreadP.h>
+
+/* Wait on barrier. */
+int
+pthread_barrier_wait (barrier)
+ pthread_barrier_t *barrier;
+{
+ union sparc_pthread_barrier *ibarrier
+ = (union sparc_pthread_barrier *) barrier;
+ int result = 0;
+ int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE;
+
+ /* Make sure we are alone. */
+ lll_lock (ibarrier->b.lock, private);
+
+ /* One more arrival. */
+ --ibarrier->b.left;
+
+ /* Are these all? */
+ if (ibarrier->b.left == 0)
+ {
+ /* Yes. Increment the event counter to avoid invalid wake-ups and
+ tell the current waiters that it is their turn. */
+ ++ibarrier->b.curr_event;
+
+ /* Wake up everybody. */
+ lll_futex_wake (&ibarrier->b.curr_event, INT_MAX, private);
+
+ /* This is the thread which finished the serialization. */
+ result = PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ else
+ {
+ /* The number of the event we are waiting for. The barrier's event
+ number must be bumped before we continue. */
+ unsigned int event = ibarrier->b.curr_event;
+
+ /* Before suspending, make the barrier available to others. */
+ lll_unlock (ibarrier->b.lock, private);
+
+ /* Wait for the event counter of the barrier to change. */
+ do
+ lll_futex_wait (&ibarrier->b.curr_event, event, private);
+ while (event == ibarrier->b.curr_event);
+ }
+
+ /* Make sure the init_count is stored locally or in a register. */
+ unsigned int init_count = ibarrier->b.init_count;
+
+ /* If this was the last woken thread, unlock. */
+ if (atomic_increment_val (&ibarrier->b.left) == init_count)
+ /* We are done. */
+ lll_unlock (ibarrier->b.lock, private);
+
+ return result;
+}
diff --git a/sysdeps/sparc/nptl/sem_init.c b/sysdeps/sparc/nptl/sem_init.c
new file mode 100644
index 0000000..cbefdc4
--- /dev/null
+++ b/sysdeps/sparc/nptl/sem_init.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 2002-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <string.h>
+#include <semaphore.h>
+#include <lowlevellock.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+#include <kernel-features.h>
+
+
+int
+__new_sem_init (sem, pshared, value)
+ sem_t *sem;
+ int pshared;
+ unsigned int value;
+{
+ /* Parameter sanity check. */
+ if (__glibc_unlikely (value > SEM_VALUE_MAX))
+ {
+ __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
+attribute_compat_text_section
+__old_sem_init (sem, pshared, value)
+ sem_t *sem;
+ int pshared;
+ unsigned int value;
+{
+ /* Parameter sanity check. */
+ if (__glibc_unlikely (value > SEM_VALUE_MAX))
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* Map to the internal type. */
+ struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
+
+ /* Use the value 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;
+}
+compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0);
+#endif
diff --git a/sysdeps/sparc/nptl/sem_post.c b/sysdeps/sparc/nptl/sem_post.c
new file mode 100644
index 0000000..d83b9d8
--- /dev/null
+++ b/sysdeps/sparc/nptl/sem_post.c
@@ -0,0 +1,69 @@
+/* sem_post -- post to a POSIX semaphore. SPARC version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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;
+
+ atomic_increment (&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 err;
+
+ atomic_increment (&isem->value);
+ 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/sysdeps/sparc/nptl/sem_timedwait.c b/sysdeps/sparc/nptl/sem_timedwait.c
new file mode 100644
index 0000000..0557e4e
--- /dev/null
+++ b/sysdeps/sparc/nptl/sem_timedwait.c
@@ -0,0 +1,116 @@
+/* sem_timedwait -- wait on a semaphore. Generic futex-using version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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;
+
+/* This is in a seperate function in order to make sure gcc
+ puts the call site into an exception region, and thus the
+ cleanups get properly run. */
+static int
+__attribute__ ((noinline))
+do_futex_timed_wait (struct sparc_new_sem *isem, struct timespec *rt)
+{
+ int err, oldtype = __pthread_enable_asynccancel ();
+
+ err = lll_futex_timed_wait (&isem->value, 0, rt,
+ isem->private ^ FUTEX_PRIVATE_FLAG);
+
+ __pthread_disable_asynccancel (oldtype);
+ return err;
+}
+
+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? */
+ if (sec < 0)
+ {
+ __set_errno (ETIMEDOUT);
+ err = -1;
+ break;
+ }
+
+ /* Do wait. */
+ rt.tv_sec = sec;
+ rt.tv_nsec = nsec;
+ err = do_futex_timed_wait(isem, &rt);
+ 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/sysdeps/sparc/nptl/sem_wait.c b/sysdeps/sparc/nptl/sem_wait.c
new file mode 100644
index 0000000..cfa1ef3
--- /dev/null
+++ b/sysdeps/sparc/nptl/sem_wait.c
@@ -0,0 +1,122 @@
+/* sem_wait -- wait on a semaphore. Generic futex-using version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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);
+}
+
+/* This is in a seperate function in order to make sure gcc
+ puts the call site into an exception region, and thus the
+ cleanups get properly run. */
+static int
+__attribute__ ((noinline))
+do_futex_wait (struct sparc_new_sem *isem)
+{
+ int err, oldtype = __pthread_enable_asynccancel ();
+
+ err = lll_futex_wait (&isem->value, 0, isem->private ^ FUTEX_PRIVATE_FLAG);
+
+ __pthread_disable_asynccancel (oldtype);
+ return err;
+}
+
+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)
+ {
+ err = do_futex_wait(isem);
+ 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/sysdeps/sparc/sparc32/nptl/lowlevellock.c b/sysdeps/sparc/sparc32/nptl/lowlevellock.c
new file mode 100644
index 0000000..8384281
--- /dev/null
+++ b/sysdeps/sparc/sparc32/nptl/lowlevellock.c
@@ -0,0 +1,131 @@
+/* low level locking for pthread library. SPARC version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+
+
+void
+__lll_lock_wait_private (int *futex)
+{
+ do
+ {
+ int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+ if (oldval != 0)
+ lll_futex_wait (futex, 2, LLL_PRIVATE);
+ }
+ while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+}
+
+
+/* These functions don't get included in libc.so */
+#ifdef IS_IN_libpthread
+void
+__lll_lock_wait (int *futex, int private)
+{
+ do
+ {
+ int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+ if (oldval != 0)
+ lll_futex_wait (futex, 2, private);
+ }
+ while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+}
+
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
+{
+ /* Reject invalid timeouts. */
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+ return EINVAL;
+
+ do
+ {
+ struct timeval tv;
+ struct timespec rt;
+
+ /* Get the current time. */
+ (void) __gettimeofday (&tv, NULL);
+
+ /* Compute relative timeout. */
+ rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+ if (rt.tv_nsec < 0)
+ {
+ rt.tv_nsec += 1000000000;
+ --rt.tv_sec;
+ }
+
+ /* Already timed out? */
+ if (rt.tv_sec < 0)
+ return ETIMEDOUT;
+
+ /* Wait. */
+ int oldval = atomic_compare_and_exchange_val_24_acq (futex, 2, 1);
+ if (oldval != 0)
+ lll_futex_timed_wait (futex, 2, &rt, private);
+ }
+ while (atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0);
+
+ return 0;
+}
+
+
+int
+__lll_timedwait_tid (int *tidp, const struct timespec *abstime)
+{
+ int tid;
+
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+ return EINVAL;
+
+ /* Repeat until thread terminated. */
+ while ((tid = *tidp) != 0)
+ {
+ struct timeval tv;
+ struct timespec rt;
+
+ /* Get the current time. */
+ (void) __gettimeofday (&tv, NULL);
+
+ /* Compute relative timeout. */
+ rt.tv_sec = abstime->tv_sec - tv.tv_sec;
+ rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
+ if (rt.tv_nsec < 0)
+ {
+ rt.tv_nsec += 1000000000;
+ --rt.tv_sec;
+ }
+
+ /* Already timed out? */
+ if (rt.tv_sec < 0)
+ return ETIMEDOUT;
+
+ /* Wait until thread terminates. The kernel so far does not use
+ the private futex operations for this. */
+ if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT)
+ return ETIMEDOUT;
+ }
+
+ return 0;
+}
+#endif
diff --git a/sysdeps/sparc/sparc32/nptl/pthread_barrier_wait.c b/sysdeps/sparc/sparc32/nptl/pthread_barrier_wait.c
new file mode 100644
index 0000000..0fed908
--- /dev/null
+++ b/sysdeps/sparc/sparc32/nptl/pthread_barrier_wait.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Martin Schwidefsky <schwidefsky@de.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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <pthreadP.h>
+
+/* Wait on barrier. */
+int
+pthread_barrier_wait (barrier)
+ pthread_barrier_t *barrier;
+{
+ union sparc_pthread_barrier *ibarrier
+ = (union sparc_pthread_barrier *) barrier;
+ int result = 0;
+ int private = ibarrier->s.pshared ? LLL_SHARED : LLL_PRIVATE;
+
+ /* Make sure we are alone. */
+ lll_lock (ibarrier->b.lock, private);
+
+ /* One more arrival. */
+ --ibarrier->b.left;
+
+ /* Are these all? */
+ if (ibarrier->b.left == 0)
+ {
+ /* Yes. Increment the event counter to avoid invalid wake-ups and
+ tell the current waiters that it is their turn. */
+ ++ibarrier->b.curr_event;
+
+ /* Wake up everybody. */
+ lll_futex_wake (&ibarrier->b.curr_event, INT_MAX, private);
+
+ /* This is the thread which finished the serialization. */
+ result = PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ else
+ {
+ /* The number of the event we are waiting for. The barrier's event
+ number must be bumped before we continue. */
+ unsigned int event = ibarrier->b.curr_event;
+
+ /* Before suspending, make the barrier available to others. */
+ lll_unlock (ibarrier->b.lock, private);
+
+ /* Wait for the event counter of the barrier to change. */
+ do
+ lll_futex_wait (&ibarrier->b.curr_event, event, private);
+ while (event == ibarrier->b.curr_event);
+ }
+
+ /* Make sure the init_count is stored locally or in a register. */
+ unsigned int init_count = ibarrier->b.init_count;
+
+ /* If this was the last woken thread, unlock. */
+ if (__atomic_is_v9 || ibarrier->s.pshared == 0)
+ {
+ if (atomic_increment_val (&ibarrier->b.left) == init_count)
+ /* We are done. */
+ lll_unlock (ibarrier->b.lock, private);
+ }
+ else
+ {
+ unsigned int left;
+ /* Slightly more complicated. On pre-v9 CPUs, atomic_increment_val
+ is only atomic for threads within the same process, not for
+ multiple processes. */
+ __sparc32_atomic_do_lock24 (&ibarrier->s.left_lock);
+ left = ++ibarrier->b.left;
+ __sparc32_atomic_do_unlock24 (&ibarrier->s.left_lock);
+ if (left == init_count)
+ /* We are done. */
+ lll_unlock (ibarrier->b.lock, private);
+ }
+
+ return result;
+}
diff --git a/sysdeps/sparc/sparc32/nptl/sem_post.c b/sysdeps/sparc/sparc32/nptl/sem_post.c
new file mode 100644
index 0000000..d3846c0
--- /dev/null
+++ b/sysdeps/sparc/sparc32/nptl/sem_post.c
@@ -0,0 +1,84 @@
+/* sem_post -- post to a POSIX semaphore. SPARC version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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;
+
+ 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);
+ }
+ 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);
+ return -1;
+ }
+ return 0;
+}
+compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
+#endif
diff --git a/sysdeps/sparc/sparc32/nptl/sem_timedwait.c b/sysdeps/sparc/sparc32/nptl/sem_timedwait.c
new file mode 100644
index 0000000..5c48cb3
--- /dev/null
+++ b/sysdeps/sparc/sparc32/nptl/sem_timedwait.c
@@ -0,0 +1,153 @@
+/* sem_timedwait -- wait on a semaphore. SPARC version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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;
+
+/* This is in a seperate function in order to make sure gcc
+ puts the call site into an exception region, and thus the
+ cleanups get properly run. */
+static int
+__attribute__ ((noinline))
+do_futex_timed_wait (struct sparc_new_sem *isem, struct timespec *rt)
+{
+ int err, oldtype = __pthread_enable_asynccancel ();
+
+ err = lll_futex_timed_wait (&isem->value, 0, rt,
+ isem->private ^ FUTEX_PRIVATE_FLAG);
+
+ __pthread_disable_asynccancel (oldtype);
+ return err;
+}
+
+int
+sem_timedwait (sem_t *sem, const struct timespec *abstime)
+{
+ 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;
+ __sparc32_atomic_do_unlock24 (&isem->lock);
+ }
+
+ if (val > 0)
+ return 0;
+
+ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+ {
+ __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);
+ }
+
+ 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? */
+ if (sec < 0)
+ {
+ __set_errno (ETIMEDOUT);
+ err = -1;
+ break;
+ }
+
+ /* Do wait. */
+ rt.tv_sec = sec;
+ rt.tv_nsec = nsec;
+ err = do_futex_timed_wait(isem, &rt);
+ 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);
+
+ 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;
+}
diff --git a/sysdeps/sparc/sparc32/nptl/sem_trywait.c b/sysdeps/sparc/sparc32/nptl/sem_trywait.c
new file mode 100644
index 0000000..7d0fc55
--- /dev/null
+++ b/sysdeps/sparc/sparc32/nptl/sem_trywait.c
@@ -0,0 +1,58 @@
+/* sem_trywait -- wait on a semaphore. SPARC version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <internaltypes.h>
+#include <semaphore.h>
+
+#include <shlib-compat.h>
+
+
+int
+__new_sem_trywait (sem_t *sem)
+{
+ struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
+ int val;
+
+ if (isem->value > 0)
+ {
+ 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)
+ return 0;
+ }
+
+ __set_errno (EAGAIN);
+ return -1;
+}
+versioned_symbol (libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1);
+#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
+strong_alias (__new_sem_trywait, __old_sem_trywait)
+compat_symbol (libpthread, __old_sem_trywait, sem_trywait, GLIBC_2_0);
+#endif
diff --git a/sysdeps/sparc/sparc32/nptl/sem_wait.c b/sysdeps/sparc/sparc32/nptl/sem_wait.c
new file mode 100644
index 0000000..8c072fe
--- /dev/null
+++ b/sysdeps/sparc/sparc32/nptl/sem_wait.c
@@ -0,0 +1,176 @@
+/* sem_wait -- wait on a semaphore. Generic futex-using version.
+ Copyright (C) 2003-2014 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#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;
+
+ if (__atomic_is_v9)
+ atomic_decrement (&isem->nwaiters);
+ else
+ {
+ __sparc32_atomic_do_lock24 (&isem->lock);
+ isem->nwaiters--;
+ __sparc32_atomic_do_unlock24 (&isem->lock);
+ }
+}
+
+/* This is in a seperate function in order to make sure gcc
+ puts the call site into an exception region, and thus the
+ cleanups get properly run. */
+static int
+__attribute__ ((noinline))
+do_futex_wait (struct sparc_new_sem *isem)
+{
+ int err, oldtype = __pthread_enable_asynccancel ();
+
+ err = lll_futex_wait (&isem->value, 0, isem->private ^ FUTEX_PRIVATE_FLAG);
+
+ __pthread_disable_asynccancel (oldtype);
+ return err;
+}
+
+int
+__new_sem_wait (sem_t *sem)
+{
+ 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)
+ {
+ err = do_futex_wait(isem);
+ 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);
+
+ 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
+ {
+ 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)
+ 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/sysdeps/sparc/sparc32/sparcv9/Makefile b/sysdeps/sparc/sparc32/sparcv9/Makefile
index 7d475b0..36f889e 100644
--- a/sysdeps/sparc/sparc32/sparcv9/Makefile
+++ b/sysdeps/sparc/sparc32/sparcv9/Makefile
@@ -18,3 +18,7 @@ ASFLAGS-.op += -Wa,-Av9a
ASFLAGS-.og += -Wa,-Av9a
ASFLAGS-.oS += -Wa,-Av9a
endif
+
+ifeq ($(subdir), nptl)
+libpthread-routines += cpu_relax
+endif
diff --git a/sysdeps/sparc/sparc32/sparcv9/nptl/cpu_relax.S b/sysdeps/sparc/sparc32/sparcv9/nptl/cpu_relax.S
new file mode 100644
index 0000000..fa88647
--- /dev/null
+++ b/sysdeps/sparc/sparc32/sparcv9/nptl/cpu_relax.S
@@ -0,0 +1 @@
+#include <sysdeps/sparc/sparc64/nptl/cpu_relax.S>
diff --git a/sysdeps/sparc/sparc32/sparcv9/nptl/pthread_barrier_wait.c b/sysdeps/sparc/sparc32/sparcv9/nptl/pthread_barrier_wait.c
new file mode 100644
index 0000000..8336f5e
--- /dev/null
+++ b/sysdeps/sparc/sparc32/sparcv9/nptl/pthread_barrier_wait.c
@@ -0,0 +1 @@
+#include <sysdeps/sparc/nptl/pthread_barrier_wait.c>
diff --git a/sysdeps/sparc/sparc32/sparcv9/nptl/sem_post.c b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_post.c
new file mode 100644
index 0000000..3c4b940
--- /dev/null
+++ b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_post.c
@@ -0,0 +1 @@
+#include <sysdeps/sparc/nptl/sem_post.c>
diff --git a/sysdeps/sparc/sparc32/sparcv9/nptl/sem_timedwait.c b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_timedwait.c
new file mode 100644
index 0000000..f19b2c5
--- /dev/null
+++ b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_timedwait.c
@@ -0,0 +1 @@
+#include <sysdeps/sparc/nptl/sem_timedwait.c>
diff --git a/sysdeps/sparc/sparc32/sparcv9/nptl/sem_trywait.c b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_trywait.c
new file mode 100644
index 0000000..80157c5
--- /dev/null
+++ b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_trywait.c
@@ -0,0 +1 @@
+#include <sysdeps/unix/sysv/linux/sem_trywait.c>
diff --git a/sysdeps/sparc/sparc32/sparcv9/nptl/sem_wait.c b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_wait.c
new file mode 100644
index 0000000..b6d8287
--- /dev/null
+++ b/sysdeps/sparc/sparc32/sparcv9/nptl/sem_wait.c
@@ -0,0 +1 @@
+#include <sysdeps/sparc/nptl/sem_wait.c>
diff --git a/sysdeps/sparc/sparc64/nptl/cpu_relax.S b/sysdeps/sparc/sparc64/nptl/cpu_relax.S
new file mode 100644
index 0000000..9d45eb7
--- /dev/null
+++ b/sysdeps/sparc/sparc64/nptl/cpu_relax.S
@@ -0,0 +1,67 @@
+/* CPU strand yielding for busy loops.
+ Copyright (C) 2012-2014 Free Software Foundation, Inc.
+ Contributed by David S. Miller (davem@davemloft.net)
+ This file is part of the GNU C Library.
+
+ 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+ .text
+__cpu_relax_generic:
+ rd %ccr, %g0
+ rd %ccr, %g0
+ rd %ccr, %g0
+ retl
+ nop
+ .size __cpu_relax_generic,.-__cpu_relax_generic
+
+__cpu_relax_pause:
+ wr %g0, 128, %asr27
+ retl
+ nop
+ .size __cpu_relax_pause,.-__cpu_relax_pause
+
+ENTRY(__cpu_relax)
+ .type __cpu_relax, @gnu_indirect_function
+# ifdef SHARED
+ SETUP_PIC_REG_LEAF(o3, o5)
+# endif
+ set HWCAP_SPARC_PAUSE, %o1
+ andcc %o0, %o1, %g0
+ be 1f
+ nop
+# ifdef SHARED
+ sethi %gdop_hix22(__cpu_relax_pause), %o1
+ xor %o1, %gdop_lox10(__cpu_relax_pause), %o1
+# else
+ set __cpu_relax_pause, %o1
+# endif
+ ba 10f
+ nop
+1:
+# ifdef SHARED
+ sethi %gdop_hix22(__cpu_relax_generic), %o1
+ xor %o1, %gdop_lox10(__cpu_relax_generic), %o1
+# else
+ set __cpu_relax_generic, %o1
+# endif
+10:
+# ifdef SHARED
+ add %o3, %o1, %o1
+# endif
+ retl
+ mov %o1, %o0
+END(__cpu_relax)