diff options
Diffstat (limited to 'sysdeps/sparc/nptl')
-rw-r--r-- | sysdeps/sparc/nptl/internaltypes.h | 35 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/pthread_barrier_destroy.c | 44 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/pthread_barrier_init.c | 54 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/pthread_barrier_wait.c | 77 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/sem_init.c | 92 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/sem_post.c | 69 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/sem_timedwait.c | 116 | ||||
-rw-r--r-- | sysdeps/sparc/nptl/sem_wait.c | 122 |
8 files changed, 609 insertions, 0 deletions
diff --git a/sysdeps/sparc/nptl/internaltypes.h b/sysdeps/sparc/nptl/internaltypes.h new file mode 100644 index 0000000000..e5c27408d8 --- /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 0000000000..2221a27e22 --- /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 0000000000..6af686361d --- /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 0000000000..ed5c1f7071 --- /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 0000000000..cbefdc4823 --- /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 0000000000..d83b9d8e2e --- /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 0000000000..0557e4e709 --- /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 0000000000..cfa1ef3727 --- /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 |