diff options
Diffstat (limited to 'sysdeps/sparc/sparc32/sem_post.c')
-rw-r--r-- | sysdeps/sparc/sparc32/sem_post.c | 87 |
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); |