mirror of git://sourceware.org/git/glibc.git
* 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.
This commit is contained in:
parent
de96d1483f
commit
02a9f771e3
|
@ -1,3 +1,61 @@
|
||||||
|
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.
|
||||||
|
|
||||||
2005-11-16 Daniel Jacobowitz <dan@codesourcery.com>
|
2005-11-16 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* sysdeps/arm/dl-machine.h (CLEAR_CACHE): Use INTERNAL_SYSCALL_ARM.
|
* sysdeps/arm/dl-machine.h (CLEAR_CACHE): Use INTERNAL_SYSCALL_ARM.
|
||||||
|
|
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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. */
|
/* 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."
|
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,3 +37,5 @@ typedef int __jmp_buf[10];
|
||||||
containing a local variable at ADDRESS. */
|
containing a local variable at ADDRESS. */
|
||||||
#define _JMPBUF_UNWINDS(jmpbuf, address) \
|
#define _JMPBUF_UNWINDS(jmpbuf, address) \
|
||||||
((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
|
((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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. */
|
/* 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."
|
# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,3 +37,5 @@ typedef int __jmp_buf[22];
|
||||||
containing a local variable at ADDRESS. */
|
containing a local variable at ADDRESS. */
|
||||||
#define _JMPBUF_UNWINDS(jmpbuf, address) \
|
#define _JMPBUF_UNWINDS(jmpbuf, address) \
|
||||||
((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
|
((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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))
|
|
@ -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)
|
|
@ -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 */
|
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
@ -20,8 +22,11 @@
|
||||||
#define _ERRNO_H
|
#define _ERRNO_H
|
||||||
#include <bits/errno.h>
|
#include <bits/errno.h>
|
||||||
|
|
||||||
.globl C_SYMBOL_NAME(errno)
|
#ifdef IS_IN_rtld
|
||||||
.globl syscall_error
|
# include <dl-sysdep.h> /* Defines RTLD_PRIVATE_ERRNO. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <tls.h>
|
||||||
|
|
||||||
#undef syscall_error
|
#undef syscall_error
|
||||||
#ifdef NO_UNDERSCORES
|
#ifdef NO_UNDERSCORES
|
||||||
|
@ -37,7 +42,29 @@ syscall_error:
|
||||||
moveq r0, $EAGAIN /* Yes; translate it to EAGAIN. */
|
moveq r0, $EAGAIN /* Yes; translate it to EAGAIN. */
|
||||||
#endif
|
#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 lr, [sp, #-4]!
|
||||||
str r0, [sp, #-4]!
|
str r0, [sp, #-4]!
|
||||||
bl PLTJMP(C_SYMBOL_NAME(__errno_location))
|
bl PLTJMP(C_SYMBOL_NAME(__errno_location))
|
||||||
|
|
|
@ -25,7 +25,11 @@
|
||||||
#define _ERRNO_H 1
|
#define _ERRNO_H 1
|
||||||
#include <bits/errno.h>
|
#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
|
.text
|
||||||
ENTRY(__clone)
|
ENTRY(__clone)
|
||||||
|
@ -42,16 +46,58 @@ ENTRY(__clone)
|
||||||
@ do the system call
|
@ do the system call
|
||||||
@ get flags
|
@ get flags
|
||||||
mov r0, r2
|
mov r0, r2
|
||||||
|
#ifdef RESET_PID
|
||||||
|
mov ip, r2
|
||||||
|
#endif
|
||||||
@ new sp is already in r1
|
@ new sp is already in r1
|
||||||
DO_CALL (clone, 0)
|
#ifdef __ARM_EABI__
|
||||||
movs a1, a1
|
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))
|
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
|
@ pick the function arg and call address off the stack and execute
|
||||||
ldr r0, [sp, #4]
|
ldr r0, [sp, #4]
|
||||||
mov lr, pc
|
mov lr, pc
|
||||||
ldr pc, [sp]
|
ldr pc, [sp], #8
|
||||||
|
|
||||||
@ and we are done, passing the return value through r0
|
@ and we are done, passing the return value through r0
|
||||||
b PLTJMP(_exit)
|
b PLTJMP(_exit)
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
# This file is generated from configure.in by Autoconf. DO NOT EDIT!
|
||||||
|
|
||||||
|
libc_cv_gcc_exceptions=yes
|
||||||
|
exceptions=-fexceptions
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
#include <aeabi_unwind_cpp_pr1.c>
|
|
@ -0,0 +1 @@
|
||||||
|
#include <aeabi_unwind_cpp_pr1.c>
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 */
|
|
@ -20,16 +20,35 @@
|
||||||
|
|
||||||
/* If no SA_RESTORER function was specified by the application we use
|
/* 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
|
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)
|
ENTRY(__default_sa_restorer)
|
||||||
mov r7, $SYS_ify(sigreturn)
|
mov r7, $SYS_ify(sigreturn)
|
||||||
swi 0x0
|
swi 0x0
|
||||||
|
.fnend
|
||||||
|
|
||||||
#ifdef __NR_rt_sigreturn
|
#ifdef __NR_rt_sigreturn
|
||||||
|
|
||||||
|
.fnstart
|
||||||
|
.save {r0-r15}
|
||||||
|
.pad #168
|
||||||
|
nop
|
||||||
ENTRY(__default_rt_sa_restorer)
|
ENTRY(__default_rt_sa_restorer)
|
||||||
mov r7, $SYS_ify(rt_sigreturn)
|
mov r7, $SYS_ify(rt_sigreturn)
|
||||||
swi 0x0
|
swi 0x0
|
||||||
|
.fnend
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,19 +33,19 @@
|
||||||
The .S files for the other calls just #define socket and #include this. */
|
The .S files for the other calls just #define socket and #include this. */
|
||||||
|
|
||||||
#ifndef __socket
|
#ifndef __socket
|
||||||
#ifndef NO_WEAK_ALIAS
|
# ifndef NO_WEAK_ALIAS
|
||||||
#define __socket P(__,socket)
|
# define __socket P(__,socket)
|
||||||
#else
|
# else
|
||||||
#define __socket socket
|
# define __socket socket
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PUSHARGS_1 str a1, [sp, $-8]!
|
#define PUSHARGS_1 str a1, [sp, $-8]!; .pad #8
|
||||||
#define PUSHARGS_2 stmfd sp!, {a1, a2}
|
#define PUSHARGS_2 stmfd sp!, {a1, a2}; .pad #8
|
||||||
#define PUSHARGS_3 stmfd sp!, {a1, a2, a3, a4} /* a4 pushed for padding */
|
#define PUSHARGS_3 stmfd sp!, {a1, a2, a3, a4}; .pad #16 /* a4 pushed for padding */
|
||||||
#define PUSHARGS_4 stmfd sp!, {a1, a2, a3, a4}
|
#define PUSHARGS_4 stmfd sp!, {a1, a2, a3, a4}; .pad #16
|
||||||
#define PUSHARGS_5 stmfd sp!, {a1, a2, a3, a4} /* Caller has already pushed arg 5 */
|
#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}
|
#define PUSHARGS_6 stmfd sp!, {a1, a2, a3, a4}; .pad #16
|
||||||
|
|
||||||
#define POPARGS_1 add sp, sp, #8
|
#define POPARGS_1 add sp, sp, #8
|
||||||
#define POPARGS_2 add sp, sp, #8
|
#define POPARGS_2 add sp, sp, #8
|
||||||
|
@ -64,6 +64,8 @@
|
||||||
|
|
||||||
.globl __socket
|
.globl __socket
|
||||||
ENTRY (__socket)
|
ENTRY (__socket)
|
||||||
|
.fnstart
|
||||||
|
|
||||||
/* This code previously moved sp into ip and stored the args using
|
/* 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
|
stmdb ip!, {a1-a4}. It did not modify sp, so the stack never had
|
||||||
to be restored after the syscall completed. It saved an
|
to be restored after the syscall completed. It saved an
|
||||||
|
@ -98,11 +100,12 @@ ENTRY (__socket)
|
||||||
#if defined NEED_CANCELLATION && defined CENABLE
|
#if defined NEED_CANCELLATION && defined CENABLE
|
||||||
1:
|
1:
|
||||||
stmfd sp!, {r7, lr}
|
stmfd sp!, {r7, lr}
|
||||||
|
.save {r7, lr}
|
||||||
CENABLE
|
CENABLE
|
||||||
mov ip, r0
|
mov ip, r0
|
||||||
|
|
||||||
mov r0, #P(SOCKOP_,socket)
|
mov r0, #P(SOCKOP_,socket)
|
||||||
add r1, sp, #4
|
add r1, sp, #8
|
||||||
mov r7, #SYS_ify(socketcall)
|
mov r7, #SYS_ify(socketcall)
|
||||||
swi 0x0
|
swi 0x0
|
||||||
|
|
||||||
|
@ -120,6 +123,7 @@ ENTRY (__socket)
|
||||||
b PLTJMP(SYSCALL_ERROR)
|
b PLTJMP(SYSCALL_ERROR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
.fnend
|
||||||
PSEUDO_END (__socket)
|
PSEUDO_END (__socket)
|
||||||
|
|
||||||
#ifndef NO_WEAK_ALIAS
|
#ifndef NO_WEAK_ALIAS
|
||||||
|
|
|
@ -48,6 +48,11 @@
|
||||||
: "memory"); \
|
: "memory"); \
|
||||||
_a1; })
|
_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 must save and restore r7 (call-saved) for the syscall number.
|
||||||
We never make function calls from inside here (only potentially
|
We never make function calls from inside here (only potentially
|
||||||
signal handlers), so we do not bother with doubleword alignment.
|
signal handlers), so we do not bother with doubleword alignment.
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
libc {
|
||||||
|
GLIBC_PRIVATE {
|
||||||
|
# A copy of sigaction lives in NPTL, and needs these.
|
||||||
|
__default_sa_restorer; __default_rt_sa_restorer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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; })
|
|
@ -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 */
|
|
@ -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;
|
|
@ -0,0 +1,3 @@
|
||||||
|
#define RESET_PID
|
||||||
|
#include <tcb-offsets.h>
|
||||||
|
#include "../clone.S"
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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 */
|
|
@ -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"
|
|
@ -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
|
|
@ -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"
|
|
@ -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.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
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));
|
memcpy (&kact.sa_mask, &act->sa_mask, sizeof (sigset_t));
|
||||||
kact.sa_flags = act->sa_flags;
|
kact.sa_flags = act->sa_flags;
|
||||||
# ifdef HAVE_SA_RESTORER
|
# ifdef HAVE_SA_RESTORER
|
||||||
/* If the user specified SA_ONSTACK this means she is trying to
|
if (kact.sa_flags & SA_RESTORER)
|
||||||
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))
|
|
||||||
kact.sa_restorer = act->sa_restorer;
|
kact.sa_restorer = act->sa_restorer;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -131,8 +125,7 @@ __libc_sigaction (sig, act, oact)
|
||||||
k_sigact.sa_mask = act->sa_mask.__val[0];
|
k_sigact.sa_mask = act->sa_mask.__val[0];
|
||||||
k_sigact.sa_flags = act->sa_flags;
|
k_sigact.sa_flags = act->sa_flags;
|
||||||
# ifdef HAVE_SA_RESTORER
|
# ifdef HAVE_SA_RESTORER
|
||||||
/* See the comments above for why we test SA_ONSTACK. */
|
if (k_sigact.sa_flags & SA_RESTORER)
|
||||||
if (k_sigact.sa_flags & (SA_RESTORER | SA_ONSTACK))
|
|
||||||
k_sigact.sa_restorer = act->sa_restorer;
|
k_sigact.sa_restorer = act->sa_restorer;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,11 +34,11 @@
|
||||||
The .S files for the other calls just #define socket and #include this. */
|
The .S files for the other calls just #define socket and #include this. */
|
||||||
|
|
||||||
#ifndef __socket
|
#ifndef __socket
|
||||||
#ifndef NO_WEAK_ALIAS
|
# ifndef NO_WEAK_ALIAS
|
||||||
#define __socket P(__,socket)
|
# define __socket P(__,socket)
|
||||||
#else
|
# else
|
||||||
#define __socket socket
|
# define __socket socket
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PUSHARGS_1 str a1, [sp, $-4]!
|
#define PUSHARGS_1 str a1, [sp, $-4]!
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
#define POPARGS_3 add sp, sp, #12
|
#define POPARGS_3 add sp, sp, #12
|
||||||
#define POPARGS_4 add sp, sp, #16
|
#define POPARGS_4 add sp, sp, #16
|
||||||
#define POPARGS_5 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
|
#ifndef NARGS
|
||||||
#define NARGS 3 /* If we were called with no wrapper, this is really socket() */
|
#define NARGS 3 /* If we were called with no wrapper, this is really socket() */
|
||||||
|
@ -66,8 +66,8 @@
|
||||||
.globl __socket
|
.globl __socket
|
||||||
ENTRY (__socket)
|
ENTRY (__socket)
|
||||||
/* This code previously moved sp into ip and stored the args using
|
/* 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
|
stmdb ip!, {a1-a4}. It did not modify sp, so the stack never had
|
||||||
to be restored after the syscall completed. It saved an
|
to be restored after the syscall completed. It saved an
|
||||||
instruction and meant no stack cleanup work was required.
|
instruction and meant no stack cleanup work was required.
|
||||||
|
|
||||||
This will not work in the case of a socket call being interrupted
|
This will not work in the case of a socket call being interrupted
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
/* There is some commonality. */
|
/* There is some commonality. */
|
||||||
#include <ports/sysdeps/unix/arm/sysdep.h>
|
#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
|
/* For Linux we can use the system call table in the header file
|
||||||
/usr/include/asm/unistd.h
|
/usr/include/asm/unistd.h
|
||||||
of the kernel. But these symbols do not follow the SYS_* syntax
|
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
|
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
|
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
|
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. */
|
test with -4095. */
|
||||||
|
|
||||||
#undef PSEUDO
|
#undef PSEUDO
|
||||||
|
@ -96,7 +99,17 @@
|
||||||
|
|
||||||
#if NOT_IN_libc
|
#if NOT_IN_libc
|
||||||
# define SYSCALL_ERROR __local_syscall_error
|
# 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: \
|
__local_syscall_error: \
|
||||||
str lr, [sp, #-4]!; \
|
str lr, [sp, #-4]!; \
|
||||||
str r0, [sp, #-4]!; \
|
str r0, [sp, #-4]!; \
|
||||||
|
@ -106,6 +119,7 @@ __local_syscall_error: \
|
||||||
str r1, [r0]; \
|
str r1, [r0]; \
|
||||||
mvn r0, #0; \
|
mvn r0, #0; \
|
||||||
ldr pc, [sp], #4;
|
ldr pc, [sp], #4;
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
|
# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
|
||||||
# define SYSCALL_ERROR __syscall_error
|
# define SYSCALL_ERROR __syscall_error
|
||||||
|
@ -239,6 +253,24 @@ __local_syscall_error: \
|
||||||
LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6)
|
LOAD_ARGS_6 (a1, a2, a3, a4, a5, a6)
|
||||||
#define ASM_ARGS_7 ASM_ARGS_6, "r" (_v3)
|
#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 /* __ASSEMBLER__ */
|
||||||
|
|
||||||
#endif /* linux/arm/sysdep.h */
|
#endif /* linux/arm/sysdep.h */
|
||||||
|
|
|
@ -30,16 +30,22 @@
|
||||||
ENTRY (__vfork)
|
ENTRY (__vfork)
|
||||||
|
|
||||||
#ifdef __NR_vfork
|
#ifdef __NR_vfork
|
||||||
|
#ifdef SAVE_PID
|
||||||
|
SAVE_PID
|
||||||
|
#endif
|
||||||
DO_CALL (vfork, 0)
|
DO_CALL (vfork, 0)
|
||||||
|
#ifdef RESTORE_PID
|
||||||
|
RESTORE_PID
|
||||||
|
#endif
|
||||||
cmn a1, #4096
|
cmn a1, #4096
|
||||||
RETINSTR(cc, lr)
|
RETINSTR(cc, lr)
|
||||||
|
|
||||||
# ifdef __ASSUME_VFORK_SYSCALL
|
# ifdef __ASSUME_VFORK_SYSCALL
|
||||||
b PLTJMP(C_SYMBOL_NAME(__syscall_error))
|
b PLTJMP(SYSCALL_ERROR)
|
||||||
# else
|
# else
|
||||||
/* Check if vfork syscall is known at all. */
|
/* Check if vfork syscall is known at all. */
|
||||||
cmn a2, #ENOSYS
|
cmn a1, #ENOSYS
|
||||||
bne PLTJMP(C_SYMBOL_NAME(__syscall_error))
|
bne PLTJMP(SYSCALL_ERROR)
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -48,7 +54,7 @@ ENTRY (__vfork)
|
||||||
DO_CALL (fork, 0)
|
DO_CALL (fork, 0)
|
||||||
cmn a1, #4096
|
cmn a1, #4096
|
||||||
RETINSTR(cc, lr)
|
RETINSTR(cc, lr)
|
||||||
b PLTJMP(C_SYMBOL_NAME(__syscall_error))
|
b PLTJMP(SYSCALL_ERROR)
|
||||||
#elif !defined __NR_vfork
|
#elif !defined __NR_vfork
|
||||||
# error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined"
|
# error "__NR_vfork not available and __ASSUME_VFORK_SYSCALL defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue