This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ARM NPTL - EABI


I've just checked in NPTL support for arm-none-linux-gnueabi.  Support for
the APCS ABI will follow in a moment.

Bits of this were originally written by Phil Blundell; thanks, Phil!  I've
butchered it all pretty thoroughly since then though.

For both ARM ports, most of the interesting bits were caused by the fact
that ARM doesn't use dwarf2 exception handling.  For EABI, all the necessary
bits have just been checked in to GCC (this morning, will be in 4.1).  The
implementation of _Unwind_GetCFA is a bit hokey, but works well enough for
NPTL.  One difference between the ARM compact EH tables and dwarf2 EH tables
is that the compact tables have only starting PC addresses, not ending; one
NPTL test had to be skipped because it relied on unwinding stopping when we
entered a region where we had no unwinding information.  As a consequence,
to use pthread cancellation on the ARM EABI, everything on the call chain
must either be compiled with exception tables, or in a shared object
containing no EH tables at all.  Otherwise, an earlier function's unwind
tables will be used with predictable results.

Atomic operations are provided by a kernel helper, in order to guarantee
atomicity on pre-ARMv6 platforms, where "swp" is the best we have.  The
kernel helper was added mid-2.6.  They could be implemented without a kernel
helper on v6 and later platforms if anyone is interested in doing that.
Futexes are implemented using only atomic_exchange_acq and swp; the cmpxchg
helper was not required here.  Nicolas Pitre lent me a hand with getting
those right.

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-11-16  Daniel Jacobowitz  <dan@codesourcery.com>

	* sysdeps/arm/bits/setjmp.h, sysdeps/arm/fpu/bits/setjmp.h: Update
	include guards.

	* sysdeps/unix/arm/sysdep.S (syscall_error): Handle USE___THREAD and
	RTLD_PRIVATE_ERRNO.

	* sysdeps/unix/sysv/linux/arm/clone.S (__clone): Handle RESET_PID.
	Handle new arguments.
	* sysdeps/unix/sysv/linux/arm/vfork.S (__vfork): Use SAVE_PID and
	RESTORE_PID.  Use the right syscall error handler.

	* sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S
	(__default_sa_restorer, __default_rt_sa_restorer): Add unwind
	information.

	* sysdeps/unix/sysv/linux/arm/eabi/socket.S: Update formatting.
	Add unwind information.  Correct stack alignment typo.

	* sysdeps/unix/sysv/linux/arm/eabi/sysdep.h
	(INTERNAL_SYSCALL_NCS): Define.

	* sysdeps/unix/sysv/linux/arm/sigaction.c
	(__libc_sigaction): Remove never-valid handling for SA_ONSTACK.

	* sysdeps/unix/sysv/linux/arm/socket.S: Whitespace cleanup.

	* sysdeps/unix/sysv/linux/arm/sysdep.h (SYSCALL_ERROR_HANDLER): Handle
	RTLD_PRIVATE_ERRNO.
	(INTERNAL_SYSCALL_NCS): Implement.

	* sysdeps/arm/nptl/Makefile, sysdeps/arm/nptl/jmpbuf-unwind.h,
	sysdeps/arm/nptl/pthread_spin_lock.S,
	sysdeps/arm/nptl/pthread_spin_trylock.S,
	sysdeps/arm/nptl/pthreaddef.h, sysdeps/arm/nptl/tcb-offsets.sym,
	sysdeps/arm/nptl/tls.h, sysdeps/unix/sysv/linux/arm/eabi/Makefile,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/Makefile,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/configure,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/configure.in,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/nptl-aeabi_unwind_cpp_pr1.c,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/rt-aeabi_unwind_cpp_pr1.c,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind-forcedunwind.c,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind-resume.c,
	sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h,
	sysdeps/unix/sysv/linux/arm/nptl/Versions,
	sysdeps/unix/sysv/linux/arm/nptl/bits/atomic.h,
	sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h,
	sysdeps/unix/sysv/linux/arm/nptl/clone.S,
	sysdeps/unix/sysv/linux/arm/nptl/createthread.c,
	sysdeps/unix/sysv/linux/arm/nptl/fork.c,
	sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.c,
	sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.h,
	sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S,
	sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c,
	sysdeps/unix/sysv/linux/arm/nptl/vfork.S: New files.

Index: glibc/ports/sysdeps/arm/bits/setjmp.h
===================================================================
--- glibc.orig/ports/sysdeps/arm/bits/setjmp.h	2005-11-16 11:12:20.000000000 -0500
+++ glibc/ports/sysdeps/arm/bits/setjmp.h	2005-11-16 11:50:51.000000000 -0500
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 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
@@ -18,7 +18,10 @@
 
 /* Define the machine-dependent type `jmp_buf'.  ARM version. */
 
-#ifndef _SETJMP_H
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H 1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -34,3 +37,5 @@ typedef int __jmp_buf[10];
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
+
+#endif
Index: glibc/ports/sysdeps/arm/fpu/bits/setjmp.h
===================================================================
--- glibc.orig/ports/sysdeps/arm/fpu/bits/setjmp.h	2005-11-16 11:12:20.000000000 -0500
+++ glibc/ports/sysdeps/arm/fpu/bits/setjmp.h	2005-11-16 11:50:51.000000000 -0500
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 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
@@ -18,7 +18,10 @@
 
 /* Define the machine-dependent type `jmp_buf'.  ARM version. */
 
-#ifndef _SETJMP_H
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H 1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
 # error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
 #endif
 
@@ -34,3 +37,5 @@ typedef int __jmp_buf[22];
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
+
+#endif
Index: glibc/ports/sysdeps/arm/nptl/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/Makefile	2005-11-16 13:26:58.000000000 -0500
@@ -0,0 +1,21 @@
+# 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.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
Index: glibc/ports/sysdeps/arm/nptl/jmpbuf-unwind.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/jmpbuf-unwind.h	2005-11-16 13:27:03.000000000 -0500
@@ -0,0 +1,30 @@
+/* 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 <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+  _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+  ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[__JMP_BUF_SP] - (_adj))
+
+/* We use the normal longjmp for unwinding.  */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
Index: glibc/ports/sysdeps/arm/nptl/pthread_spin_lock.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/pthread_spin_lock.S	2005-11-16 13:27:25.000000000 -0500
@@ -0,0 +1,31 @@
+/* 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 <sysdep.h>
+
+	.text
+	.align	4
+
+ENTRY (pthread_spin_lock)
+	mov	r1, #1
+1:	swp	r2, r1, [r0]
+	teq	r2, #0
+	bne	1b
+	mov	r0, #0
+	PSEUDO_RET_NOERRNO
+END (pthread_spin_lock)
Index: glibc/ports/sysdeps/arm/nptl/pthread_spin_trylock.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/pthread_spin_trylock.S	2005-11-16 13:27:43.000000000 -0500
@@ -0,0 +1,34 @@
+/* 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.  */
+
+#define _ERRNO_H 1
+#include <bits/errno.h>
+
+#include <sysdep.h>
+
+	.text
+	.align	4
+
+ENTRY (pthread_spin_trylock)
+	mov	r1, #1
+	swp	r2, r1, [r0]
+	teq	r2, #0
+	moveq	r0, #0
+	movne	r0, #EBUSY
+	PSEUDO_RET_NOERRNO
+END (pthread_spin_trylock)
Index: glibc/ports/sysdeps/arm/nptl/pthreaddef.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/pthreaddef.h	2005-11-16 13:28:10.000000000 -0500
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002, 2003, 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.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  SSE requires 16
+   bytes.  */
+#define STACK_ALIGN		16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK	2048
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT		16
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME	__builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
Index: glibc/ports/sysdeps/arm/nptl/tcb-offsets.sym
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/tcb-offsets.sym	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)	(long)(offsetof(struct pthread, mem) - sizeof(struct pthread))
+
+MULTIPLE_THREADS_OFFSET		thread_offsetof (header.multiple_threads)
+PID_OFFSET			thread_offsetof (pid)
+TID_OFFSET			thread_offsetof (tid)
Index: glibc/ports/sysdeps/arm/nptl/tls.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/arm/nptl/tls.h	2005-11-16 13:28:26.000000000 -0500
@@ -0,0 +1,137 @@
+/* Definition for thread-local data handling.  NPTL/ARM version.
+   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.  */
+
+#ifndef _TLS_H
+#define _TLS_H	1
+
+#include <dl-sysdep.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+/* We require TLS support in the tools.  */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP	1
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE	sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN	16
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE		sizeof (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+# define TLS_PRE_TCB_SIZE	sizeof (struct pthread)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN		16
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  (((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall) \
+  ({ INTERNAL_SYSCALL_DECL (err);					\
+     long result_var;							\
+     result_var = INTERNAL_SYSCALL_ARM (set_tls, err, 1, (tcbp));	\
+     INTERNAL_SYSCALL_ERROR_P (result_var, err)				\
+       ? "unknown error" : NULL; })
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) __builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+ ((struct pthread *)__builtin_thread_pointer () - 1)
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, sizeof (struct pthread))
+
+/* Access to data in the thread descriptor is easy.  */
+#define THREAD_GETMEM(descr, member) \
+  descr->member
+#define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+#define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+#define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* Initializing the thread pointer will generate a SIGILL if the syscall
+   is not available.  */
+#define TLS_INIT_TP_EXPENSIVE 1
+
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
Index: glibc/ports/sysdeps/unix/arm/sysdep.S
===================================================================
--- glibc.orig/ports/sysdeps/unix/arm/sysdep.S	2005-11-16 11:12:20.000000000 -0500
+++ glibc/ports/sysdeps/unix/arm/sysdep.S	2005-11-16 13:31:31.000000000 -0500
@@ -1,4 +1,6 @@
-/* Copyright (C) 1991,92,93,94,95,96,97,98,2002,03 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 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
@@ -20,8 +22,11 @@
 #define _ERRNO_H
 #include <bits/errno.h>
 
-.globl C_SYMBOL_NAME(errno)
-.globl syscall_error
+#ifdef IS_IN_rtld
+# include <dl-sysdep.h>			/* Defines RTLD_PRIVATE_ERRNO.  */
+#endif
+
+#include <tls.h>
 
 #undef syscall_error
 #ifdef NO_UNDERSCORES
@@ -37,7 +42,29 @@ syscall_error:
 	moveq r0, $EAGAIN	/* Yes; translate it to EAGAIN.  */
 #endif
 
-#ifdef _LIBC_REENTRANT
+#if USE___THREAD
+	mov ip, lr
+	mov r1, r0
+
+	mov r0, #0xffff0fff
+	mov lr, pc
+	sub pc, r0, #31
+
+	ldr r2, 1f
+2:	ldr r2, [pc, r2]
+	str r1, [r0, r2]
+	mvn r0, #0
+	RETINSTR (, ip)
+
+1:	.word errno(gottpoff) + (. - 2b - 8)
+#elif RTLD_PRIVATE_ERRNO
+	ldr r1, 1f
+0:	str r0, [pc, r1]
+	mvn r0, $0
+	DO_RET(r14)
+
+1:	.word C_SYMBOL_NAME(rtld_errno) - 0b - 8
+#elif defined(_LIBC_REENTRANT)
 	str lr, [sp, #-4]!
 	str r0, [sp, #-4]!
 	bl PLTJMP(C_SYMBOL_NAME(__errno_location))
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/clone.S
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/clone.S	2005-11-16 11:19:16.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/clone.S	2005-11-16 11:50:51.000000000 -0500
@@ -25,7 +25,11 @@
 #define _ERRNO_H	1
 #include <bits/errno.h>
 
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+	     pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
 
         .text
 ENTRY(__clone)
@@ -42,16 +46,58 @@ ENTRY(__clone)
 	@ do the system call
 	@ get flags
 	mov	r0, r2
+#ifdef RESET_PID
+	mov	ip, r2
+#endif
 	@ new sp is already in r1
-	DO_CALL (clone, 0)
-	movs	a1, a1
+#ifdef __ARM_EABI__
+	stmfd	sp!, {r4, r7}
+#else
+	str	r4, [sp, #-8]!
+#endif
+	ldr	r2, [sp, #8]
+	ldr	r3, [sp, #12]
+	ldr	r4, [sp, #16]
+#ifdef __ARM_EABI__
+	ldr	r7, =SYS_ify(clone)
+	swi	0x0
+#else
+	swi	SYS_ify(clone)
+#endif
+	cmp	r0, #0
+	beq	1f
+#ifdef __ARM_EABI__
+	ldmfd	sp!, {r4, r7}
+#else
+	ldr	r4, [sp], #8
+#endif
 	blt	PLTJMP(C_SYMBOL_NAME(__syscall_error))
-	RETINSTR(ne, lr)
+	RETINSTR(, lr)
 
+1:
+#ifdef RESET_PID
+	tst	ip, #CLONE_THREAD
+	bne	3f
+	mov	r0, #0xffff0fff
+	mov	lr, pc
+	sub	pc, r0, #31
+	mov	r1, r0
+	tst	ip, #CLONE_VM
+	movne	r0, #-1
+#ifdef __ARM_EABI__
+	ldr	r7, =SYS_ify(getpid)
+	swieq	0x0
+#else
+	swieq	SYS_ify(getpid)
+#endif
+	str	r0, [r1, #PID_OFFSET]
+	str	r0, [r1, #TID_OFFSET]
+3:
+#endif
 	@ pick the function arg and call address off the stack and execute
 	ldr	r0, [sp, #4]
 	mov	lr, pc
-	ldr 	pc, [sp]
+	ldr 	pc, [sp], #8
 
 	@ and we are done, passing the return value through r0
 	b	PLTJMP(_exit)
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/Makefile	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,6 @@
+ifeq ($(subdir),csu)
+# In order for unwinding to fail when it falls out of main, we need a
+# cantunwind marker.  There's one in start.S.  To make sure we reach it, add
+# unwind tables for __libc_start_main.
+CFLAGS-libc-start.c += -fexceptions
+endif
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/Makefile	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,17 @@
+ifeq ($(subdir),rt)
+librt-sysdep_routines += rt-aeabi_unwind_cpp_pr1
+librt-shared-only-routines += rt-aeabi_unwind_cpp_pr1
+endif
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += nptl-aeabi_unwind_cpp_pr1
+libpthread-shared-only-routines += nptl-aeabi_unwind_cpp_pr1
+
+# This test relies on compiling part of the binary with EH information,
+# part without, and unwinding through.  The .ARM.exidx tables have
+# start addresses for EH regions, but no end addresses.  Every
+# region an exception needs to propogate through must have unwind
+# information, or a previous function's unwind table may be used
+# by mistake.
+tests := $(filter-out tst-cleanupx4,$(tests))
+endif
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/configure
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/configure	2005-11-16 13:44:22.000000000 -0500
@@ -0,0 +1,4 @@
+# This file is generated from configure.in by Autoconf.  DO NOT EDIT!
+
+libc_cv_gcc_exceptions=yes
+exceptions=-fexceptions
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/configure.in
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/configure.in	2005-11-16 13:44:05.000000000 -0500
@@ -0,0 +1,8 @@
+dnl configure fragment for NPTL and ARM/Linux EABI.
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+
+dnl The normal configure check for gcc -fexecptions fails because it can't
+dnl find __aeabi_unwind_cpp_pr0.  Work around this here; our GCC definitely
+dnl has -fexceptions.
+libc_cv_gcc_exceptions=yes
+exceptions=-fexceptions
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/nptl-aeabi_unwind_cpp_pr1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/nptl-aeabi_unwind_cpp_pr1.c	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1 @@
+#include <aeabi_unwind_cpp_pr1.c>
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/rt-aeabi_unwind_cpp_pr1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/rt-aeabi_unwind_cpp_pr1.c	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1 @@
+#include <aeabi_unwind_cpp_pr1.c>
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/sysdep-cancel.h	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,149 @@
+/* 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 <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#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)				\
+  .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:							\
+    .fnstart;								\
+    DOCARGS_##args;	/* save syscall args etc. around CENABLE.  */	\
+    CENABLE;								\
+    mov ip, r0;		/* put mask in safe place.  */			\
+    UNDOCARGS_##args;	/* restore syscall args.  */			\
+    ldr r7, =SYS_ify (syscall_name);					\
+    swi 0x0;		/* do the call.  */				\
+    .fnend;		/* Past here we can't easily unwind.  */	\
+    mov r7, r0;		/* save syscall return value.  */		\
+    mov r0, ip;		/* get mask back.  */				\
+    CDISABLE;								\
+    mov r0, r7;		/* retrieve return value.  */			\
+    RESTORE_LR_##args;							\
+    UNDOARGS_##args;							\
+    cmn r0, $4096;
+
+/* DOARGS pushes four bytes on the stack for five arguments, and nothing
+   otherwise.  In order to preserve doubleword alignment, sometimes we must
+   save an extra register.  */
+
+# define RESTART_UNWIND .fnend; .fnstart; .save {r7, lr}
+
+# define DOCARGS_0	stmfd sp!, {r7, lr}; .save {r7, lr}
+# define UNDOCARGS_0
+# define RESTORE_LR_0	ldmfd sp!, {r7, lr};
+
+# define DOCARGS_1	stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8
+# define UNDOCARGS_1	ldr r0, [sp], #8; RESTART_UNWIND
+# define RESTORE_LR_1	RESTORE_LR_0
+
+# define DOCARGS_2	stmfd sp!, {r0, r1, r7, lr}; .save {r7, lr}; .pad #8
+# define UNDOCARGS_2	ldmfd sp!, {r0, r1}; RESTART_UNWIND
+# define RESTORE_LR_2	RESTORE_LR_0
+
+# define DOCARGS_3	stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16
+# define UNDOCARGS_3	ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND
+# define RESTORE_LR_3	RESTORE_LR_0
+
+# define DOCARGS_4	stmfd sp!, {r0, r1, r2, r3, r7, lr}; .save {r7, lr}; .pad #16
+# define UNDOCARGS_4	ldmfd sp!, {r0, r1, r2, r3}; RESTART_UNWIND
+# define RESTORE_LR_4	RESTORE_LR_0
+
+# define DOCARGS_5	.save {r4}; stmfd sp!, {r0, r1, r2, r3, r4, r7, lr}; .save {r7, lr}; .pad #20
+# define UNDOCARGS_5	ldmfd sp!, {r0, r1, r2, r3}; .fnend; .fnstart; .save {r4}; .save {r7, lr}; .pad #4
+# define RESTORE_LR_5	ldmfd sp!, {r4, r7, lr}
+
+# 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
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind-forcedunwind.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind-forcedunwind.c	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,113 @@
+/* Copyright (C) 2003, 2005 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>
+
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (_Unwind_State, 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 *);
+
+void
+pthread_cancel_init (void)
+{
+  void *resume, *personality, *forcedunwind, *getcfa;
+  void *handle;
+
+  if (__builtin_expect (libgcc_s_getcfa != NULL, 1))
+    return;
+
+  handle = __libc_dlopen ("libgcc_s.so.1");
+
+  if (handle == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
+      || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
+	 == NULL
+      || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
+#ifdef ARCH_CANCEL_INIT
+      || ARCH_CANCEL_INIT (handle)
+#endif
+      )
+    __libc_fatal ("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_getcfa = getcfa;
+}
+
+/* It's vitally important that _Unwind_Resume not have a stack frame; the
+   ARM unwinder relies on register state at entrance.  So we write this in
+   assembly.  */
+
+asm (
+"	.globl	_Unwind_Resume\n"
+"	.type	_Unwind_Resume, %function\n"
+"_Unwind_Resume:\n"
+"	stmfd	sp!, {r4, r5, r6, lr}\n"
+"	ldr	r4, 1f\n"
+"	ldr	r5, 2f\n"
+"3:	add	r4, pc, r4\n"
+"	ldr	r3, [r4, r5]\n"
+"	mov	r6, r0\n"
+"	cmp	r3, #0\n"
+"	beq	4f\n"
+"5:	mov	r0, r6\n"
+"	ldmfd	sp!, {r4, r5, r6, lr}\n"
+"	bx	r3\n"
+"4:	bl	pthread_cancel_init\n"
+"	ldr	r3, [r4, r5]\n"
+"	b	5b\n"
+"1:	.word	_GLOBAL_OFFSET_TABLE_ - 3b - 8\n"
+"2:	.word	libgcc_s_resume(GOTOFF)\n"
+"	.size	_Unwind_Resume, .-_Unwind_Resume\n"
+);
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (_Unwind_State state,
+		      struct _Unwind_Exception *ue_header,
+		      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    pthread_cancel_init ();
+  return libgcc_s_personality (state, 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);
+}
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind-resume.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind-resume.c	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,82 @@
+/* Copyright (C) 2003, 2005 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>
+
+static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
+static _Unwind_Reason_Code (*libgcc_s_personality)
+  (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *);
+
+static void init (void) __attribute_used__;
+
+static void
+init (void)
+{
+  void *resume, *personality;
+  void *handle;
+
+  handle = __libc_dlopen ("libgcc_s.so.1");
+
+  if (handle == NULL
+      || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
+      || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL)
+    __libc_fatal ("libgcc_s.so.1 must be installed for pthread_cancel to work\n");
+
+  libgcc_s_resume = resume;
+  libgcc_s_personality = personality;
+}
+
+/* It's vitally important that _Unwind_Resume not have a stack frame; the
+   ARM unwinder relies on register state at entrance.  So we write this in
+   assembly.  */
+
+asm (
+"	.globl	_Unwind_Resume\n"
+"	.type	_Unwind_Resume, %function\n"
+"_Unwind_Resume:\n"
+"	stmfd	sp!, {r4, r5, r6, lr}\n"
+"	ldr	r4, 1f\n"
+"	ldr	r5, 2f\n"
+"3:	add	r4, pc, r4\n"
+"	ldr	r3, [r4, r5]\n"
+"	mov	r6, r0\n"
+"	cmp	r3, #0\n"
+"	beq	4f\n"
+"5:	mov	r0, r6\n"
+"	ldmfd	sp!, {r4, r5, r6, lr}\n"
+"	bx	r3\n"
+"4:	bl	init\n"
+"	ldr	r3, [r4, r5]\n"
+"	b	5b\n"
+"1:	.word	_GLOBAL_OFFSET_TABLE_ - 3b - 8\n"
+"2:	.word	libgcc_s_resume(GOTOFF)\n"
+"	.size	_Unwind_Resume, .-_Unwind_Resume\n"
+);
+
+_Unwind_Reason_Code
+__gcc_personality_v0 (_Unwind_State state,
+		      struct _Unwind_Exception *ue_header,
+		      struct _Unwind_Context *context)
+{
+  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+    init ();
+  return libgcc_s_personality (state, ue_header, context);
+}
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/nptl/unwind.h	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,274 @@
+/* Header file for the ARM EABI unwinder
+   Copyright (C) 2003, 2004, 2005  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))
+
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
+#endif /* defined UNWIND_ARM_H */
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S	2005-11-16 11:41:14.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/sigrestorer.S	2005-11-16 11:54:38.000000000 -0500
@@ -20,16 +20,35 @@
 
 /* If no SA_RESTORER function was specified by the application we use
    one of these.  This avoids the need for the kernel to synthesise a return
-   instruction on the stack, which would involve expensive cache flushes. */
+   instruction on the stack, which would involve expensive cache flushes.
 
+   Nowadays (2.6 series, and somewhat earlier) the kernel uses a high page
+   for signal trampolines, so the cache flushes are not an issue.  But since
+   we do not have a vDSO, continue to use these so that we can provide
+   unwind information.
+
+   Start the unwind tables at least one instruction before the signal
+   trampoline, because the unwinder will assume we are returning after
+   a call site.  */
+
+	.fnstart
+	.save {r0-r15}
+	.pad #12
+	nop
 ENTRY(__default_sa_restorer)
 	mov	r7, $SYS_ify(sigreturn)
 	swi	0x0
+	.fnend
 
 #ifdef __NR_rt_sigreturn
 
+	.fnstart
+	.save {r0-r15}
+	.pad #168
+	nop
 ENTRY(__default_rt_sa_restorer)
 	mov	r7, $SYS_ify(rt_sigreturn)
 	swi	0x0
+	.fnend
 
 #endif
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/socket.S
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/eabi/socket.S	2005-11-16 11:19:16.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/socket.S	2005-11-16 11:50:51.000000000 -0500
@@ -33,19 +33,19 @@
    The .S files for the other calls just #define socket and #include this.  */
 
 #ifndef __socket
-#ifndef NO_WEAK_ALIAS
-#define __socket P(__,socket)
-#else
-#define __socket socket
-#endif
+# ifndef NO_WEAK_ALIAS
+#  define __socket P(__,socket)
+# else
+#  define __socket socket
+# endif
 #endif
 
-#define PUSHARGS_1	str a1, [sp, $-8]!
-#define PUSHARGS_2	stmfd sp!, {a1, a2}
-#define PUSHARGS_3	stmfd sp!, {a1, a2, a3, a4}	/* a4 pushed for padding */
-#define PUSHARGS_4	stmfd sp!, {a1, a2, a3, a4}
-#define PUSHARGS_5	stmfd sp!, {a1, a2, a3, a4}	/* Caller has already pushed arg 5 */
-#define PUSHARGS_6	stmfd sp!, {a1, a2, a3, a4}
+#define PUSHARGS_1	str a1, [sp, $-8]!; .pad #8
+#define PUSHARGS_2	stmfd sp!, {a1, a2}; .pad #8
+#define PUSHARGS_3	stmfd sp!, {a1, a2, a3, a4}; .pad #16	/* a4 pushed for padding */
+#define PUSHARGS_4	stmfd sp!, {a1, a2, a3, a4}; .pad #16
+#define PUSHARGS_5	stmfd sp!, {a1, a2, a3, a4}; .pad #16	/* Caller has already pushed arg 5 */
+#define PUSHARGS_6	stmfd sp!, {a1, a2, a3, a4}; .pad #16
 
 #define POPARGS_1	add sp, sp, #8
 #define POPARGS_2	add sp, sp, #8
@@ -64,6 +64,8 @@
 
 .globl __socket
 ENTRY (__socket)
+	.fnstart
+
 	/* This code previously moved sp into ip and stored the args using
 	   stmdb ip!, {a1-a4}.  It did not modify sp, so the stack never had
 	   to be restored after the syscall completed.  It saved an
@@ -98,11 +100,12 @@ ENTRY (__socket)
 #if defined NEED_CANCELLATION && defined CENABLE
 1:
 	stmfd sp!, {r7, lr}
+	.save {r7, lr}
 	CENABLE
 	mov ip, r0
 
 	mov r0, #P(SOCKOP_,socket)
-	add r1, sp, #4
+	add r1, sp, #8
 	mov r7, #SYS_ify(socketcall)
 	swi 0x0
 
@@ -120,6 +123,7 @@ ENTRY (__socket)
 	b PLTJMP(SYSCALL_ERROR)
 #endif
 
+	.fnend
 PSEUDO_END (__socket)
 
 #ifndef NO_WEAK_ALIAS
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h	2005-11-16 11:19:16.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/eabi/sysdep.h	2005-11-16 11:50:51.000000000 -0500
@@ -48,6 +48,11 @@
 		     : "memory");				\
        _a1; })
 
+/* For EABI, non-constant syscalls are actually pretty easy...  */
+#undef INTERNAL_SYSCALL_NCS
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)          \
+  INTERNAL_SYSCALL_RAW (number, err, nr, args)
+
 /* We must save and restore r7 (call-saved) for the syscall number.
    We never make function calls from inside here (only potentially
    signal handlers), so we do not bother with doubleword alignment.
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/Versions
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/Versions	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,6 @@
+libc {
+  GLIBC_PRIVATE {
+    # A copy of sigaction lives in NPTL, and needs these.
+    __default_sa_restorer; __default_rt_sa_restorer;
+  }
+}
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/atomic.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/atomic.h	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,95 @@
+/* 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);
+
+#define atomic_exchange_acq(mem, newvalue)				      \
+  ({ __typeof (*mem) result;						      \
+     if (sizeof (*mem) == 1)						      \
+       __asm__ __volatile__ ("swpb %0, %1, [%2]"			      \
+			     : "=&r,&r" (result)			      \
+			     : "r,0" (newvalue), "r,r" (mem) : "memory");     \
+     else if (sizeof (*mem) == 4)					      \
+       __asm__ __volatile__ ("swp %0, %1, [%2]"				      \
+			     : "=&r,&r" (result)			      \
+			     : "r,0" (newvalue), "r,r" (mem) : "memory");     \
+     else								      \
+       {								      \
+	 result = 0;							      \
+	 abort ();							      \
+       }								      \
+     result; })
+
+/* 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.  */
+
+#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%1,[%3]\n\t"					      \
+	      "cmp\t%1, %4\n\t"						      \
+	      "bne\t1f\n\t"						      \
+	      "mov\t%0, %4\n\t"						      \
+	      "mov\t%1, #0xffff0fff\n\t"				      \
+	      "mov\tlr, pc\n\t"						      \
+	      "add\tpc, %1, #(0xffff0fc0 - 0xffff0fff)\n\t"		      \
+	      "bcc\t0b\n\t"						      \
+	      "mov\t%1, %4\n\t"						      \
+	      "1:"							      \
+	      : "=&r" (a_oldval), "=&r" (a_tmp)				      \
+	      : "r" (a_newval), "r" (a_ptr), "r" (a_oldval2)		      \
+	      : "ip", "lr", "cc", "memory");				      \
+     a_tmp; })
+
+#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+  ({ __arm_link_error (); oldval; })
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/pthreadtypes.h	2005-11-16 13:52:56.000000000 -0500
@@ -0,0 +1,157 @@
+/* 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.  */
+
+#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;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is not exposed on purpose.  */
+typedef union
+{
+  struct
+  {
+    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;
+    int __spins;
+  } __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;
+    unsigned long long int __total_seq;
+    unsigned long long int __wakeup_seq;
+    unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  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 int __flags;
+    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 */
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/semaphore.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/bits/semaphore.h	2005-11-16 13:53:02.000000000 -0500
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002, 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.  */
+
+#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)
+
+/* Maximum value the semaphore can have.  */
+#define SEM_VALUE_MAX   ((int) ((~0u) >> 1))
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/clone.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/clone.S	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,3 @@
+#define RESET_PID
+#include <tcb-offsets.h>
+#include "../clone.S"
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/createthread.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/createthread.c	2005-11-16 13:53:31.000000000 -0500
@@ -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 <nptl/sysdeps/pthread/createthread.c>
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/fork.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/fork.c	2005-11-16 13:53:42.000000000 -0500
@@ -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 <nptl/sysdeps/unix/sysv/linux/fork.c>
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.c	2005-11-16 13:54:20.000000000 -0500
@@ -0,0 +1,118 @@
+/* low level locking for pthread library.  Generic futex-using version.
+   Copyright (C) 2003, 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 <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime)
+{
+  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;
+
+      lll_futex_timed_wait (futex, 2, &rt);
+    }
+  while (atomic_exchange_acq (futex, 2) != 0);
+
+  return 0;
+}
+
+
+/* These don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+int
+lll_unlock_wake_cb (int *futex)
+{
+  int val = atomic_exchange_rel (futex, 0);
+
+  if (__builtin_expect (val > 1, 0))
+    lll_futex_wake (futex, 1);
+
+  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.  */
+      if (lll_futex_timed_wait (tidp, tid, &rt) == -ETIMEDOUT)
+	return ETIMEDOUT;
+    }
+
+  return 0;
+}
+
+#endif
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.h	2005-11-16 11:50:51.000000000 -0500
@@ -0,0 +1,268 @@
+/* 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 Libr	\ary; 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>
+
+#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)
+
+/* Initializer for compatibility lock.	*/
+#define LLL_MUTEX_LOCK_INITIALIZER (0)
+
+#define lll_futex_wait(futexp, val) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \
+			      (futexp), FUTEX_WAIT, (val), 0);		      \
+    __ret;								      \
+  })
+
+#define lll_futex_timed_wait(futexp, val, timespec) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \
+			      (futexp), FUTEX_WAIT, (val), (timespec));	      \
+    __ret;								      \
+  })
+
+#define lll_futex_wake(futexp, nr) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4,				      \
+			      (futexp), FUTEX_WAKE, (nr), 0);		      \
+    __ret;								      \
+  })
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \
+			      (futexp), FUTEX_CMP_REQUEUE, (nr_wake),	      \
+			      (nr_move), (mutex), (val));		      \
+    __ret;								      \
+  })
+
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) \
+  ({									      \
+    INTERNAL_SYSCALL_DECL (__err);					      \
+    long int __ret;							      \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6,				      \
+			      (futexp), FUTEX_WAKE_OP, (nr_wake),	      \
+			      (nr_wake2), (futexp2),			      \
+			      FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);		      \
+    __ret;								      \
+  })
+
+
+static inline int __attribute__((always_inline))
+__lll_mutex_trylock (int *futex)
+{
+  int flag = 1, old;
+  asm volatile (
+    "\tswp	%[old], %[flag], [%[futex]]	@ try to take the lock\n"
+    "\tcmp	%[old], #1			@ check old lock value\n"
+    "\tmovlo	%[flag], #0			@ if we got it, return 0\n"
+    "\tswphi	%[flag], %[old], [%[futex]]	@ if it was contested,\n"
+    "						@ restore the contested flag,\n"
+    "						@ and check whether that won."
+    : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old)
+    : : "memory" );
+
+  return flag;
+}
+#define lll_mutex_trylock(lock)	__lll_mutex_trylock (&(lock))
+
+
+static inline int __attribute__((always_inline))
+__lll_mutex_cond_trylock (int *futex)
+{
+  int flag = 2, old;
+  asm volatile (
+    "\tswp	%[old], %[flag], [%[futex]]	@ try to take the lock\n"
+    "\tcmp	%[old], #1			@ check old lock value\n"
+    "\tmovlo	%[flag], #0			@ if we got it, return 0\n"
+    "\tswphi	%[flag], %[old], [%[futex]]	@ if it was contested,\n"
+    "						@ restore the contested flag,\n"
+    "						@ and check whether that won."
+    : [futex] "+&r" (futex), [flag] "+&r" (flag), [old] "=&r" (old)
+    : : "memory" );
+
+  return flag;
+}
+#define lll_mutex_cond_trylock(lock)	__lll_mutex_cond_trylock (&(lock))
+
+
+extern void __lll_mutex_lock_outlined (int *futex) attribute_hidden;
+
+static inline void __attribute__((always_inline))
+__lll_mutex_lock (int *futex)
+{
+  int val = atomic_exchange_acq (futex, 1);
+
+  if (__builtin_expect (val != 0, 0))
+    {
+      while (atomic_exchange_acq (futex, 2) != 0)
+	lll_futex_wait (futex, 2);
+    }
+}
+#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex))
+
+
+static inline void __attribute__ ((always_inline))
+__lll_mutex_cond_lock (int *futex)
+{
+  int val = atomic_exchange_acq (futex, 2);
+
+  if (__builtin_expect (val != 0, 0))
+    {
+      while (atomic_exchange_acq (futex, 2) != 0)
+	lll_futex_wait (futex, 2);
+    }
+}
+#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex))
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *)
+	attribute_hidden;
+
+extern int __lll_mutex_timedlock_outlined (int *futex,
+					   const struct timespec *)
+	attribute_hidden;
+
+static inline int __attribute__ ((always_inline))
+__lll_mutex_timedlock (int *futex, const struct timespec *abstime)
+{
+  int result = 0;
+  int val = atomic_exchange_acq (futex, 1);
+
+  if (__builtin_expect (val != 0, 0))
+    result = __lll_timedlock_wait (futex, abstime);
+  return result;
+}
+#define lll_mutex_timedlock(futex, abstime) \
+  __lll_mutex_timedlock (&(futex), abstime)
+
+
+static inline void __attribute__ ((always_inline))
+__lll_mutex_unlock (int *futex)
+{
+  int val = atomic_exchange_rel (futex, 0);
+  if (__builtin_expect (val > 1, 0))
+    lll_futex_wake (futex, 1);
+}
+#define lll_mutex_unlock(futex) __lll_mutex_unlock(&(futex))
+
+
+static inline void __attribute__ ((always_inline))
+__lll_mutex_unlock_force (int *futex)
+{
+  (void) atomic_exchange_rel (futex, 0);
+  lll_futex_wake (futex, 1);
+}
+#define lll_mutex_unlock_force(futex) __lll_mutex_unlock_force(&(futex))
+
+
+#define lll_mutex_islocked(futex) \
+  (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+   mutex implementation. */
+
+/* Type for lock object.  */
+typedef int lll_lock_t;
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER		(0)
+#define LLL_LOCK_INITIALIZER_LOCKED	(1)
+
+extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
+
+/* The states of a lock are:
+    0  -  untaken
+    1  -  taken by one user
+   >1  -  taken by more users */
+
+#define lll_trylock(lock)	lll_mutex_trylock (lock)
+#define lll_lock(lock)		lll_mutex_lock (lock)
+#define lll_unlock(lock)	lll_mutex_unlock (lock)
+#define lll_islocked(lock)	lll_mutex_islocked (lock)
+
+/* 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);	\
+  } 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;						\
+  })
+
+
+/* Conditional variable handling.  */
+
+extern void __lll_cond_wait (pthread_cond_t *cond)
+     attribute_hidden;
+extern int __lll_cond_timedwait (pthread_cond_t *cond,
+				 const struct timespec *abstime)
+     attribute_hidden;
+extern void __lll_cond_wake (pthread_cond_t *cond)
+     attribute_hidden;
+extern void __lll_cond_broadcast (pthread_cond_t *cond)
+     attribute_hidden;
+
+#define lll_cond_wait(cond) \
+  __lll_cond_wait (cond)
+#define lll_cond_timedwait(cond, abstime) \
+  __lll_cond_timedwait (cond, abstime)
+#define lll_cond_wake(cond) \
+  __lll_cond_wake (cond)
+#define lll_cond_broadcast(cond) \
+  __lll_cond_broadcast (cond)
+
+#endif	/* lowlevellock.h */
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/pt-vfork.S	2005-11-16 11:50:51.000000000 -0500
@@ -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 "../vfork.S"
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/pthread_once.c	2005-11-16 13:54:52.000000000 -0500
@@ -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);
+}
+
+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);
+    }
+
+  /* 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);
+
+  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
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/nptl/vfork.S	2005-11-16 11:50:51.000000000 -0500
@@ -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 "../vfork.S"
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/sigaction.c
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/sigaction.c	2005-11-16 11:12:20.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/sigaction.c	2005-11-16 13:57:17.000000000 -0500
@@ -1,4 +1,5 @@
-/* Copyright (C) 1997,1998,1999,2000,2002,2003 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 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
@@ -78,14 +79,7 @@ __libc_sigaction (sig, act, oact)
 	  memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
 	  kact.sa_flags = act->sa_flags;
 # ifdef HAVE_SA_RESTORER
-	  /* If the user specified SA_ONSTACK this means she is trying to
-	     use the old-style stack switching.  Unfortunately this
-	     requires the sa_restorer field so we cannot install our own
-	     handler.  (In fact the user is likely to be out of luck anyway
-	     since the kernel currently only supports stack switching via
-	     the X/Open sigaltstack interface, but we allow for the
-	     possibility that this might change in the future.)  */
-	  if (kact.sa_flags & (SA_RESTORER | SA_ONSTACK))
+	  if (kact.sa_flags & SA_RESTORER)
 	    kact.sa_restorer = act->sa_restorer;
 	  else
 	    {
@@ -131,8 +125,7 @@ __libc_sigaction (sig, act, oact)
       k_sigact.sa_mask = act->sa_mask.__val[0];
       k_sigact.sa_flags = act->sa_flags;
 # ifdef HAVE_SA_RESTORER
-      /* See the comments above for why we test SA_ONSTACK.  */
-      if (k_sigact.sa_flags & (SA_RESTORER | SA_ONSTACK))
+      if (k_sigact.sa_flags & SA_RESTORER)
 	k_sigact.sa_restorer = act->sa_restorer;
       else
 	{
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/socket.S
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/socket.S	2005-11-16 11:19:16.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/socket.S	2005-11-16 11:50:51.000000000 -0500
@@ -34,11 +34,11 @@
    The .S files for the other calls just #define socket and #include this.  */
 
 #ifndef __socket
-#ifndef NO_WEAK_ALIAS
-#define __socket P(__,socket)
-#else
-#define __socket socket
-#endif
+# ifndef NO_WEAK_ALIAS
+#  define __socket P(__,socket)
+# else
+#  define __socket socket
+# endif
 #endif
 
 #define PUSHARGS_1	str a1, [sp, $-4]!
@@ -53,7 +53,7 @@
 #define POPARGS_3	add sp, sp, #12
 #define POPARGS_4	add sp, sp, #16
 #define POPARGS_5	add sp, sp, #16
-#define POPARGS_6	add sp, sp, #16 
+#define POPARGS_6	add sp, sp, #16
 
 #ifndef NARGS
 #define NARGS 3			/* If we were called with no wrapper, this is really socket() */
@@ -66,8 +66,8 @@
 .globl __socket
 ENTRY (__socket)
 	/* This code previously moved sp into ip and stored the args using
-	   stmdb ip!, {a1-a4}.  It did not modify sp, so the stack never had 
-	   to be restored after the syscall completed.  It saved an 
+	   stmdb ip!, {a1-a4}.  It did not modify sp, so the stack never had
+	   to be restored after the syscall completed.  It saved an
 	   instruction and meant no stack cleanup work was required.
 
 	   This will not work in the case of a socket call being interrupted
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/sysdep.h
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/sysdep.h	2005-11-16 11:12:20.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/sysdep.h	2005-11-16 11:50:51.000000000 -0500
@@ -24,6 +24,9 @@
 /* There is some commonality.  */
 #include <ports/sysdeps/unix/arm/sysdep.h>
 
+/* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO.  */
+#include <dl-sysdep.h>
+
 /* For Linux we can use the system call table in the header file
 	/usr/include/asm/unistd.h
    of the kernel.  But these symbols do not follow the SYS_* syntax
@@ -43,7 +46,7 @@
    might return a large offset.  Therefore we must not anymore test
    for < 0, but test for a real error by making sure the value in R0
    is a real error number.  Linus said he will make sure the no syscall
-   returns a value in -1 .. -4095 as a valid result so we can savely
+   returns a value in -1 .. -4095 as a valid result so we can safely
    test with -4095.  */
 
 #undef	PSEUDO
@@ -96,7 +99,17 @@
 
 #if NOT_IN_libc
 # define SYSCALL_ERROR __local_syscall_error
-# define SYSCALL_ERROR_HANDLER					\
+# if RTLD_PRIVATE_ERRNO
+#  define SYSCALL_ERROR_HANDLER					\
+__local_syscall_error:						\
+       ldr     r1, 1f;						\
+       rsb     r0, r0, #0;					\
+0:     str     r0, [pc, r1];					\
+       mvn     r0, #0;						\
+       DO_RET(lr);						\
+1:     .word C_SYMBOL_NAME(rtld_errno) - 0b - 8;
+# else
+#  define SYSCALL_ERROR_HANDLER					\
 __local_syscall_error:						\
 	str	lr, [sp, #-4]!;					\
 	str	r0, [sp, #-4]!;					\
@@ -106,6 +119,7 @@ __local_syscall_error:						\
 	str	r1, [r0];					\
 	mvn	r0, #0;						\
 	ldr	pc, [sp], #4;
+# endif
 #else
 # define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */
 # define SYSCALL_ERROR __syscall_error
@@ -239,6 +253,24 @@ __local_syscall_error:						\
   LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6)
 #define ASM_ARGS_7	ASM_ARGS_6, "r" (_v3)
 
+/* We can't implement non-constant syscalls directly since the syscall
+   number is normally encoded in the instruction.  So use SYS_syscall.  */
+#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)		\
+	INTERNAL_SYSCALL_NCS_##nr (number, err, args)
+
+#define INTERNAL_SYSCALL_NCS_0(number, err, args...)		\
+	INTERNAL_SYSCALL (syscall, err, 1, number, args)
+#define INTERNAL_SYSCALL_NCS_1(number, err, args...)		\
+	INTERNAL_SYSCALL (syscall, err, 2, number, args)
+#define INTERNAL_SYSCALL_NCS_2(number, err, args...)		\
+	INTERNAL_SYSCALL (syscall, err, 3, number, args)
+#define INTERNAL_SYSCALL_NCS_3(number, err, args...)		\
+	INTERNAL_SYSCALL (syscall, err, 4, number, args)
+#define INTERNAL_SYSCALL_NCS_4(number, err, args...)		\
+	INTERNAL_SYSCALL (syscall, err, 5, number, args)
+#define INTERNAL_SYSCALL_NCS_5(number, err, args...)		\
+	INTERNAL_SYSCALL (syscall, err, 6, number, args)
+
 #endif	/* __ASSEMBLER__ */
 
 #endif /* linux/arm/sysdep.h */
Index: glibc/ports/sysdeps/unix/sysv/linux/arm/vfork.S
===================================================================
--- glibc.orig/ports/sysdeps/unix/sysv/linux/arm/vfork.S	2005-11-16 11:19:16.000000000 -0500
+++ glibc/ports/sysdeps/unix/sysv/linux/arm/vfork.S	2005-11-16 11:50:51.000000000 -0500
@@ -30,16 +30,22 @@
 ENTRY (__vfork)
 
 #ifdef __NR_vfork
+#ifdef SAVE_PID
+	SAVE_PID
+#endif
 	DO_CALL (vfork, 0)
+#ifdef RESTORE_PID
+	RESTORE_PID
+#endif
 	cmn	a1, #4096
 	RETINSTR(cc, lr)
 
 # ifdef __ASSUME_VFORK_SYSCALL
-	b	PLTJMP(C_SYMBOL_NAME(__syscall_error))
+	b	PLTJMP(SYSCALL_ERROR)
 # else
 	/* Check if vfork syscall is known at all.  */
-	cmn	a2, #ENOSYS
-	bne	PLTJMP(C_SYMBOL_NAME(__syscall_error))
+	cmn	a1, #ENOSYS
+	bne	PLTJMP(SYSCALL_ERROR)
 # endif
 #endif
 
@@ -48,7 +54,7 @@ ENTRY (__vfork)
 	DO_CALL (fork, 0)
 	cmn	a1, #4096
 	RETINSTR(cc, lr)
-    	b	PLTJMP(C_SYMBOL_NAME(__syscall_error))
+    	b	PLTJMP(SYSCALL_ERROR)
 #elif !defined __NR_vfork
 # error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined"
 #endif


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]