summaryrefslogtreecommitdiff
path: root/sysdeps/sparc/sparc32/sem_post.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/sparc/sparc32/sem_post.c')
-rw-r--r--sysdeps/sparc/sparc32/sem_post.c87
1 files changed, 54 insertions, 33 deletions
diff --git a/sysdeps/sparc/sparc32/sem_post.c b/sysdeps/sparc/sparc32/sem_post.c
index 7ca189810e..64cd851ffa 100644
--- a/sysdeps/sparc/sparc32/sem_post.c
+++ b/sysdeps/sparc/sparc32/sem_post.c
@@ -1,4 +1,4 @@
-/* sem_post -- post to a POSIX semaphore. SPARC version.
+/* sem_post -- post to a POSIX semaphore. Generic futex-using version.
Copyright (C) 2003-2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
@@ -17,6 +17,7 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <atomic.h>
#include <errno.h>
#include <sysdep.h>
#include <lowlevellock.h>
@@ -24,33 +25,58 @@
#include <semaphore.h>
#include <shlib-compat.h>
-#include <sparc-nptl.h>
+/* Wrapper for lll_futex_wake, with error checking.
+ TODO Remove when cleaning up the futex API throughout glibc. */
+static __always_inline void
+futex_wake (unsigned int* futex, int processes_to_wake, int private)
+{
+ int res = lll_futex_wake (futex, processes_to_wake, private);
+ /* No error. Ignore the number of woken processes. */
+ if (res >= 0)
+ return;
+ switch (res)
+ {
+ case -EFAULT: /* Could have happened due to memory reuse. */
+ case -EINVAL: /* Could be either due to incorrect alignment (a bug in
+ glibc or in the application) or due to memory being
+ reused for a PI futex. We cannot distinguish between the
+ two causes, and one of them is correct use, so we do not
+ act in this case. */
+ return;
+ case -ENOSYS: /* Must have been caused by a glibc bug. */
+ /* No other errors are documented at this time. */
+ default:
+ abort ();
+ }
+}
+
+
+/* See sem_wait for an explanation of the algorithm. */
int
__new_sem_post (sem_t *sem)
{
- struct sparc_new_sem *isem = (struct sparc_new_sem *) sem;
- int nr;
+ struct new_sem *isem = (struct new_sem *) sem;
+ int private = isem->private;
+ unsigned int v;
- 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)
+ __sparc32_atomic_do_lock24(&isem->pad);
+
+ v = isem->value;
+ if ((v << SEM_VALUE_SHIFT) == SEM_VALUE_MAX)
{
- int err = lll_futex_wake (&isem->value, 1,
- isem->private ^ FUTEX_PRIVATE_FLAG);
- if (__builtin_expect (err, 0) < 0)
- {
- __set_errno (-err);
- return -1;
- }
+ __sparc32_atomic_do_unlock24(&isem->pad);
+
+ __set_errno (EOVERFLOW);
+ return -1;
}
+ isem->value = v + (1 << SEM_VALUE_SHIFT);
+
+ __sparc32_atomic_do_unlock24(&isem->pad);
+
+ if ((v & SEM_NWAITERS_MASK) != 0)
+ futex_wake (&isem->value, 1, private);
+
return 0;
}
versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
@@ -61,19 +87,14 @@ int
attribute_compat_text_section
__old_sem_post (sem_t *sem)
{
- struct sparc_old_sem *isem = (struct sparc_old_sem *) sem;
- int nr;
+ int *futex = (int *) sem;
- 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);
+ /* We must need to synchronize with consumers of this token, so the atomic
+ increment must have release MO semantics. */
+ atomic_write_barrier ();
+ (void) atomic_increment_val (futex);
+ /* We always have to assume it is a shared semaphore. */
+ int err = lll_futex_wake (futex, 1, LLL_SHARED);
if (__builtin_expect (err, 0) < 0)
{
__set_errno (-err);