summaryrefslogtreecommitdiff
path: root/libpthread/nptl/sysdeps/unix/sysv/linux/or1k
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2017-04-14 07:07:57 +0200
committerWaldemar Brodkorb <wbx@openadk.org>2017-05-14 10:29:09 +0200
commitbaad294eaf59e0e1b311a11448a04e3d3c5f3c56 (patch)
tree858d8924af34509f8742d025c6d8740f20464a97 /libpthread/nptl/sysdeps/unix/sysv/linux/or1k
parent69ea4c1f65bff99575cd7f0210312dc355929240 (diff)
or1k: add NPTL/TLS support
Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/or1k')
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile9
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile.arch9
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/atomic.h128
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/pthreadtypes.h177
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/semaphore.h34
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/createthread.c23
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/fork.c27
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/lowlevellock.h323
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/pthread_once.c92
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/or1k/sysdep-cancel.h116
10 files changed, 938 insertions, 0 deletions
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile
new file mode 100644
index 000000000..2caba11b7
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile
@@ -0,0 +1,9 @@
+# Makefile for uClibc-ng NPTL
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+top_srcdir=../../../../../../../
+top_builddir=../../../../../../../
+all: objs
+include $(top_builddir)Rules.mak
+include Makefile.arch
+include $(top_srcdir)Makerules
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile.arch
new file mode 100644
index 000000000..94aa25ffb
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/Makefile.arch
@@ -0,0 +1,9 @@
+# Makefile for uClibc-ng NPTL
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+libpthread_linux_arch_SSRC =
+libpthread_linux_arch_CSRC = pthread_once.c
+
+libc_linux_arch_CSRC = fork.c
+
+CFLAGS += $(SSP_ALL_CFLAGS)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/atomic.h
new file mode 100644
index 000000000..43440dc3c
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/atomic.h
@@ -0,0 +1,128 @@
+/* Copyright (C) 2010-2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+ 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/>. */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+#include <stdint.h>
+
+/* This is needed to break a depencency loop, we do not need errno anyway */
+#ifndef _ERRNO_H
+# define _ERRNO_H
+# include <sysdep.h>
+# undef _ERRNO_H
+#else
+# include <sysdep.h>
+#endif
+
+/* Or1k has no atomic compare-and-exchange operation, but the
+ kernel provides userspace atomicity operations. Use them. */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* TODO: Move these to a kernel header */
+#define OR1K_ATOMIC_SWAP 1
+#define OR1K_ATOMIC_CMPXCHG 2
+#define OR1K_ATOMIC_XCHG 3
+#define OR1K_ATOMIC_ADD 4
+#define OR1K_ATOMIC_DECPOS 5
+#define OR1K_ATOMIC_AND 6
+#define OR1K_ATOMIC_OR 7
+#define OR1K_ATOMIC_UMAX 8
+#define OR1K_ATOMIC_UMIN 9
+
+#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 4, \
+ OR1K_ATOMIC_CMPXCHG, mem, oldval, newval) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_exchange_acq(mem, newval) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 3, \
+ OR1K_ATOMIC_XCHG, mem, newval) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_exchange_and_add_acq(mem, val) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 3, \
+ OR1K_ATOMIC_ADD, mem, val) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_decrement_if_positive(mem) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 2, \
+ OR1K_ATOMIC_DECPOS, mem) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_and_val(mem, mask) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 3, \
+ OR1K_ATOMIC_AND, mem, mask) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_or_val(mem, mask) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 3, \
+ OR1K_ATOMIC_OR, mem, mask) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_max_val(mem, val) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 3, \
+ OR1K_ATOMIC_UMAX, mem, val) \
+ : __atomic_error_bad_argument_size ()))
+
+#define atomic_min_val(mem, val) \
+ ((__typeof (*(mem))) ((sizeof (*(mem)) == 4) ? \
+ INTERNAL_SYSCALL (or1k_atomic, , 3, \
+ OR1K_ATOMIC_UMIN, mem, val) \
+ : __atomic_error_bad_argument_size ()))
+
+
+/* atomic_bit_test_set in terms of atomic_or_val. */
+#define atomic_bit_test_set(mem, bit) \
+ ({ __typeof (*(mem)) __att0_mask = ((__typeof (*(mem))) 1 << (bit)); \
+ atomic_or_val ((mem), __att0_mask) & __att0_mask; })
+
+/* Various macros that should just be synonyms. */
+#define catomic_exchange_and_add atomic_exchange_and_add
+#define atomic_and(mem, mask) ((void) atomic_and_val ((mem), (mask)))
+#define catomic_and atomic_and
+#define atomic_or(mem, mask) ((void) atomic_or_val ((mem), (mask)))
+#define catomic_or atomic_or
+#define atomic_max(mem, val) ((void)atomic_max_val ((mem), (val)))
+#define catomic_max atomic_max
+#define atomic_min(mem, val) ((void)atomic_min_val ((mem), (val)))
+#define catomic_min atomic_min
+/*
+ * This non-existent symbol is called for unsupporrted sizes,
+ * indicating a bug in the caller.
+ */
+extern int __atomic_error_bad_argument_size(void)
+ __attribute__ ((error ("bad sizeof atomic argument")));
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/pthreadtypes.h
new file mode 100644
index 000000000..695a61fdd
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/pthreadtypes.h
@@ -0,0 +1,177 @@
+/* Copyright (C) 2002,2003,2004,2005,2006,2007 Free Software Foundation, Inc.
+
+ 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. */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers. The structure of the attribute type is not
+ exposed on purpose. */
+typedef unsigned long int pthread_t;
+
+union pthread_attr_t
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+};
+#ifndef __have_pthread_attr_t
+typedef union pthread_attr_t pthread_attr_t;
+# define __have_pthread_attr_t 1
+#endif
+
+
+typedef struct __pthread_internal_slist
+{
+ struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is not exposed on purpose. */
+typedef union
+{
+ struct __pthread_mutex_s
+ {
+ int __lock;
+ unsigned int __count;
+ int __owner;
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility. */
+ int __kind;
+ unsigned int __nusers;
+ __extension__ union
+ {
+ int __spins;
+ __pthread_slist_t __list;
+ };
+ } __data;
+ char __size[__SIZEOF_PTHREAD_MUTEX_T];
+ long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ long int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling. The structure of
+ the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __futex;
+ __extension__ unsigned long long int __total_seq;
+ __extension__ unsigned long long int __wakeup_seq;
+ __extension__ unsigned long long int __woken_seq;
+ void *__mutex;
+ unsigned int __nwaiters;
+ unsigned int __broadcast_seq;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_COND_T];
+ __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+ long int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling. The
+ structure of the attribute type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __nr_readers;
+ unsigned int __readers_wakeup;
+ unsigned int __writer_wakeup;
+ unsigned int __nr_readers_queued;
+ unsigned int __nr_writers_queued;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned char __flags;
+ unsigned char __shared;
+ unsigned char __pad1;
+ unsigned char __pad2;
+ int __writer;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+ long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+ long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type. */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type. The structure of the type is
+ deliberately not exposed. */
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIER_T];
+ long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+ int __align;
+} pthread_barrierattr_t;
+#endif
+/* Extra attributes for the cleanup functions. */
+/*
+ FIXME, check this after gcc uprgrade.
+ #define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
+ warning: '__regparm__' attribute directive ignored
+*/
+
+#endif /* bits/pthreadtypes.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/semaphore.h
new file mode 100644
index 000000000..3ed1424d7
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/bits/semaphore.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002, 2005, 2007 Free Software Foundation, Inc.
+ 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/>. */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed. */
+#define SEM_FAILED ((sem_t *) 0)
+
+
+typedef union
+{
+ char __size[__SIZEOF_SEM_T];
+ long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/createthread.c
new file mode 100644
index 000000000..90838ddc5
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/createthread.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ 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; see the file COPYING.LIB. If
+ not, see <http://www.gnu.org/licenses/>.  */
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE (pd + 1)
+
+
+/* Get the real implementation. */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/fork.c
new file mode 100644
index 000000000..beb6cb0f7
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/fork.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Phil Blundell <pb@nexus.co.uk>, 2005
+
+ 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 <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+ INLINE_SYSCALL (clone, 5, \
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0, \
+ NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/lowlevellock.h
new file mode 100644
index 000000000..32b004486
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/lowlevellock.h
@@ -0,0 +1,323 @@
+/* Copyright (C) 2005-2013 Free Software Foundation, Inc.
+
+ 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/>. */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H 1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.h>
+
+
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+#define FUTEX_REQUEUE 3
+#define FUTEX_CMP_REQUEUE 4
+#define FUTEX_WAKE_OP 5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1)
+#define FUTEX_LOCK_PI 6
+#define FUTEX_UNLOCK_PI 7
+#define FUTEX_TRYLOCK_PI 8
+#define FUTEX_WAIT_BITSET 9
+#define FUTEX_WAKE_BITSET 10
+#define FUTEX_WAIT_REQUEUE_PI 11
+#define FUTEX_CMP_REQUEUE_PI 12
+#define FUTEX_PRIVATE_FLAG 128
+#define FUTEX_CLOCK_REALTIME 256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros. Yes, the
+ definition seems to be backwards. But it is not. The bit will be
+ reversed before passing to the system call. */
+#define LLL_PRIVATE 0
+#define LLL_SHARED FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private. */
+# ifdef __ASSUME_PRIVATE_FUTEX
+# define __lll_private_flag(fl, private) \
+ ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+# define __lll_private_flag(fl, private) \
+ ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+# define __lll_private_flag(fl, private) \
+ (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+# define __lll_private_flag(fl, private) \
+ (__builtin_constant_p (private) \
+ ? ((private) == 0 \
+ ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \
+ : (fl)) \
+ : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \
+ & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+ lll_futex_timed_wait(futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAIT, private), \
+ (val), (timespec)); \
+ __ret; \
+ })
+
+#define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ int __op = FUTEX_WAIT_BITSET | clockbit; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (__op, private), \
+ (val), (timespec), NULL /* Unused. */, \
+ FUTEX_BITSET_MATCH_ANY); \
+ __ret; \
+ })
+
+#define lll_futex_wake(futexp, nr, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAKE, private), \
+ (nr), 0); \
+ __ret; \
+ })
+
+#define lll_robust_dead(futexv, private) \
+ do \
+ { \
+ int *__futexp = &(futexv); \
+ atomic_or (__futexp, FUTEX_OWNER_DIED); \
+ lll_futex_wake (__futexp, 1, private); \
+ } \
+ while (0)
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+ (nr_wake), (nr_move), (mutex), (val)); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+
+/* Returns non-zero if error happened, zero if success. */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_WAKE_OP, private), \
+ (nr_wake), (nr_wake2), (futexp2), \
+ FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+/* Priority Inheritance support. */
+#define lll_futex_wait_requeue_pi(futexp, val, mutex, private) \
+ lll_futex_timed_wait_requeue_pi (futexp, val, NULL, 0, mutex, private)
+
+#define lll_futex_timed_wait_requeue_pi(futexp, val, timespec, clockbit, \
+ mutex, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ int __op = FUTEX_WAIT_REQUEUE_PI | clockbit; \
+ \
+ INTERNAL_SYSCALL (futex, __err, 5, (futexp), \
+ __lll_private_flag (__op, private), \
+ (val), (timespec), mutex); \
+ })
+
+#define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, val, priv) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ long int __ret; \
+ \
+ __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
+ __lll_private_flag (FUTEX_CMP_REQUEUE_PI, priv),\
+ (nr_wake), (nr_move), (mutex), (val)); \
+ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \
+ })
+
+
+#define lll_trylock(lock) \
+ atomic_compare_and_exchange_val_acq(&(lock), 1, 0)
+
+#define lll_cond_trylock(lock) \
+ atomic_compare_and_exchange_val_acq(&(lock), 2, 0)
+
+#define __lll_robust_trylock(futex, id) \
+ (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0)
+#define lll_robust_trylock(lock, id) \
+ __lll_robust_trylock (&(lock), id)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define __lll_lock(futex, private) \
+ ((void) ({ \
+ int *__futex = (futex); \
+ if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex, \
+ 1, 0), 0)) \
+ { \
+ if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
+ __lll_lock_wait_private (__futex); \
+ else \
+ __lll_lock_wait (__futex, private); \
+ } \
+ }))
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+#define __lll_robust_lock(futex, id, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
+ 0), 0)) \
+ __val = __lll_robust_lock_wait (__futex, private); \
+ __val; \
+ })
+#define lll_robust_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), id, private)
+
+
+#define __lll_cond_lock(futex, private) \
+ ((void) ({ \
+ int *__futex = (futex); \
+ if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0)) \
+ __lll_lock_wait (__futex, private); \
+ }))
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+ int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+ int private) attribute_hidden;
+
+#define __lll_timedlock(futex, abstime, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0)) \
+ __val = __lll_timedlock_wait (__futex, abstime, private); \
+ __val; \
+ })
+#define lll_timedlock(futex, abstime, private) \
+ __lll_timedlock (&(futex), abstime, private)
+
+
+#define __lll_robust_timedlock(futex, abstime, id, private) \
+ ({ \
+ int *__futex = (futex); \
+ int __val = 0; \
+ \
+ if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id, \
+ 0), 0)) \
+ __val = __lll_robust_timedlock_wait (__futex, abstime, private); \
+ __val; \
+ })
+#define lll_robust_timedlock(futex, abstime, id, private) \
+ __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private) \
+ (void) \
+ ({ int *__futex = (futex); \
+ int __oldval = atomic_exchange_rel (__futex, 0); \
+ if (__builtin_expect (__oldval > 1, 0)) \
+ lll_futex_wake (__futex, 1, private); \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private) \
+ (void) \
+ ({ int *__futex = (futex); \
+ int __oldval = atomic_exchange_rel (__futex, 0); \
+ if (__builtin_expect (__oldval & FUTEX_WAITERS, 0)) \
+ lll_futex_wake (__futex, 1, private); \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_robust_unlock(futex, private) \
+ __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+ (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+ mutex implementation. */
+
+/* Initializers for lock. */
+#define LLL_LOCK_INITIALIZER (0)
+#define LLL_LOCK_INITIALIZER_LOCKED (1)
+
+/* The states of a lock are:
+ 0 - untaken
+ 1 - taken by one user
+ >1 - taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CHILD_CLEARTID via futex
+ wakeup when the clone terminates. The memory location contains the
+ thread ID while the clone is running and is reset to zero
+ afterwards. */
+#define lll_wait_tid(tid) \
+ do { \
+ __typeof (tid) __tid; \
+ while ((__tid = (tid)) != 0) \
+ lll_futex_wait (&(tid), __tid, LLL_SHARED);\
+ } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+ attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+ ({ \
+ int __res = 0; \
+ if ((tid) != 0) \
+ __res = __lll_timedwait_tid (&(tid), (abstime)); \
+ __res; \
+ })
+
+#endif /* lowlevellock.h */
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/pthread_once.c
new file mode 100644
index 000000000..ce68ce68c
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/pthread_once.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 2003-2013 Free Software Foundation, Inc.
+ 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 "pthreadP.h"
+#include <lowlevellock.h>
+
+
+unsigned long int __fork_generation attribute_hidden;
+
+
+static void
+clear_once_control (void *arg)
+{
+ pthread_once_t *once_control = (pthread_once_t *) arg;
+
+ *once_control = 0;
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+
+int
+__pthread_once (once_control, init_routine)
+ pthread_once_t *once_control;
+ void (*init_routine) (void);
+{
+ while (1)
+ {
+ int oldval, val, newval;
+
+ val = *once_control;
+ do
+ {
+ /* Check if the initialized has already been done. */
+ if ((val & 2) != 0)
+ return 0;
+
+ oldval = val;
+ newval = (oldval & 3) | __fork_generation | 1;
+ val = atomic_compare_and_exchange_val_acq (once_control, newval,
+ oldval);
+ }
+ while (__builtin_expect (val != oldval, 0));
+
+ /* Check if another thread already runs the initializer. */
+ if ((oldval & 1) != 0)
+ {
+ /* Check whether the initializer execution was interrupted
+ by a fork. */
+ if (((oldval ^ newval) & -4) == 0)
+ {
+ /* Same generation, some other thread was faster. Wait. */
+ lll_futex_wait (once_control, newval, LLL_PRIVATE);
+ continue;
+ }
+ }
+
+ /* This thread is the first here. Do the initialization.
+ Register a cleanup handler so that in case the thread gets
+ interrupted the initialization can be restarted. */
+ pthread_cleanup_push (clear_once_control, once_control);
+
+ init_routine ();
+
+ pthread_cleanup_pop (0);
+
+
+ /* Add one to *once_control. */
+ atomic_increment (once_control);
+
+ /* Wake up all other threads. */
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+ break;
+ }
+
+ return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/sysdep-cancel.h
new file mode 100644
index 000000000..286fa0cce
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/or1k/sysdep-cancel.h
@@ -0,0 +1,116 @@
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+ 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>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args) \
+ENTRY(__##syscall_name##_nocancel); \
+L(pseudo_nocancel): \
+ DO_CALL(syscall_name); \
+ l.j L(pseudo_finish); \
+ l.nop; \
+END(__##syscall_name##_nocancel); \
+ENTRY(name); \
+ SINGLE_THREAD_P(r13); \
+ l.sfeq r13,r0; \
+ l.bnf L(pseudo_nocancel); \
+ l.nop; \
+ /* Reserve the same amount of stack space, effectivly disregarding \
+ * how many args we're supposed to push. This makes the code easier. */ \
+ l.addi r1,r1,-28; \
+ cfi_adjust_cfa_offset(28); \
+ PUSHARGS_##args; /* CENABLE is a function call, save args for syscall. */ \
+ CENABLE; \
+ l.sw 24(r1),r11; \
+ POPARGS_##args; \
+ DO_CALL(syscall_name); \
+ l.lwz r3,24(r1); /* pass return value from CENABLE to CDISABLE. */ \
+ l.sw 24(r1),r11; /* save syscall return value for after CDISABLE. */ \
+ CDISABLE; \
+ l.lwz r11,24(r1); /* restore syscall return value. */ \
+ cfi_adjust_cfa_offset(-28); \
+ l.addi r1,r1,28; \
+L(pseudo_finish): \
+ /* if -4096 < ret < 0 holds, it's an error */ \
+ l.sfgeui r11,0xf001; \
+ l.bf L(pseudo_end); \
+ l.nop
+
+# undef PSEUDO_END
+# define PSEUDO_END(name) \
+L(pseudo_end): \
+ l.j SYSCALL_ERROR_NAME; \
+ l.ori r3,r11,0; \
+ END(name)
+
+# define PUSHARGS_0 /* nothing to do */
+# define PUSHARGS_1 PUSHARGS_0 l.sw 0(r1),r3;
+# define PUSHARGS_2 PUSHARGS_1 l.sw 4(r1),r4;
+# define PUSHARGS_3 PUSHARGS_2 l.sw 8(r1),r5;
+# define PUSHARGS_4 PUSHARGS_3 l.sw 12(r1),r6;
+# define PUSHARGS_5 PUSHARGS_4 l.sw 16(r1),r7;
+# define PUSHARGS_6 PUSHARGS_5 l.sw 20(r1),r8;
+
+# define POPARGS_0 /* nothing to do */
+# define POPARGS_1 POPARGS_0 l.lwz r3,0(r1);
+# define POPARGS_2 POPARGS_1 l.lwz r4,4(r1);
+# define POPARGS_3 POPARGS_2 l.lwz r5,8(r1);
+# define POPARGS_4 POPARGS_3 l.lwz r6,12(r1);
+# define POPARGS_5 POPARGS_4 l.lwz r7,16(r1);
+# define POPARGS_6 POPARGS_5 l.lwz r8,20(r1);
+
+# define PSEUDO_JMP(sym) l.jal sym; l.nop;
+
+# ifdef IS_IN_libpthread
+# define CENABLE PSEUDO_JMP (__pthread_enable_asynccancel)
+# define CDISABLE PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif defined IS_IN_librt
+# define CENABLE PSEUDO_JMP (__librt_enable_asynccancel)
+# define CDISABLE PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+# define CENABLE PSEUDO_JMP (__libc_enable_asynccancel)
+# define CDISABLE PSEUDO_JMP (__libc_disable_asynccancel)
+# endif
+
+# ifndef __ASSEMBLER__
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+# else
+/* It's not super nice to have "r10" hardcoded here */
+# define SINGLE_THREAD_P(reg) l.lwz reg, MULTIPLE_THREADS_OFFSET(r10)
+#endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+#endif