From 6af3332a4cbd1ffbc81f74759ef7c5e1a87d2e10 Mon Sep 17 00:00:00 2001 From: Vincent Ren-Wei Chen Date: Tue, 17 Jan 2017 07:31:24 +0100 Subject: nds32: add NPTL/TLS, *context function, libm changes and code cleanup This commit includes following features. 1. Support NPTL/TLS 2. Add libm function which is used to handle FP rounding and excpetions (ex: fclrexcpt,fedisblxcpti,feenablxcpt... ) 3. Add *context function for operating user context (ex: setcontext,getcontext,makecontext... ) 4. Change the return flow from signal handler 5. Cleanup of old code The testsuite only has 2 errors, tst-cpuclock1 and tst-cputimer1, which are related to timing accuracy. (math and locale tests are disabled) Signed-off-by: Vincent Ren-Wei Chen --- .../nptl/sysdeps/unix/sysv/linux/nds32/Makefile | 9 + .../sysdeps/unix/sysv/linux/nds32/Makefile.arch | 12 + .../unix/sysv/linux/nds32/bits/pthreadtypes.h | 177 +++++++++++ .../sysdeps/unix/sysv/linux/nds32/bits/semaphore.h | 38 +++ .../nptl/sysdeps/unix/sysv/linux/nds32/clone.S | 4 + .../sysdeps/unix/sysv/linux/nds32/createthread.c | 22 ++ .../nptl/sysdeps/unix/sysv/linux/nds32/fork.c | 27 ++ .../sysdeps/unix/sysv/linux/nds32/lowlevellock.h | 323 +++++++++++++++++++++ .../nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c | 18 ++ .../sysdeps/unix/sysv/linux/nds32/pthread_once.c | 92 ++++++ .../sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h | 273 +++++++++++++++++ .../nptl/sysdeps/unix/sysv/linux/nds32/vfork.S | 43 +++ 12 files changed, 1038 insertions(+) create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux') diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile new file mode 100644 index 000000000..2caba11b7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/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/nds32/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch new file mode 100644 index 000000000..3b8935ce5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/Makefile.arch @@ -0,0 +1,12 @@ +# 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 +libc_linux_arch_SSRC = clone.S vfork.S +libc_linux_arch_SSRC-OMIT = waitpid.S + +CFLAGS += $(SSP_ALL_CFLAGS) + diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/pthreadtypes.h new file mode 100644 index 000000000..695a61fdd --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/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/nds32/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h new file mode 100644 index 000000000..8ee77429a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/bits/semaphore.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use directly; include instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX (2147483647) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S new file mode 100644 index 000000000..94b39fcf9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/clone.S @@ -0,0 +1,4 @@ +/* We want an #include_next, but we are the main source file. + So, #include ourselves and in that incarnation we can use #include_next. */ +# define RESET_PID +# include diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c new file mode 100644 index 000000000..486bc24f5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/createthread.c @@ -0,0 +1,22 @@ +/* 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 + . */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE ((void *) (pd) \ + + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE) + +/* Get the real implementation. */ +#include diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c new file mode 100644 index 000000000..beb6cb0f7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/fork.c @@ -0,0 +1,27 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + Contributed by Phil Blundell , 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 + . */ +#include +#include +#include +#include + +#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/nds32/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/lowlevellock.h new file mode 100644 index 000000000..32b004486 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/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 + . */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include +#include +#include +#include +#include +#include + + +#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/nds32/pt-raise.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c new file mode 100644 index 000000000..6c0d4b5d3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pt-raise.c @@ -0,0 +1,18 @@ +/* Copyright (C) 2002-2013 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 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 + . */ + +#include diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c new file mode 100644 index 000000000..ce68ce68c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/pthread_once.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2003-2013 Free Software Foundation, Inc. + Contributed by Jakub Jelinek , 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 + . */ + +#include "pthreadP.h" +#include + + +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/nds32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h new file mode 100644 index 000000000..a0f4de5c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/sysdep-cancel.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 2003-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 + . */ + +#include +#include +#ifndef __ASSEMBLER__ +# include +#endif + + + +#define PUSHARGS_0 +#define PUSHARGS_1 smw.adm $r0, [$sp], $r0, #0; \ + cfi_adjust_cfa_offset(4); \ + cfi_rel_offset(r0,0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); +#define PUSHARGS_2 smw.adm $r0, [$sp], $r1, #0; \ + cfi_adjust_cfa_offset(8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); +#define PUSHARGS_3 smw.adm $r0, [$sp], $r2, #0; \ + cfi_adjust_cfa_offset(12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); +#define PUSHARGS_4 smw.adm $r0, [$sp], $r3, #0; \ + cfi_adjust_cfa_offset(16); \ + cfi_rel_offset(r3, 12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); +#define PUSHARGS_5 smw.adm $r0, [$sp], $r4, #0; \ + cfi_adjust_cfa_offset(20); \ + cfi_rel_offset(r4, 16); \ + cfi_rel_offset(r3, 12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); +#define PUSHARGS_6 smw.adm $r0, [$sp], $r5, #0; \ + cfi_adjust_cfa_offset(24); \ + cfi_rel_offset(r5, 20); \ + cfi_rel_offset(r4, 16); \ + cfi_rel_offset(r3, 12); \ + cfi_rel_offset(r2, 8); \ + cfi_rel_offset(r1, 4); \ + cfi_rel_offset(r0, 0); + +#define POPARGS2_0 +#define POPARGS2_1 addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + lmw.bim $r0, [$sp], $r0, #0; \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(r0); +#define POPARGS2_2 lmw.bim $r0, [$sp], $r1, #0; \ + cfi_adjust_cfa_offset(-8); \ + cfi_restore(r0); \ + cfi_restore(r1); +#define POPARGS2_3 addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + lmw.bim $r0, [$sp], $r2, #0; \ + cfi_adjust_cfa_offset(-12); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); +#define POPARGS2_4 lmw.bim $r0, [$sp], $r3, #0; \ + cfi_adjust_cfa_offset(-16); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); \ + cfi_restore(r3); +#define POPARGS2_5 addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + lmw.bim $r0, [$sp], $r4, #0; \ + cfi_adjust_cfa_offset(-20); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); \ + cfi_restore(r3); \ + cfi_restore(r4); +#define POPARGS2_6 lmw.bim $r0, [$sp], $r5, #0; \ + cfi_adjust_cfa_offset(-24); \ + cfi_restore(r0); \ + cfi_restore(r1); \ + cfi_restore(r2); \ + cfi_restore(r3); \ + cfi_restore(r4); \ + cfi_restore(r5); + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* NOTE: We do mark syscalls with unwind annotations, for the benefit of + cancellation; but they're really only accurate at the point of the + syscall. The ARM unwind directives are not rich enough without adding + a custom personality function. */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .align 2; \ + ENTRY (__##syscall_name##_nocancel); \ + __do_syscall(syscall_name); \ + PSEUDO_RET; \ + ret; \ + END (__##syscall_name##_nocancel); \ + ENTRY (name); \ + smw.adm $r6,[$sp],$r6,0x2; \ + cfi_adjust_cfa_offset(8); \ + cfi_offset(r6,-8); \ + cfi_offset(lp,-4); \ + SINGLE_THREAD_P ($r15); \ + bgtz $r15, .Lpseudo_cancel; \ + __do_syscall(syscall_name); \ + j 50f; \ + .Lpseudo_cancel: \ + PUSHARGS_##args; /* save syscall args etc. around CENABLE. */ \ + CENABLE ($r5); \ + mov55 $r6, $r0; /* put mask in safe place. */ \ + POPARGS2_##args; \ + __do_syscall(syscall_name); /* do the call. */ \ + push $r0; \ + cfi_adjust_cfa_offset(4); \ + cfi_rel_offset(r0, 0); \ + addi $sp, $sp, -4; \ + cfi_adjust_cfa_offset(4); \ + mov55 $r0, $r6; /* save syscall return value. */\ + CDISABLE($r5); \ + addi $sp, $sp, 4; \ + cfi_adjust_cfa_offset(-4); \ + pop $r0; /* retrieve return value. */ \ + cfi_adjust_cfa_offset(-4); \ + cfi_restore(r0); \ +50: \ + lmw.bim $r6,[$sp],$r6, 0x2; \ + cfi_adjust_cfa_offset(-8); \ + cfi_restore(lp); \ + cfi_restore(r6); \ + PSEUDO_RET; +# ifndef __ASSEMBLER__ +//# if defined IS_IN_libpthread || !defined NOT_IN_libc +//extern int __local_multiple_threads attribute_hidden; +//# define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +//# else +/* There is no __local_multiple_threads for librt */ +# define SINGLE_THREAD_P __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0, 1) +//# endif +# else +# define SINGLE_THREAD_P(reg) \ + addi reg, $r25, MULTIPLE_THREADS_OFFSET; \ + lw reg, [reg]; +# define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P(x) +# endif + + +# ifdef IS_IN_libpthread +# define CENABLE(reg) jmp(reg, __pthread_enable_asynccancel) +# define CDISABLE(reg) jmp(reg, __pthread_disable_asynccancel) +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE(reg) jmp(reg, __libc_enable_asynccancel) +# define CDISABLE(reg) jmp(reg, __libc_disable_asynccancel) +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE(reg) jmp(reg, __librt_enable_asynccancel) +# define CDISABLE(reg) jmp(reg, __librt_disable_asynccancel) +# else +# error Unsupported library +# endif + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera. */ +# 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 + + + +#ifdef PIC +#define PSEUDO_RET \ + .pic \ + .align 2; \ + bgez $r0, 1f; \ + sltsi $r1, $r0, -4096; \ + bgtz $r1, 1f; \ + PIC_jmp_err \ + nop; \ + 1: +#else /* PIC*/ +#define PSEUDO_RET \ + .align 2; \ + bgez $r0, 1f; \ + sltsi $r1, $r0, -4096; \ + bgtz $r1, 1f; \ + j SYSCALL_ERROR; \ + 1: +#endif + +#ifdef PIC +#define jmp(reg, symble) PIC_jmpr(reg, symble) +/* reg: available register */ +#define PIC_jmp_err \ + smw.adm $sp,[$sp],$sp,#0x6; \ + mfusr $r15, $PC; \ + sethi $gp, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ + ori $gp, $gp, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ + add $gp, $r15, $gp; \ + sethi $r15, hi20(SYSCALL_ERROR@PLT); \ + ori $r15, $r15, lo12(SYSCALL_ERROR@PLT); \ + add $r15, $r15, $gp; \ + jral $r15; \ + lmw.bim $sp,[$sp],$sp,#0x6; \ + ret; + +#define PIC_jmp(reg, symble) \ + mfusr $r15, $PC; \ + sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ + ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ + add reg, $r15, reg; \ + sethi $r15, hi20(symble@PLT); \ + ori $r15, $r15, lo12(symble@PLT); \ + add $r15, $r15, reg; \ + jr $r15; + + +#define PIC_jmpr(reg, symble) \ + mfusr $r15, $PC; \ + sethi reg, hi20(_GLOBAL_OFFSET_TABLE_ + 4); \ + ori reg, reg, lo12(_GLOBAL_OFFSET_TABLE_ + 8); \ + add reg, $r15, reg; \ + sethi $r15, hi20(symble@PLT); \ + ori $r15, $r15, lo12(symble@PLT); \ + add $r15, $r15, reg; \ + jral $r15; + +#else +#define jmp(reg, symble) jal symble +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S new file mode 100644 index 000000000..f11f76ae1 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/nds32/vfork.S @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016-2017 Andes Technology, Inc. + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* Copyright (C) 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 + . */ + +#include + +/* Save the PID value. */ +#define SAVE_PID \ + lwi $r1, [$r25 + PID_OFFSET];/* Get the thread pointer. */ \ + subri $r1, $r1, 0x0; /* Negate it. */ \ + bnez $r1, 1f; /* If it was zero... */ \ + sethi $r1, 0x80000; /* use 0x80000000 instead. */ \ +1: swi $r1, [$r25 + PID_OFFSET];/* Store the temporary PID. */ + +/* Restore the old PID value in the parent. */ +#define RESTORE_PID \ + beqz $r0, 1f; /* If we are the parent... */ \ + lwi $r1, [$r25 + PID_OFFSET];/* Get the thread pointer. */ \ + subri $r1, $r1, 0x0; /* Re-negate it. */ \ + sethi $r2, 0x80000; /* Load 0x80000000... */ \ + bne $r1, $r2, 2f; /* ... compare against it... */ \ + movi $r1, 0; /* ... use 0 instead. */ \ +2: swi $r1, [$r25 + PID_OFFSET];/* Restore the PID. */ \ +1: + +#include <../../../../../../../libc/sysdeps/linux/nds32/vfork.S> -- cgit v1.2.3