diff options
Diffstat (limited to 'libpthread/nptl/sysdeps/unix/sysv/linux/arm')
21 files changed, 1721 insertions, 0 deletions
| diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, 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/arm/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch new file mode 100644 index 000000000..c5852818d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/Makefile.arch @@ -0,0 +1,58 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S +libpthread_CSRC = pthread_once.c lowlevellock.c \ +                  pt-__syscall_rt_sigaction.c pt-__syscall_error.c + +libc_a_CSRC = fork.c lowlevellock.c +libc_a_SSRC = clone.S vfork.S + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-lowlevellock.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +CFLAGS-pt-__syscall_error.c =  -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -marm +# We always compile it in arm mode because of SAVE_PID macro +# This macro should be alternatively implemented in THUMB +# assembly. +ASFLAGS-vfork.S = -marm + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/arm +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/arm + +LINUX_ARCH_OBJ:=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libpthread_SSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +ifeq ($(DOPIC),y) +libpthread-a-y += $(LINUX_ARCH_OBJ:.o=.os) +else +libpthread-a-y += $(LINUX_ARCH_OBJ) +endif +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJ) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=pthread_linux_arch_objclean + +pthread_linux_arch_objclean: +	$(RM) $(LINUX_ARCH_OUT)/*.{o,os,oS} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h new file mode 100644 index 000000000..b0586ea1e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/atomic.h @@ -0,0 +1,122 @@ +/* Copyright (C) 2002, 2003, 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <stdint.h> +#include <sysdep.h> + + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +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; + +void __arm_link_error (void); + +#ifdef __thumb2__ +#define atomic_full_barrier() \ +     __asm__ __volatile__						      \ +	     ("movw\tip, #0x0fa0\n\t"					      \ +	      "movt\tip, #0xffff\n\t"					      \ +	      "blx\tip"							      \ +	      : : : "ip", "lr", "cc", "memory"); +#else +#define atomic_full_barrier() \ +     __asm__ __volatile__						      \ +	     ("mov\tip, #0xffff0fff\n\t"				      \ +	      "mov\tlr, pc\n\t"						      \ +	      "add\tpc, ip, #(0xffff0fa0 - 0xffff0fff)"			      \ +	      : : : "ip", "lr", "cc", "memory"); +#endif + +/* Atomic compare and exchange.  This sequence relies on the kernel to +   provide a compare and exchange operation which is atomic on the +   current architecture, either via cleverness on pre-ARMv6 or via +   ldrex / strex on ARMv6.  */ + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) + +/* It doesn't matter what register is used for a_oldval2, but we must +   specify one to work around GCC PR rtl-optimization/21223.  Otherwise +   it may cause a_oldval or a_tmp to be moved to a different register.  */ + +#ifdef __thumb2__ +/* Thumb-2 has ldrex/strex.  However it does not have barrier instructions, +   so we still need to use the kernel helper.  */ +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +  ({ register __typeof (oldval) a_oldval asm ("r0");			      \ +     register __typeof (oldval) a_newval asm ("r1") = (newval);		      \ +     register __typeof (mem) a_ptr asm ("r2") = (mem);			      \ +     register __typeof (oldval) a_tmp asm ("r3");			      \ +     register __typeof (oldval) a_oldval2 asm ("r4") = (oldval);	      \ +     __asm__ __volatile__						      \ +	     ("0:\tldr\t%[tmp],[%[ptr]]\n\t"				      \ +	      "cmp\t%[tmp], %[old2]\n\t"				      \ +	      "bne\t1f\n\t"						      \ +	      "mov\t%[old], %[old2]\n\t"				      \ +	      "movw\t%[tmp], #0x0fc0\n\t"				      \ +	      "movt\t%[tmp], #0xffff\n\t"				      \ +	      "blx\t%[tmp]\n\t"						      \ +	      "bcc\t0b\n\t"						      \ +	      "mov\t%[tmp], %[old2]\n\t"				      \ +	      "1:"							      \ +	      : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp)		      \ +	      : [new] "r" (a_newval), [ptr] "r" (a_ptr),		      \ +		[old2] "r" (a_oldval2)					      \ +	      : "ip", "lr", "cc", "memory");				      \ +     a_tmp; }) +#else +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +  ({ register __typeof (oldval) a_oldval asm ("r0");			      \ +     register __typeof (oldval) a_newval asm ("r1") = (newval);		      \ +     register __typeof (mem) a_ptr asm ("r2") = (mem);			      \ +     register __typeof (oldval) a_tmp asm ("r3");			      \ +     register __typeof (oldval) a_oldval2 asm ("r4") = (oldval);	      \ +     __asm__ __volatile__						      \ +	     ("0:\tldr\t%[tmp],[%[ptr]]\n\t"				      \ +	      "cmp\t%[tmp], %[old2]\n\t"				      \ +	      "bne\t1f\n\t"						      \ +	      "mov\t%[old], %[old2]\n\t"				      \ +	      "mov\t%[tmp], #0xffff0fff\n\t"				      \ +	      "mov\tlr, pc\n\t"						      \ +	      "add\tpc, %[tmp], #(0xffff0fc0 - 0xffff0fff)\n\t"		      \ +	      "bcc\t0b\n\t"						      \ +	      "mov\t%[tmp], %[old2]\n\t"				      \ +	      "1:"							      \ +	      : [old] "=&r" (a_oldval), [tmp] "=&r" (a_tmp)		      \ +	      : [new] "r" (a_newval), [ptr] "r" (a_ptr),		      \ +		[old2] "r" (a_oldval2)					      \ +	      : "ip", "lr", "cc", "memory");				      \ +     a_tmp; }) +#endif + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ +  ({ __arm_link_error (); oldval; }) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h new file mode 100644 index 000000000..e1b115c8c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/pthreadtypes.h @@ -0,0 +1,181 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 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, 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 + +#include <endian.h> + +#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; + + +typedef union +{ +  char __size[__SIZEOF_PTHREAD_ATTR_T]; +  long int __align; +} pthread_attr_t; + + +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; +#if __BYTE_ORDER == __BIG_ENDIAN +    unsigned char __pad1; +    unsigned char __pad2; +    unsigned char __shared; +    /* FLAGS must stay at this position in the structure to maintain +       binary compatibility.  */ +    unsigned char __flags; +#else +    /* 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; +#endif +    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 + + +#endif	/* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h new file mode 100644 index 000000000..dadfac2af --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/bits/semaphore.h @@ -0,0 +1,35 @@ +/* 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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/arm/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S new file mode 100644 index 000000000..23227eb24 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/clone.S @@ -0,0 +1,3 @@ +#define RESET_PID +#include <tcb-offsets.h> +#include "../../../../../../../libc/sysdeps/linux/arm/clone.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c new file mode 100644 index 000000000..2d4355980 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +/* 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/arm/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c new file mode 100644 index 000000000..1c8f4c43a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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,	\ +		  NULL, NULL, NULL, &THREAD_SELF->tid) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c new file mode 100644 index 000000000..8c8955e05 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.c @@ -0,0 +1,134 @@ +/* low level locking for pthread library.  Generic futex-using version. +   Copyright (C) 2003, 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <errno.h> +#include <sysdep.h> +#include <lowlevellock.h> +#include <sys/time.h> +#include <tls.h> + +void +__lll_lock_wait_private (int *futex) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2, LLL_PRIVATE); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +/* These functions don't get included in libc.so  */ +#ifdef IS_IN_libpthread +void +__lll_lock_wait (int *futex, int private) +{ +  do +    { +      int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); +      if (oldval != 0) +	lll_futex_wait (futex, 2, private); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) +{ +  struct timespec rt; + +  /* Reject invalid timeouts.  */ +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Upgrade the lock.  */ +  if (atomic_exchange_acq (futex, 2) == 0) +    return 0; + +  do +    { +      struct timeval tv; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      // XYZ: Lost the lock to check whether it was private. +      lll_futex_timed_wait (futex, 2, &rt, private); +    } +  while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + +  return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ +  int tid; + +  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) +    return EINVAL; + +  /* Repeat until thread terminated.  */ +  while ((tid = *tidp) != 0) +    { +      struct timeval tv; +      struct timespec rt; + +      /* Get the current time.  */ +      (void) gettimeofday (&tv, NULL); + +      /* Compute relative timeout.  */ +      rt.tv_sec = abstime->tv_sec - tv.tv_sec; +      rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; +      if (rt.tv_nsec < 0) +	{ +	  rt.tv_nsec += 1000000000; +	  --rt.tv_sec; +	} + +      /* Already timed out?  */ +      if (rt.tv_sec < 0) +	return ETIMEDOUT; + +      /* Wait until thread terminates.  */ +      // XYZ: Lost the lock to check whether it was private. +      if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT) +	return ETIMEDOUT; +    } + +  return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h new file mode 100644 index 000000000..4c7d08c92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/lowlevellock.h @@ -0,0 +1,282 @@ +/* Copyright (C) 2005, 2006, 2007, 2008, 2009 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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_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_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);				      \ +  }) + + +#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);			\ +    }) +#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);			\ +    }) +#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_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/arm/nptl-aeabi_unwind_cpp_pr1.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c new file mode 100644 index 000000000..7b8352243 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/nptl-aeabi_unwind_cpp_pr1.c @@ -0,0 +1 @@ +#include <aeabi_unwind_cpp_pr1.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c new file mode 100644 index 000000000..5a48a9b2e --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_error.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/arm/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..50137c84a --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-__syscall_rt_sigaction.c @@ -0,0 +1 @@ +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c new file mode 100644 index 000000000..08710f1c8 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-gettimeofday.c @@ -0,0 +1,5 @@ +#include <sys/syscall.h> +#include <sys/time.h> + +int gettimeofday (struct timeval *, struct timezone *) attribute_hidden; +_syscall2(int, gettimeofday, struct timeval *, tv, struct timezone *, tz); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S new file mode 100644 index 000000000..9764e9ee2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pt-vfork.S @@ -0,0 +1,38 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tcb-offsets.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	str	lr, [sp, #-4]!;		/* Save LR.  */			\ +	mov	r0, #0xffff0fff;	/* Point to the high page.  */	\ +	mov	lr, pc;			/* Save our return address.  */	\ +	sub	pc, r0, #31;		/* Jump to the TLS entry.  */	\ +	ldr	lr, [sp], #4;		/* Restore LR.  */		\ +	mov	r2, r0;			/* Save the TLS addr in r2.  */	\ +	ldr	r3, [r2, #PID_OFFSET];	/* Load the saved PID.  */	\ +	rsb	r0, r3, #0;		/* Negate it.  */		\ +	str	r0, [r2, #PID_OFFSET]	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	cmp	r0, #0;			/* If we are the parent... */	\ +	strne	r3, [r2, #PID_OFFSET]	/* ... restore the saved PID.  */ + +#INCLUDE <../../../../../../../LIBC/SYSDEPS/LINUX/ARM/VFORK.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c new file mode 100644 index 000000000..d81ecd4e5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/pthread_once.c @@ -0,0 +1,99 @@ +/* Copyright (C) 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#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 (pthread_once_t *once_control, void (*init_routine) (void)) +{ +  for (;;) +    { +      int oldval; +      int newval; + +      /* Pseudo code: +	 newval = __fork_generation | 1; +	 oldval = *once_control; +	 if ((oldval & 2) == 0) +	   *once_control = newval; +	 Do this atomically. +      */ +      do +	{ +	  newval = __fork_generation | 1; +	  oldval = *once_control; +	  if (oldval & 2) +	    break; +	} while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval); + +      /* Check if the initializer has already been done.  */ +      if ((oldval & 2) != 0) +	return 0; + +      /* Check if another thread already runs the initializer.	*/ +      if ((oldval & 1) == 0) +	break; + +      /* Check whether the initializer execution was interrupted by a fork.  */ +      if (oldval != newval) +	break; + +      /* Same generation, some other thread was faster. Wait.  */ +      lll_futex_wait (once_control, oldval, LLL_PRIVATE); +    } + +  /* 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); + +  /* Say that the initialisation is done.  */ +  *once_control = __fork_generation | 2; + +  /* Wake up all other threads.  */ +  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + +  return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) + +#if defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__PIC__) +/* When statically linked, if pthread_create is used, this file +   will be brought in.  The exception handling code in GCC assumes +   that if pthread_create is available, so are these.  */ +const void *include_pthread_getspecific attribute_hidden = pthread_getspecific; +const void *include_pthread_setspecific attribute_hidden = pthread_setspecific; +const void *include_pthread_key_create attribute_hidden = pthread_key_create; +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h new file mode 100644 index 000000000..423c23195 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004, 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <sysdep.h> +#include <tcb-offsets.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)				\ +  .section ".text";							\ +    PSEUDO_PROLOGUE;							\ +  .type __##syscall_name##_nocancel,%function;				\ +  .globl __##syscall_name##_nocancel;					\ +  __##syscall_name##_nocancel:						\ +    DO_CALL (syscall_name, args);					\ +    PSEUDO_RET;								\ +  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;	\ +  ENTRY (name);								\ +    SINGLE_THREAD_P;							\ +    DOARGS_##args;							\ +    bne .Lpseudo_cancel;						\ +    DO_CALL (syscall_name, 0);						\ +    UNDOARGS_##args;							\ +    cmn r0, $4096;							\ +    PSEUDO_RET;								\ +  .Lpseudo_cancel:							\ +    DOCARGS_##args;	/* save syscall args etc. around CENABLE.  */	\ +    CENABLE;								\ +    mov ip, r0;		/* put mask in safe place.  */			\ +    UNDOCARGS_##args;	/* restore syscall args.  */			\ +    swi SYS_ify (syscall_name);	/* do the call.  */			\ +    str r0, [sp, $-4]!; /* save syscall return value.  */		\ +    mov r0, ip;		/* get mask back.  */				\ +    CDISABLE;								\ +    ldmfd sp!, {r0, lr}; /* retrieve return value and address.  */	\ +    UNDOARGS_##args;							\ +    cmn r0, $4096; + +# define DOCARGS_0	str lr, [sp, #-4]!; +# define UNDOCARGS_0 + +# define DOCARGS_1	stmfd sp!, {r0, lr}; +# define UNDOCARGS_1	ldr r0, [sp], #4; + +# define DOCARGS_2	stmfd sp!, {r0, r1, lr}; +# define UNDOCARGS_2	ldmfd sp!, {r0, r1}; + +# define DOCARGS_3	stmfd sp!, {r0, r1, r2, lr}; +# define UNDOCARGS_3	ldmfd sp!, {r0, r1, r2}; + +# define DOCARGS_4	stmfd sp!, {r0, r1, r2, r3, lr}; +# define UNDOCARGS_4	ldmfd sp!, {r0, r1, r2, r3}; + +# define DOCARGS_5	DOCARGS_4 +# define UNDOCARGS_5	UNDOCARGS_4 + +# define DOCARGS_6	DOCARGS_5 +# define UNDOCARGS_6	UNDOCARGS_5 + +# ifdef IS_IN_libpthread +#  define CENABLE	bl PLTJMP(__pthread_enable_asynccancel) +#  define CDISABLE	bl PLTJMP(__pthread_disable_asynccancel) +#  define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +#  define CENABLE	bl PLTJMP(__libc_enable_asynccancel) +#  define CDISABLE	bl PLTJMP(__libc_disable_asynccancel) +#  define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +#  define CENABLE	bl PLTJMP(__librt_enable_asynccancel) +#  define CDISABLE	bl PLTJMP(__librt_disable_asynccancel) +# else +#  error Unsupported library +# endif + +# if defined IS_IN_libpthread || !defined NOT_IN_libc +#  ifndef __ASSEMBLER__ +extern int __local_multiple_threads attribute_hidden; +#   define SINGLE_THREAD_P __builtin_expect (__local_multiple_threads == 0, 1) +#  else +#   define SINGLE_THREAD_P						\ +  ldr ip, 1b;								\ +2:									\ +  ldr ip, [pc, ip];							\ +  teq ip, #0; +#   define PSEUDO_PROLOGUE						\ +  1:  .word __local_multiple_threads - 2f - 8; +#  endif +# else +/*  There is no __local_multiple_threads for librt, so use the TCB.  */ +#  ifndef __ASSEMBLER__ +#   define SINGLE_THREAD_P						\ +  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				\ +				   header.multiple_threads) == 0, 1) +#  else +#   define PSEUDO_PROLOGUE +#   define SINGLE_THREAD_P						\ +  stmfd	sp!, {r0, lr};							\ +  bl	__aeabi_read_tp;						\ +  ldr	ip, [r0, #MULTIPLE_THREADS_OFFSET];				\ +  ldmfd	sp!, {r0, lr};							\ +  teq	ip, #0 +#   define SINGLE_THREAD_P_PIC(x) SINGLE_THREAD_P +#  endif +# 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 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c new file mode 100644 index 000000000..d095d3083 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2003, 2009 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>. + +   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, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#include <pthreadP.h> +#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym            dlsym +#define __libc_dlclose          dlclose + +static void *libgcc_s_handle; +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) +  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, +   struct _Unwind_Context *); +static _Unwind_Reason_Code (*libgcc_s_forcedunwind) +  (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *); +static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *); +static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *); +static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *); + +void +__attribute_noinline__ +pthread_cancel_init (void) +{ +  void *resume, *personality, *forcedunwind, *getcfa; +  void *handle; +  void *sjlj_register, *sjlj_unregister; + +  if (__builtin_expect (libgcc_s_handle != NULL, 1)) +    { +      /* Force gcc to reload all values.  */ +      asm volatile ("" ::: "memory"); +      return; +    } + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL +      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL +      || (forcedunwind = __libc_dlsym (handle, "_Unwind_SjLj_ForcedUnwind")) +	 == NULL +      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL +      ) +      fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +  libgcc_s_forcedunwind = forcedunwind; +  libgcc_s_sjlj_register = sjlj_register; +  libgcc_s_sjlj_unregister = sjlj_unregister; +  libgcc_s_getcfa = getcfa; +  /* Make sure libgcc_s_getcfa is written last.  Otherwise, +     pthread_cancel_init might return early even when the pointer the +     caller is interested in is not initialized yet.  */ +  atomic_write_barrier (); +  libgcc_s_handle = handle; +} + +void +__libc_freeres_fn_section +__unwind_freeres (void) +{ +  void *handle = libgcc_s_handle; +  if (handle != NULL) +    { +      libgcc_s_handle = NULL; +      __libc_dlclose (handle); +    } +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ +  if (__builtin_expect (libgcc_s_resume == NULL, 0)) +    pthread_cancel_init (); + +  libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, +		      _Unwind_Exception_Class exception_class, +                      struct _Unwind_Exception *ue_header, +                      struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_personality == NULL, 0)) +    pthread_cancel_init (); + +  return libgcc_s_personality (version, actions, exception_class, +			       ue_header, context); +} + +_Unwind_Reason_Code +_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, +		      void *stop_argument) +{ +  if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0)) +    pthread_cancel_init (); + +  return libgcc_s_forcedunwind (exc, stop, stop_argument); +} + +_Unwind_Word +_Unwind_GetCFA (struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_getcfa == NULL, 0)) +    pthread_cancel_init (); + +  return libgcc_s_getcfa (context); +} + +void +_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0)) +    pthread_cancel_init (); + +  libgcc_s_sjlj_register (fc); +} + +void +_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0)) +    pthread_cancel_init (); + +  libgcc_s_sjlj_unregister (fc); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c new file mode 100644 index 000000000..bf0348ac2 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind-resume.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. +   This file is part of the GNU C Library. +   Contributed by Jakub Jelinek <jakub@redhat.com>. + +   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, +   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +   Boston, MA 02111-1307, USA.  */ + +#include <dlfcn.h> +#include <stdio.h> +#include <unwind.h> +#define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY)) +#define __libc_dlsym            dlsym +#define __libc_dlclose		dlclose + +static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); +static _Unwind_Reason_Code (*libgcc_s_personality) +  (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, +   struct _Unwind_Context *); +static void (*libgcc_s_sjlj_register) (struct SjLj_Function_Context *); +static void (*libgcc_s_sjlj_unregister) (struct SjLj_Function_Context *); + +static void +init (void) +{ +  void *resume, *personality; +  void *handle; +  void *sjlj_register, *sjlj_unregister; + +  handle = __libc_dlopen ("libgcc_s.so.1"); + +  if (handle == NULL +      || (sjlj_register = __libc_dlsym (handle, "_Unwind_SjLj_Register")) == NULL +      || (sjlj_unregister = __libc_dlsym (handle, "_Unwind_SjLj_Unregister")) == NULL +      || (resume = __libc_dlsym (handle, "_Unwind_SjLj_Resume")) == NULL +      || (personality = __libc_dlsym (handle, "__gcc_personality_sj0")) == NULL) +      fprintf(stderr, "libgcc_s.so.1 must be installed for pthread_cancel to work\n"); + +  libgcc_s_resume = resume; +  libgcc_s_personality = personality; +  libgcc_s_sjlj_register = sjlj_register; +  libgcc_s_sjlj_unregister = sjlj_unregister; +} + +void +_Unwind_Resume (struct _Unwind_Exception *exc) +{ +  if (__builtin_expect (libgcc_s_resume == NULL, 0)) +    init (); +  libgcc_s_resume (exc); +} + +_Unwind_Reason_Code +__gcc_personality_v0 (int version, _Unwind_Action actions, +		      _Unwind_Exception_Class exception_class, +                      struct _Unwind_Exception *ue_header, +                      struct _Unwind_Context *context) +{ +  if (__builtin_expect (libgcc_s_personality == NULL, 0)) +    init (); +  return libgcc_s_personality (version, actions, exception_class, +			       ue_header, context); +} + +void +_Unwind_SjLj_Register (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_register == NULL, 0)) +    init (); +  libgcc_s_sjlj_register (fc); +} + +void +_Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc) +{ +  if (__builtin_expect (libgcc_s_sjlj_unregister == NULL, 0)) +    init (); +  libgcc_s_sjlj_unregister (fc); +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h new file mode 100644 index 000000000..eeb9cf8b6 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/unwind.h @@ -0,0 +1,279 @@ +/* Header file for the ARM EABI unwinder +   Copyright (C) 2003, 2004, 2005, 2009  Free Software Foundation, Inc. +   Contributed by Paul Brook + +   This file is free software; you can redistribute it and/or modify it +   under the terms of the GNU General Public License as published by the +   Free Software Foundation; either version 2, or (at your option) any +   later version. + +   In addition to the permissions in the GNU General Public License, the +   Free Software Foundation gives you unlimited permission to link the +   compiled version of this file into combinations with other programs, +   and to distribute those combinations without any restriction coming +   from the use of this file.  (The General Public License restrictions +   do apply in other respects; for example, they cover modification of +   the file, and distribution when not linked into a combine +   executable.) + +   This file 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 +   General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; see the file COPYING.  If not, write to +   the Free Software Foundation, 51 Franklin Street, Fifth Floor, +   Boston, MA 02110-1301, USA.  */ + +/* Language-independent unwinder header public defines.  This contains both +   ABI defined objects, and GNU support routines.  */ + +#ifndef UNWIND_ARM_H +#define UNWIND_ARM_H + +#define __ARM_EABI_UNWINDER__ 1 + +#ifdef __cplusplus +extern "C" { +#endif +  typedef unsigned _Unwind_Word __attribute__((__mode__(__word__))); +  typedef signed _Unwind_Sword __attribute__((__mode__(__word__))); +  typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); +  typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__))); +  typedef _Unwind_Word _uw; +  typedef unsigned _uw64 __attribute__((mode(__DI__))); +  typedef unsigned _uw16 __attribute__((mode(__HI__))); +  typedef unsigned _uw8 __attribute__((mode(__QI__))); + +  typedef enum +    { +      _URC_OK = 0,       /* operation completed successfully */ +      _URC_FOREIGN_EXCEPTION_CAUGHT = 1, +      _URC_END_OF_STACK = 5, +      _URC_HANDLER_FOUND = 6, +      _URC_INSTALL_CONTEXT = 7, +      _URC_CONTINUE_UNWIND = 8, +      _URC_FAILURE = 9   /* unspecified failure of some kind */ +    } +  _Unwind_Reason_Code; + +  typedef enum +    { +      _US_VIRTUAL_UNWIND_FRAME = 0, +      _US_UNWIND_FRAME_STARTING = 1, +      _US_UNWIND_FRAME_RESUME = 2, +      _US_ACTION_MASK = 3, +      _US_FORCE_UNWIND = 8, +      _US_END_OF_STACK = 16 +    } +  _Unwind_State; + +  /* Provided only for for compatibility with existing code.  */ +  typedef int _Unwind_Action; +#define _UA_SEARCH_PHASE	1 +#define _UA_CLEANUP_PHASE	2 +#define _UA_HANDLER_FRAME	4 +#define _UA_FORCE_UNWIND	8 +#define _UA_END_OF_STACK	16 +#define _URC_NO_REASON 	_URC_OK + +  typedef struct _Unwind_Control_Block _Unwind_Control_Block; +  typedef struct _Unwind_Context _Unwind_Context; +  typedef _uw _Unwind_EHT_Header; + + +  /* UCB: */ + +  struct _Unwind_Control_Block +    { +#ifdef _LIBC +      /* For the benefit of code which assumes this is a scalar.  All +	 glibc ever does is clear it.  */ +      _uw64 exception_class; +#else +      char exception_class[8]; +#endif +      void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *); +      /* Unwinder cache, private fields for the unwinder's use */ +      struct +	{ +	  _uw reserved1;  /* Forced unwind stop fn, 0 if not forced */ +	  _uw reserved2;  /* Personality routine address */ +	  _uw reserved3;  /* Saved callsite address */ +	  _uw reserved4;  /* Forced unwind stop arg */ +	  _uw reserved5; +	} +      unwinder_cache; +      /* Propagation barrier cache (valid after phase 1): */ +      struct +	{ +	  _uw sp; +	  _uw bitpattern[5]; +	} +      barrier_cache; +      /* Cleanup cache (preserved over cleanup): */ +      struct +	{ +	  _uw bitpattern[4]; +	} +      cleanup_cache; +      /* Pr cache (for pr's benefit): */ +      struct +	{ +	  _uw fnstart;			/* function start address */ +	  _Unwind_EHT_Header *ehtp;	/* pointer to EHT entry header word */ +	  _uw additional;		/* additional data */ +	  _uw reserved1; +	} +      pr_cache; +      long long int :0;	/* Force alignment to 8-byte boundary */ +    }; + +  /* Virtual Register Set*/ + +  typedef enum +    { +      _UVRSC_CORE = 0,      /* integer register */ +      _UVRSC_VFP = 1,       /* vfp */ +      _UVRSC_FPA = 2,       /* fpa */ +      _UVRSC_WMMXD = 3,     /* Intel WMMX data register */ +      _UVRSC_WMMXC = 4      /* Intel WMMX control register */ +    } +  _Unwind_VRS_RegClass; + +  typedef enum +    { +      _UVRSD_UINT32 = 0, +      _UVRSD_VFPX = 1, +      _UVRSD_FPAX = 2, +      _UVRSD_UINT64 = 3, +      _UVRSD_FLOAT = 4, +      _UVRSD_DOUBLE = 5 +    } +  _Unwind_VRS_DataRepresentation; + +  typedef enum +    { +      _UVRSR_OK = 0, +      _UVRSR_NOT_IMPLEMENTED = 1, +      _UVRSR_FAILED = 2 +    } +  _Unwind_VRS_Result; + +  /* Frame unwinding state.  */ +  typedef struct +    { +      /* The current word (bytes packed msb first).  */ +      _uw data; +      /* Pointer to the next word of data.  */ +      _uw *next; +      /* The number of bytes left in this word.  */ +      _uw8 bytes_left; +      /* The number of words pointed to by ptr.  */ +      _uw8 words_left; +    } +  __gnu_unwind_state; + +  typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State, +      _Unwind_Control_Block *, _Unwind_Context *); + +  _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass, +                                     _uw, _Unwind_VRS_DataRepresentation, +                                     void *); + +  _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass, +                                     _uw, _Unwind_VRS_DataRepresentation, +                                     void *); + +  _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass, +                                     _uw, _Unwind_VRS_DataRepresentation); + + +  /* Support functions for the PR.  */ +#define _Unwind_Exception _Unwind_Control_Block +  typedef char _Unwind_Exception_Class[8]; + +  void * _Unwind_GetLanguageSpecificData (_Unwind_Context *); +  _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *); + +  /* These two should never be used.  */ +  _Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *); +  _Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *); + +  /* Interface functions: */ +  _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp); +  void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp); +  _Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp); + +  typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) +       (int, _Unwind_Action, _Unwind_Exception_Class, +	_Unwind_Control_Block *, struct _Unwind_Context *, void *); +  _Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *, +					    _Unwind_Stop_Fn, void *); +  _Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *); +  void _Unwind_Complete(_Unwind_Control_Block *ucbp); +  void _Unwind_DeleteException (_Unwind_Exception *); + +  _Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *, +					  _Unwind_Context *); +  _Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *, +					    __gnu_unwind_state *); + +  /* Decode an R_ARM_TARGET2 relocation.  */ +  static inline _Unwind_Word +  _Unwind_decode_target2 (_Unwind_Word ptr) +    { +      _Unwind_Word tmp; + +      tmp = *(_Unwind_Word *) ptr; +      /* Zero values are always NULL.  */ +      if (!tmp) +	return 0; + +#if defined(linux) || defined(__NetBSD__) +      /* Pc-relative indirect.  */ +      tmp += ptr; +      tmp = *(_Unwind_Word *) tmp; +#elif defined(__symbian__) +      /* Absolute pointer.  Nothing more to do.  */ +#else +      /* Pc-relative pointer.  */ +      tmp += ptr; +#endif +      return tmp; +    } + +  static inline _Unwind_Word +  _Unwind_GetGR (_Unwind_Context *context, int regno) +    { +      _uw val; +      _Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); +      return val; +    } + +  /* Return the address of the instruction, not the actual IP value.  */ +#define _Unwind_GetIP(context) \ +  (_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1) + +  static inline void +  _Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val) +    { +      _Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); +    } + +  /* The dwarf unwinder doesn't understand arm/thumb state.  We assume the +     landing pad uses the same instruction set as the call site.  */ +#define _Unwind_SetIP(context, val) \ +  _Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1)) + +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) +     (struct _Unwind_Context *, void *); + +extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *); + +#ifdef __cplusplus +}   /* extern "C" */ +#endif + +#endif /* defined UNWIND_ARM_H */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S new file mode 100644 index 000000000..935a4e904 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arm/vfork.S @@ -0,0 +1,39 @@ +/* Copyright (C) 2005 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, write to the Free +   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +   02111-1307 USA.  */ + +#include <tcb-offsets.h> + +/* Save the PID value.  */ +#define SAVE_PID \ +	str	lr, [sp, #-4]!;		/* Save LR.  */			\ +	mov	r0, #0xffff0fff;	/* Point to the high page.  */	\ +	mov	lr, pc;			/* Save our return address.  */	\ +	sub	pc, r0, #31;		/* Jump to the TLS entry.  */	\ +	ldr	lr, [sp], #4;		/* Restore LR.  */		\ +	mov	r2, r0;			/* Save the TLS addr in r2.  */	\ +	ldr	r3, [r2, #PID_OFFSET];	/* Load the saved PID.  */	\ +	rsbs	r0, r3, #0;		/* Negate it.  */		\ +	moveq	r0, #0x80000000;	/* Use 0x80000000 if it was 0.  */ \ +	str	r0, [r2, #PID_OFFSET]	/* Store the temporary PID.  */ + +/* Restore the old PID value in the parent.  */ +#define RESTORE_PID \ +	cmp	r0, #0;			/* If we are the parent... */	\ +	strne	r3, [r2, #PID_OFFSET]	/* ... restore the saved PID.  */ + +#include "../../../../../../../libc/sysdeps/linux/arm/vfork.S" | 
