diff options
27 files changed, 940 insertions, 254 deletions
diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c index ce3991f90..97c426d11 100644 --- a/ldso/ldso/sparc/elfinterp.c +++ b/ldso/ldso/sparc/elfinterp.c @@ -80,7 +80,7 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) got_addr = (char **)instr_addr; /* Get the address of the GOT entry */ - new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); + new_addr = _dl_lookup_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); if (unlikely(!new_addr)) { _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname); _dl_exit(1); @@ -185,8 +185,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, symname = strtab + sym->st_name; if (symtab_index) { - symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, - elf_machine_type_class(reloc_type)); + symbol_addr = (ElfW(Addr))_dl_lookup_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), NULL); /* * We want to allow undefined references to weak symbols - this * might have been intentional. We should not be linking local diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index a4090200d..d9785cd9d 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -88,6 +88,10 @@ ifeq ($(TARGET_ARCH),sh) CSRC := $(filter-out longjmp.c vfork.c,$(CSRC)) endif +ifeq ($(TARGET_ARCH),sparc) +CSRC := $(filter-out vfork.c,$(CSRC)) +endif + # fails for some reason ifneq ($(strip $(ARCH_OBJS)),) CSRC := $(filter-out $(notdir $(ARCH_OBJS:.o=.c)),$(CSRC)) diff --git a/libc/sysdeps/linux/sparc/Makefile.arch b/libc/sysdeps/linux/sparc/Makefile.arch index 4562eaba5..fac37e22c 100644 --- a/libc/sysdeps/linux/sparc/Makefile.arch +++ b/libc/sysdeps/linux/sparc/Makefile.arch @@ -8,7 +8,7 @@ CSRC := brk.c __syscall_error.c qp_ops.c SSRC := \ - __longjmp.S fork.S vfork.S clone.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ + __longjmp.S setjmp.S bsd-setjmp.S bsd-_setjmp.S \ syscall.S urem.S udiv.S umul.S sdiv.S rem.S include $(top_srcdir)libc/sysdeps/linux/Makefile.commonarch diff --git a/libc/sysdeps/linux/sparc/bits/atomic.h b/libc/sysdeps/linux/sparc/bits/atomic.h new file mode 100644 index 000000000..ef553f727 --- /dev/null +++ b/libc/sysdeps/linux/sparc/bits/atomic.h @@ -0,0 +1,327 @@ +/* Atomic operations. sparc32 version. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_ATOMIC_H +#define _BITS_ATOMIC_H 1 + +#include <stdint.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 int16_t atomic16_t; +typedef uint16_t uatomic16_t; +typedef int_fast16_t atomic_fast16_t; +typedef uint_fast16_t uatomic_fast16_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 int64_t atomic64_t; +typedef uint64_t uatomic64_t; +typedef int_fast64_t atomic_fast64_t; +typedef uint_fast64_t uatomic_fast64_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + + +/* We have no compare and swap, just test and set. + The following implementation contends on 64 global locks + per library and assumes no variable will be accessed using atomic.h + macros from two different libraries. */ + +__make_section_unallocated + (".gnu.linkonce.b.__sparc32_atomic_locks, \"aw\", %nobits"); + +volatile unsigned char __sparc32_atomic_locks[64] + __attribute__ ((nocommon, section (".gnu.linkonce.b.__sparc32_atomic_locks" + __sec_comment), + visibility ("hidden"))); + +#define __sparc32_atomic_do_lock(addr) \ + do \ + { \ + unsigned int __old_lock; \ + unsigned int __idx = (((long) addr >> 2) ^ ((long) addr >> 12)) \ + & 63; \ + do \ + __asm __volatile ("ldstub %1, %0" \ + : "=r" (__old_lock), \ + "=m" (__sparc32_atomic_locks[__idx]) \ + : "m" (__sparc32_atomic_locks[__idx]) \ + : "memory"); \ + while (__old_lock); \ + } \ + while (0) + +#define __sparc32_atomic_do_unlock(addr) \ + do \ + { \ + __sparc32_atomic_locks[(((long) addr >> 2) \ + ^ ((long) addr >> 12)) & 63] = 0; \ + __asm __volatile ("" ::: "memory"); \ + } \ + while (0) + +#define __sparc32_atomic_do_lock24(addr) \ + do \ + { \ + unsigned int __old_lock; \ + do \ + __asm __volatile ("ldstub %1, %0" \ + : "=r" (__old_lock), "=m" (*(addr)) \ + : "m" (*(addr)) \ + : "memory"); \ + while (__old_lock); \ + } \ + while (0) + +#define __sparc32_atomic_do_unlock24(addr) \ + do \ + { \ + *(char *) (addr) = 0; \ + __asm __volatile ("" ::: "memory"); \ + } \ + while (0) + + +#ifndef SHARED +# define __v9_compare_and_exchange_val_32_acq(mem, newval, oldval) \ +({ \ + register __typeof (*(mem)) __acev_tmp __asm ("%g6"); \ + register __typeof (mem) __acev_mem __asm ("%g1") = (mem); \ + register __typeof (*(mem)) __acev_oldval __asm ("%g5"); \ + __acev_tmp = (newval); \ + __acev_oldval = (oldval); \ + /* .word 0xcde05005 is cas [%g1], %g5, %g6. Can't use cas here though, \ + because as will then mark the object file as V8+ arch. */ \ + __asm __volatile (".word 0xcde05005" \ + : "+r" (__acev_tmp), "=m" (*__acev_mem) \ + : "r" (__acev_oldval), "m" (*__acev_mem), \ + "r" (__acev_mem) : "memory"); \ + __acev_tmp; }) +#endif + +/* The only basic operation needed is compare and exchange. */ +#define __v7_compare_and_exchange_val_acq(mem, newval, oldval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock (__acev_memp); \ + __acev_ret = *__acev_memp; \ + if (__acev_ret == (oldval)) \ + *__acev_memp = __acev_newval; \ + __sparc32_atomic_do_unlock (__acev_memp); \ + __acev_ret; }) + +#define __v7_compare_and_exchange_bool_acq(mem, newval, oldval) \ + ({ __typeof (mem) __aceb_memp = (mem); \ + int __aceb_ret; \ + __typeof (*mem) __aceb_newval = (newval); \ + \ + __sparc32_atomic_do_lock (__aceb_memp); \ + __aceb_ret = 0; \ + if (*__aceb_memp == (oldval)) \ + *__aceb_memp = __aceb_newval; \ + else \ + __aceb_ret = 1; \ + __sparc32_atomic_do_unlock (__aceb_memp); \ + __aceb_ret; }) + +#define __v7_exchange_acq(mem, newval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock (__acev_memp); \ + __acev_ret = *__acev_memp; \ + *__acev_memp = __acev_newval; \ + __sparc32_atomic_do_unlock (__acev_memp); \ + __acev_ret; }) + +#define __v7_exchange_and_add(mem, value) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + \ + __sparc32_atomic_do_lock (__acev_memp); \ + __acev_ret = *__acev_memp; \ + *__acev_memp = __acev_ret + (value); \ + __sparc32_atomic_do_unlock (__acev_memp); \ + __acev_ret; }) + +/* Special versions, which guarantee that top 8 bits of all values + are cleared and use those bits as the ldstub lock. */ +#define __v7_compare_and_exchange_val_24_acq(mem, newval, oldval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock24 (__acev_memp); \ + __acev_ret = *__acev_memp & 0xffffff; \ + if (__acev_ret == (oldval)) \ + *__acev_memp = __acev_newval; \ + else \ + __sparc32_atomic_do_unlock24 (__acev_memp); \ + __asm __volatile ("" ::: "memory"); \ + __acev_ret; }) + +#define __v7_exchange_24_rel(mem, newval) \ + ({ __typeof (mem) __acev_memp = (mem); \ + __typeof (*mem) __acev_ret; \ + __typeof (*mem) __acev_newval = (newval); \ + \ + __sparc32_atomic_do_lock24 (__acev_memp); \ + __acev_ret = *__acev_memp & 0xffffff; \ + *__acev_memp = __acev_newval; \ + __asm __volatile ("" ::: "memory"); \ + __acev_ret; }) + +#ifdef SHARED + +/* When dynamically linked, we assume pre-v9 libraries are only ever + used on pre-v9 CPU. */ +# define __atomic_is_v9 0 + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ + __v7_compare_and_exchange_val_acq (mem, newval, oldval) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ + __v7_compare_and_exchange_bool_acq (mem, newval, oldval) + +# define atomic_exchange_acq(mem, newval) \ + __v7_exchange_acq (mem, newval) + +# define atomic_exchange_and_add(mem, value) \ + __v7_exchange_and_add (mem, value) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ + ({ \ + if (sizeof (*mem) != 4) \ + abort (); \ + __v7_compare_and_exchange_val_24_acq (mem, newval, oldval); }) + +# define atomic_exchange_24_rel(mem, newval) \ + ({ \ + if (sizeof (*mem) != 4) \ + abort (); \ + __v7_exchange_24_rel (mem, newval); }) + +#else + +/* In libc.a/libpthread.a etc. we don't know if we'll be run on + pre-v9 or v9 CPU. To be interoperable with dynamically linked + apps on v9 CPUs e.g. with process shared primitives, use cas insn + on v9 CPUs and ldstub on pre-v9. */ + +/* Avoid <ldsodefs.h> include here. */ +extern uint64_t _dl_hwcap __attribute__((weak)); +# define __ATOMIC_HWCAP_SPARC_V9 16 +# define __atomic_is_v9 \ + (__builtin_expect (&_dl_hwcap != 0, 1) \ + && __builtin_expect (_dl_hwcap & __ATOMIC_HWCAP_SPARC_V9, \ + __ATOMIC_HWCAP_SPARC_V9)) + +# define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \ + ({ \ + __typeof (*mem) __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + __acev_wret \ + = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ + else \ + __acev_wret \ + = __v7_compare_and_exchange_val_acq (mem, newval, oldval); \ + __acev_wret; }) + +# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ + ({ \ + int __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + { \ + __typeof (oldval) __acev_woldval = (oldval); \ + __acev_wret \ + = __v9_compare_and_exchange_val_32_acq (mem, newval, \ + __acev_woldval) \ + != __acev_woldval; \ + } \ + else \ + __acev_wret \ + = __v7_compare_and_exchange_bool_acq (mem, newval, oldval); \ + __acev_wret; }) + +# define atomic_exchange_rel(mem, newval) \ + ({ \ + __typeof (*mem) __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + { \ + __typeof (mem) __acev_wmemp = (mem); \ + __typeof (*(mem)) __acev_wval = (newval); \ + do \ + __acev_wret = *__acev_wmemp; \ + while (__builtin_expect \ + (__v9_compare_and_exchange_val_32_acq (__acev_wmemp,\ + __acev_wval, \ + __acev_wret) \ + != __acev_wret, 0)); \ + } \ + else \ + __acev_wret = __v7_exchange_acq (mem, newval); \ + __acev_wret; }) + +# define atomic_compare_and_exchange_val_24_acq(mem, newval, oldval) \ + ({ \ + __typeof (*mem) __acev_wret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + __acev_wret \ + = __v9_compare_and_exchange_val_32_acq (mem, newval, oldval);\ + else \ + __acev_wret \ + = __v7_compare_and_exchange_val_24_acq (mem, newval, oldval);\ + __acev_wret; }) + +# define atomic_exchange_24_rel(mem, newval) \ + ({ \ + __typeof (*mem) __acev_w24ret; \ + if (sizeof (*mem) != 4) \ + abort (); \ + if (__atomic_is_v9) \ + __acev_w24ret = atomic_exchange_rel (mem, newval); \ + else \ + __acev_w24ret = __v7_exchange_24_rel (mem, newval); \ + __acev_w24ret; }) + +#endif + +#endif /* bits/atomic.h */ diff --git a/libc/sysdeps/linux/sparc/bits/syscalls.h b/libc/sysdeps/linux/sparc/bits/syscalls.h index fdaa4dee1..4dd161ebf 100644 --- a/libc/sysdeps/linux/sparc/bits/syscalls.h +++ b/libc/sysdeps/linux/sparc/bits/syscalls.h @@ -31,6 +31,8 @@ # error unknown __WORDSIZE #endif +#define __SYSCALL_CLOBBERS "cc", "memory" + #define __SYSCALL_RETURN(type) \ if (__SYSCALL_RES_CHECK) \ return (type) __res; \ @@ -41,75 +43,35 @@ #define _syscall0(type,name) \ type name(void) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res)\ - : "r" (__g1) \ - : "o0", "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,0)); \ } #undef _syscall1 #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -register long __o0 __asm__ ("o0") = (long)(arg1); \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res), "=&r" (__o0) \ - : "1" (__o0), "r" (__g1) \ - : "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,1,arg1)); \ } #undef _syscall2 #define _syscall2(type,name,type1,arg1,type2,arg2) \ type name(type1 arg1,type2 arg2) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -register long __o0 __asm__ ("o0") = (long)(arg1); \ -register long __o1 __asm__ ("o1") = (long)(arg2); \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res), "=&r" (__o0) \ - : "1" (__o0), "r" (__o1), "r" (__g1) \ - : "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,2,arg1,arg2)); \ } #undef _syscall3 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -register long __o0 __asm__ ("o0") = (long)(arg1); \ -register long __o1 __asm__ ("o1") = (long)(arg2); \ -register long __o2 __asm__ ("o2") = (long)(arg3); \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res), "=&r" (__o0) \ - : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1) \ - : "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,3,arg1,arg2,arg3)); \ } #undef _syscall4 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -register long __o0 __asm__ ("o0") = (long)(arg1); \ -register long __o1 __asm__ ("o1") = (long)(arg2); \ -register long __o2 __asm__ ("o2") = (long)(arg3); \ -register long __o3 __asm__ ("o3") = (long)(arg4); \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res), "=&r" (__o0) \ - : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__o3), "r" (__g1) \ - : "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,4,arg1,arg2,arg3,arg4)); \ } #undef _syscall5 @@ -117,18 +79,7 @@ __SYSCALL_RETURN(type) \ type5,arg5) \ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -register long __o0 __asm__ ("o0") = (long)(arg1); \ -register long __o1 __asm__ ("o1") = (long)(arg2); \ -register long __o2 __asm__ ("o2") = (long)(arg3); \ -register long __o3 __asm__ ("o3") = (long)(arg4); \ -register long __o4 __asm__ ("o4") = (long)(arg5); \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res), "=&r" (__o0) \ - : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__o3), "r" (__o4), "r" (__g1) \ - : "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,5,arg1,arg2,arg3,arg4,arg5)); \ } #undef _syscall6 @@ -136,20 +87,118 @@ __SYSCALL_RETURN(type) \ type5,arg5,type6,arg6) \ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, type6 arg6) \ { \ -long __res; \ -register long __g1 __asm__ ("g1") = __NR_##name; \ -register long __o0 __asm__ ("o0") = (long)(arg1); \ -register long __o1 __asm__ ("o1") = (long)(arg2); \ -register long __o2 __asm__ ("o2") = (long)(arg3); \ -register long __o3 __asm__ ("o3") = (long)(arg4); \ -register long __o4 __asm__ ("o4") = (long)(arg5); \ -register long __o5 __asm__ ("o5") = (long)(arg6); \ -__asm__ __volatile__ (__SYSCALL_STRING \ - : "=r" (__res), "=&r" (__o0) \ - : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__o3), "r" (__o4), "r" (__o5), "r" (__g1) \ - : "cc"); \ -__SYSCALL_RETURN(type) \ + return (type)(INLINE_SYSCALL(name,6,arg1,arg2,arg3,arg4,arg5,arg6)); \ +} + +#ifndef NOT_IN_libc +#define DEBUG_SYSCALL(name) { \ + char d[64];\ + write( 2, d, snprintf( d, 64, "syscall %d error %d\n", __NR_##name, _inline_sys_result)); \ } +#else +#define DEBUG_SYSCALL(name) do{} while(0) +#endif + +#undef INLINE_SYSCALL +#define INLINE_SYSCALL(name, nr, args...) \ + ({ unsigned int _inline_sys_result = INTERNAL_SYSCALL (name, , nr, args); \ + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_inline_sys_result, ), 0)) \ + { \ + __set_errno (INTERNAL_SYSCALL_ERRNO (_inline_sys_result, )); \ + _inline_sys_result = (unsigned int) -1; \ + } \ + (int) _inline_sys_result; }) + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + + +#define INTERNAL_SYSCALL( name, err, nr, args...) \ + INTERNAL_SYSCALL_NCS( __NR_##name, err, nr, args ) + + +#define INTERNAL_SYSCALL_NCS(sys_num, err, nr, args...) \ + ({ \ + unsigned int __res; \ + { \ + register long __o0 __asm__("o0"); \ + register long __g1 __asm__("g1") = sys_num; \ + LOAD_ARGS_##nr(args) \ + __asm__ __volatile__( __SYSCALL_STRING \ + : "=r" (__res), "=&r" (__o0) \ + : "1" (__o0) ASM_ARGS_##nr, "r" (__g1) \ + : __SYSCALL_CLOBBERS ); \ + } \ + (int)__res; \ + }) + +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) \ + ((unsigned int) (val) >= 0xfffff001u) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) + +# define CALL_ERRNO_LOCATION "call __errno_location;" +#define __CLONE_SYSCALL_STRING \ + "ta 0x10;" \ + "bcs 2f;" \ + " sub %%o1, 1, %%o1;" \ + "and %%o0, %%o1, %%o0;" \ + "1:" \ + ".subsection 2;" \ + "2:" \ + "save %%sp, -192, %%sp;" \ + CALL_ERRNO_LOCATION \ + " nop;" \ + "st %%i0, [%%o0];" \ + "ba 1b;" \ + " restore %%g0, -1, %%o0;" \ + ".previous;" + +#define INLINE_CLONE_SYSCALL(arg1,arg2,arg3,arg4,arg5) \ +({ \ + register long __o0 __asm__ ("o0") = (long)(arg1); \ + register long __o1 __asm__ ("o1") = (long)(arg2); \ + register long __o2 __asm__ ("o2") = (long)(arg3); \ + register long __o3 __asm__ ("o3") = (long)(arg4); \ + register long __o4 __asm__ ("o4") = (long)(arg5); \ + register long __g1 __asm__ ("g1") = __NR_clone; \ + __asm __volatile (__CLONE_SYSCALL_STRING : \ + "=r" (__g1), "=r" (__o0), "=r" (__o1) : \ + "0" (__g1), "1" (__o0), "2" (__o1), \ + "r" (__o2), "r" (__o3), "r" (__o4) : \ + __SYSCALL_CLOBBERS); \ + __o0; \ +}) + +#define LOAD_ARGS_0() +#define ASM_ARGS_0 +#define LOAD_ARGS_1(o0) \ + __o0 = (int)o0; \ + LOAD_ARGS_0() +#define ASM_ARGS_1 ASM_ARGS_0, "r" (__o0) +#define LOAD_ARGS_2(o0, o1) \ + register int __o1 __asm__ ("o1") = (int) (o1); \ + LOAD_ARGS_1 (o0) +#define ASM_ARGS_2 ASM_ARGS_1, "r" (__o1) +#define LOAD_ARGS_3(o0, o1, o2) \ + register int __o2 __asm__ ("o2") = (int) (o2); \ + LOAD_ARGS_2 (o0, o1) +#define ASM_ARGS_3 ASM_ARGS_2, "r" (__o2) +#define LOAD_ARGS_4(o0, o1, o2, o3) \ + register int __o3 __asm__ ("o3") = (int) (o3); \ + LOAD_ARGS_3 (o0, o1, o2) +#define ASM_ARGS_4 ASM_ARGS_3, "r" (__o3) +#define LOAD_ARGS_5(o0, o1, o2, o3, o4) \ + register int __o4 __asm__ ("o4") = (int) (o4); \ + LOAD_ARGS_4 (o0, o1, o2, o3) +#define ASM_ARGS_5 ASM_ARGS_4, "r" (__o4) +#define LOAD_ARGS_6(o0, o1, o2, o3, o4, o5) \ + register int __o5 __asm__ ("o5") = (int) (o5); \ + LOAD_ARGS_5 (o0, o1, o2, o3, o4) +#define ASM_ARGS_6 ASM_ARGS_5, "r" (__o5) + #endif /* __ASSEMBLER__ */ #endif /* _BITS_SYSCALLS_H */ diff --git a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h index 41d3e7c3d..b097316b0 100644 --- a/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h +++ b/libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h @@ -35,4 +35,7 @@ /* define if target supports IEEE signed zero floats */ #define __UCLIBC_HAVE_SIGNED_ZERO__ +/* define if target supports CFI pseudo ops */ +#define __UCLIBC_HAVE_ASM_CFI_DIRECTIVES__ + #endif /* _BITS_UCLIBC_ARCH_FEATURES_H */ diff --git a/libc/sysdeps/linux/sparc/clone.S b/libc/sysdeps/linux/sparc/clone.S index 0e41ee0cb..b623bfb8d 100644 --- a/libc/sysdeps/linux/sparc/clone.S +++ b/libc/sysdeps/linux/sparc/clone.S @@ -1,4 +1,5 @@ -/* Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc. +/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2007 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Richard Henderson (rth@tamu.edu). @@ -20,47 +21,87 @@ /* clone() is even more special than fork() as it mucks with stacks and invokes a function in the right context after its all over. */ -#include <features.h> +#include <asm/errno.h> #include <asm/unistd.h> +#include <tcb-offsets.h> +#include <sysdep.h> -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 -.text -.global clone -.type clone,%function -.align 4 +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + pid_t *ptid, void *tls, pid_t *ctid); */ -clone: + .text +ENTRY (__clone) save %sp,-96,%sp + cfi_def_cfa_register(%fp) + cfi_window_save + cfi_register(%o7, %i7) /* sanity check arguments */ - tst %i0 - be __error - orcc %i1,%g0,%o1 - be __error - mov %i2,%o0 + orcc %i0,%g0,%g2 + be .Leinval + orcc %i1,%g0,%o1 + be .Leinval + mov %i2,%o0 + + /* The child_stack is the top of the stack, allocate one + whole stack frame from that as this is what the kernel + expects. */ + sub %o1, 96, %o1 + mov %i3, %g3 + mov %i2, %g4 + + /* ptid */ + mov %i4,%o2 + /* tls */ + mov %i5,%o3 + /* ctid */ + ld [%fp+92],%o4 /* Do the system call */ set __NR_clone,%g1 ta 0x10 - bcs __error - tst %o1 + bcs .Lerror + tst %o1 bne __thread_start - nop - ret - restore %o0,%g0,%o0 - -__error: - jmp __syscall_error + nop + jmpl %i7 + 8, %g0 + restore %o0,%g0,%o0 -.size clone,.-clone - -.type __thread_start,%function +.Leinval: + mov EINVAL, %o0 +.Lerror: + call HIDDEN_JUMPTARGET(__errno_location) + mov %o0, %i0 + st %i0,[%o0] + jmpl %i7 + 8, %g0 + restore %g0,-1,%o0 +END(__clone) + .type __thread_start,@function __thread_start: - call %i0 - mov %i3,%o0 +#ifdef RESET_PID + sethi %hi(CLONE_THREAD), %l0 + andcc %g4, %l0, %g0 + bne 1f + andcc %g4, CLONE_VM, %g0 + bne,a 2f + mov -1,%o0 + set __NR_getpid,%g1 + ta 0x10 +2: + st %o0,[%g7 + PID] + st %o0,[%g7 + TID] +1: +#endif + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 call HIDDEN_JUMPTARGET(_exit),0 - nop + nop + + .size __thread_start, .-__thread_start -.size __thread_start,.-__thread_start +weak_alias (__clone, clone) diff --git a/libpthread/nptl/sysdeps/sparc/Makefile.arch b/libpthread/nptl/sysdeps/sparc/Makefile.arch new file mode 100644 index 000000000..4547ee3f3 --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/Makefile.arch @@ -0,0 +1,49 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_CSRC = sparc32/pthread_spin_lock.c \ + sparc32/pthread_spin_trylock.c + +CFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-sparc = $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +PTHREAD_ARCH_DIR := $(top_srcdir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OUT := $(top_builddir)libpthread/nptl/sysdeps/sparc/ +PTHREAD_ARCH_OBJ := $(patsubst %.S,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_SSRC)) +PTHREAD_ARCH_OBJ += $(patsubst %.c,$(PTHREAD_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +libpthread-a-y += $(PTHREAD_ARCH_OBJ) +libpthread-so-y += $(PTHREAD_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y += $(PTHREAD_ARCH_OBJ) + +objclean-y += nptl_arch_clean +headers_clean-y += nptl_arch_headers_clean + +# +# Create 'tcb-offsets.h' header file. +# +CFLAGS-tcb-offsets.c = -S + +$(PTHREAD_ARCH_OUT)/tcb-offsets.c: $(PTHREAD_ARCH_DIR)/tcb-offsets.sym + $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@ + +$(PTHREAD_ARCH_OUT)/tcb-offsets.s: $(PTHREAD_ARCH_OUT)/tcb-offsets.c + $(compile.c) + +$(PTHREAD_ARCH_OUT)/tcb-offsets.h: $(PTHREAD_ARCH_OUT)/tcb-offsets.s + @sed -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@ + +nptl_arch_headers: $(PTHREAD_ARCH_OUT)/tcb-offsets.h + +nptl_arch_headers_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/tcb-offsets., c s h) + +nptl_arch_clean: + $(do_rm) $(addprefix $(PTHREAD_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h new file mode 100644 index 000000000..d6c2baabd --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h @@ -0,0 +1,6 @@ +#if defined(__arch64__) +#include "sparc64/jmpbuf-unwind.h" +#else +#include "sparc32/jmpbuf-unwind.h" +#endif + diff --git a/libpthread/nptl/sysdeps/sparc/pthreaddef.h b/libpthread/nptl/sysdeps/sparc/pthreaddef.h new file mode 100644 index 000000000..bcc6ed10a --- /dev/null +++ b/libpthread/nptl/sysdeps/sparc/pthreaddef.h @@ -0,0 +1,6 @@ +#if defined(__arch64__) +#include "sparc64/pthreaddef.h" +#else +#include "sparc32/pthreaddef.h" +#endif + diff --git a/libpthread/nptl/sysdeps/sparc/tls.h b/libpthread/nptl/sysdeps/sparc/tls.h index ea26ed32f..e5d27fb57 100644 --- a/libpthread/nptl/sysdeps/sparc/tls.h +++ b/libpthread/nptl/sysdeps/sparc/tls.h @@ -54,9 +54,9 @@ typedef struct #endif /* __ASSEMBLER__ */ /* We require TLS support in the tools. */ -#ifndef HAVE_TLS_SUPPORT -# error "TLS support is required." -#endif +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 /* Signal that TLS support is available. */ #define USE_TLS 1 @@ -65,9 +65,6 @@ typedef struct /* Get system call information. */ # include <sysdep.h> -/* Get the thread descriptor definition. */ -# include <nptl/descr.h> - register struct pthread *__thread_self __asm__("%g7"); /* This is the size of the initial TCB. Can't be just sizeof (tcbhead_t), @@ -84,6 +81,9 @@ register struct pthread *__thread_self __asm__("%g7"); /* Alignment requirements for the TCB. */ # define TLS_TCB_ALIGN __alignof__ (struct pthread) +/* Get the thread descriptor definition. */ +# include <descr.h> + /* The TCB can have any size and the memory following the address the thread pointer points to is unspecified. Allocate the TCB there. */ # define TLS_TCB_AT_TP 1 diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in index b2b901a1a..82b47b691 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in @@ -51,7 +51,7 @@ endif ifeq ($(TARGET_ARCH),sparc) libpthread_CSRC += lowlevellock.c libc_CSRC += libc-lowlevellock.c -librt_CSRC := mq_notify.c +librt_CSRC := mq_notify.c __syscall_error.c endif ifeq ($(TARGET_ARCH),sh) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c new file mode 100644 index 000000000..5e109a83b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c @@ -0,0 +1,18 @@ +/* Wrapper for setting errno. + * + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <errno.h> +#include <features.h> + +/* This routine is jumped to by all the syscall handlers, to stash + * an error number into errno. */ +int __syscall_error(int err_no) attribute_hidden; +int __syscall_error(int err_no) +{ + __set_errno(err_no); + return -1; +} diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c index 9defac619..9149efe58 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c @@ -21,4 +21,4 @@ #define TLS_VALUE pd /* Get the real implementation. */ -#include <nptl/sysdeps/pthread/createthread.c> +#include <sysdeps/pthread/createthread.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile new file mode 100644 index 000000000..43a6fad84 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../../../../../ +top_builddir=../../../../../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.arch +include $(top_srcdir)Makerules diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch new file mode 100644 index 000000000..6a0d2b51d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch @@ -0,0 +1,58 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill <sjhill@uclibc.org> +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +libpthread_SSRC = pt-vfork.S clone.S +libpthread_CSRC = pthread_once.c + +libc_a_CSRC = fork.c +libc_a_SSRC = clone.S vfork.S + +CFLAGS-OMIT-fork.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif + +ASFLAGS-pt-vfork.S = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 -D_LIBC_REENTRANT -DUSE___THREAD + +CFLAGS-pthread_once.c = -DNOT_IN_libc=1 -DIS_IN_libpthread=1 + + +ASFLAGS-clone.S = -D_LIBC_REENTRANT +ASFLAGS-vfork.S = -D_LIBC_REENTRANT + +ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) +#Needed to use the correct SYSCALL_ERROR_HANDLER +ASFLAGS-clone.S += -DUSE___THREAD +ASFLAGS-vfork.S += -DUSE___THREAD +endif + +CFLAGS += $(SSP_ALL_CFLAGS) +#CFLAGS:=$(CFLAGS:-O1=-O2) + +LINUX_ARCH_DIR:=$(top_srcdir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc +LINUX_ARCH_OUT:=$(top_builddir)libpthread/nptl/sysdeps/unix/sysv/linux/sparc + +LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) +LINUX_ARCH_OBJ+=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libpthread_CSRC)) + +libpthread-a-y += $(LINUX_ARCH_OBJ) +libpthread-so-y += $(LINUX_ARCH_OBJ:.o=.oS) + +libpthread-nomulti-y+=$(LINUX_ARCH_OBJS) + +LIBC_LINUX_ARCH_OBJ:=$(patsubst %.c,$(LINUX_ARCH_OUT)/%.o,$(libc_a_CSRC)) +LIBC_LINUX_ARCH_OBJ+=$(patsubst %.S,$(LINUX_ARCH_OUT)/%.o,$(libc_a_SSRC)) + +libc-static-y+=$(LIBC_LINUX_ARCH_OBJ) +libc-shared-y+=$(LIBC_LINUX_ARCH_OBJ:.o=.oS) + +libc-nomulti-y+=$(LIBC_LINUX_ARCH_OBJ) + +objclean-y+=nptl_linux_arch_clean + +nptl_linux_arch_clean: + $(do_rm) $(addprefix $(LINUX_ARCH_OUT)/*., o os oS) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S new file mode 100644 index 000000000..dfc5e8261 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "./sparc64/clone.S" +#else +#include "./sparc32/clone.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h index 4626aec52..4db6fb0b4 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2003, 2004, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. @@ -24,33 +24,28 @@ #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; \ - }) + lll_futex_timed_wait (futexp, val, NULL) #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 = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + FUTEX_WAIT, (val), (timespec)); \ __ret; \ }) @@ -58,9 +53,8 @@ ({ \ INTERNAL_SYSCALL_DECL (__err); \ long int __ret; \ - \ - __ret = INTERNAL_SYSCALL (futex, __err, 4, \ - (futexp), FUTEX_WAKE, (nr), 0); \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + FUTEX_WAKE, (nr), 0); \ __ret; \ }) @@ -69,70 +63,115 @@ ({ \ INTERNAL_SYSCALL_DECL (__err); \ long int __ret; \ - \ - __ret = INTERNAL_SYSCALL (futex, __err, 6, \ - (futexp), FUTEX_CMP_REQUEUE, (nr_wake), \ - (nr_move), (mutex), (val)); \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + FUTEX_CMP_REQUEUE, (nr_wake), (nr_move), (mutex), (val)); \ INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ }) +#define lll_robust_dead(futexv) \ + do \ + { \ + int *__futexp = &(futexv); \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1); \ + } \ + while (0) + +/* Returns non-zero if error happened, zero if success. */ #ifdef __sparc32_atomic_do_lock -#error SPARC < v9 does not support compare and swap which is essential for futex based locking +/* Avoid FUTEX_WAKE_OP if supporting pre-v9 CPUs. */ +# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2) 1 +#else +# 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); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) #endif static inline int __attribute__ ((always_inline)) -__lll_mutex_trylock (int *futex) +__lll_trylock (int *futex) { - return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0; + return atomic_compare_and_exchange_val_24_acq (futex, 1, 0) != 0; } -#define lll_mutex_trylock(futex) __lll_mutex_trylock (&(futex)) +#define lll_mutex_trylock(futex) __lll_trylock (&(futex)) static inline int __attribute__ ((always_inline)) -__lll_mutex_cond_trylock (int *futex) +__lll_cond_trylock (int *futex) { - return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0; + return atomic_compare_and_exchange_val_24_acq (futex, 2, 0) != 0; } -#define lll_mutex_cond_trylock(futex) __lll_mutex_cond_trylock (&(futex)) +#define lll_mutex_cond_trylock(futex) __lll_cond_trylock (&(futex)) +static inline int +__attribute__ ((always_inline)) +__lll_robust_trylock (int *futex, int id) +{ + return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0; +} +#define lll_robust_trylock(futex, id) \ + __lll_robust_trylock (&(futex), id) -extern void __lll_lock_wait (int *futex) attribute_hidden; +extern void __lll_lock_wait (int *futex) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex) attribute_hidden; static inline void __attribute__ ((always_inline)) -__lll_mutex_lock (int *futex) +__lll_lock (int *futex) { - int val = atomic_compare_and_exchange_val_acq (futex, 1, 0); + int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); if (__builtin_expect (val != 0, 0)) - __lll_lock_wait (futex); + { + __lll_lock_wait (futex); + } } -#define lll_mutex_lock(futex) __lll_mutex_lock (&(futex)) +#define lll_mutex_lock(futex) __lll_lock (&(futex)) +static inline int +__attribute__ ((always_inline)) +__lll_robust_lock (int *futex, int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_lock_wait (futex); + return result; +} +#define lll_robust_lock(futex, id) \ + __lll_robust_lock (&(futex), id) static inline void __attribute__ ((always_inline)) -__lll_mutex_cond_lock (int *futex) +__lll_cond_lock (int *futex) { - int val = atomic_compare_and_exchange_val_acq (futex, 2, 0); + int val = atomic_compare_and_exchange_val_24_acq (futex, 2, 0); if (__builtin_expect (val != 0, 0)) __lll_lock_wait (futex); } -#define lll_mutex_cond_lock(futex) __lll_mutex_cond_lock (&(futex)) +#define lll_mutex_cond_lock(futex) __lll_cond_lock (&(futex)) +#define lll_robust_cond_lock(futex, id) \ + __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS) -extern int __lll_timedlock_wait (int *futex, const struct timespec *) - attribute_hidden; +extern int __lll_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *) attribute_hidden; static inline int __attribute__ ((always_inline)) -__lll_mutex_timedlock (int *futex, const struct timespec *abstime) +__lll_timedlock (int *futex, const struct timespec *abstime) { - int val = atomic_compare_and_exchange_val_acq (futex, 1, 0); + int val = atomic_compare_and_exchange_val_24_acq (futex, 1, 0); int result = 0; if (__builtin_expect (val != 0, 0)) @@ -140,43 +179,56 @@ __lll_mutex_timedlock (int *futex, const struct timespec *abstime) return result; } #define lll_mutex_timedlock(futex, abstime) \ - __lll_mutex_timedlock (&(futex), abstime) + __lll_timedlock (&(futex), abstime) + +static inline int +__attribute__ ((always_inline)) +__lll_robust_timedlock (int *futex, const struct timespec *abstime, + int id) +{ + int result = 0; + if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0) + result = __lll_robust_timedlock_wait (futex, abstime); + return result; +} +#define lll_robust_timedlock(futex, abstime, id) \ + __lll_robust_timedlock (&(futex), abstime, id) #define lll_mutex_unlock(lock) \ ((void) ({ \ int *__futex = &(lock); \ - int __val = atomic_exchange_rel (__futex, 0); \ + int __val = atomic_exchange_24_rel (__futex, 0); \ if (__builtin_expect (__val > 1, 0)) \ - lll_futex_wake (__futex, 1); \ + lll_futex_wake (__futex, 1); \ })) -#define lll_mutex_unlock_force(lock) \ +#define lll_robust_unlock(lock) \ ((void) ({ \ int *__futex = &(lock); \ - (void) atomic_exchange_rel (__futex, 0); \ - lll_futex_wake (__futex, 1); \ + int __val = atomic_exchange_rel (__futex, 0); \ + if (__builtin_expect (__val & FUTEX_WAITERS, 0)) \ + lll_futex_wake (__futex, 1); \ })) #define lll_mutex_islocked(futex) \ (futex != 0) - /* We have a separate internal lock implementation which is not tied - to binary compatibility. We can use the lll_mutex_*. */ + to binary compatibility. */ /* Type for lock object. */ typedef int lll_lock_t; -extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; - /* Initializers for lock. */ #define LLL_LOCK_INITIALIZER (0) #define LLL_LOCK_INITIALIZER_LOCKED (1) -#define lll_trylock(futex) lll_mutex_trylock (futex) -#define lll_lock(futex) lll_mutex_lock (futex) -#define lll_unlock(futex) lll_mutex_unlock (futex) -#define lll_islocked(futex) lll_mutex_islocked (futex) +extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; + +#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 with uses CLONE_CLEARTID via futex @@ -184,12 +236,12 @@ extern int lll_unlock_wake_cb (int *__futex) attribute_hidden; 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); \ - } \ + do \ + { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid); \ + } \ while (0) extern int __lll_timedwait_tid (int *, const struct timespec *) @@ -203,26 +255,4 @@ extern int __lll_timedwait_tid (int *, const struct timespec *) __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 */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/not-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/not-cancel.h deleted file mode 100644 index acf1a617e..000000000 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/not-cancel.h +++ /dev/null @@ -1 +0,0 @@ -#include "../i386/not-cancel.h" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S new file mode 100644 index 000000000..e8705c54b --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/pt-vfork.S" +#else +#include "sparc32/pt-vfork.S" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S index da6197c00..a6142aafe 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S @@ -1,2 +1,2 @@ #define RESET_PID -#include <sysdeps/unix/sysv/linux/sparc/sparc32/clone.S> +#include <libc/sysdeps/linux/sparc/clone.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S index 55229c9e6..fb01242b5 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S @@ -21,6 +21,7 @@ #include <tcb-offsets.h> .text + .globl __syscall_error ENTRY(__vfork) ld [%g7 + PID], %o5 sub %g0, %o5, %o4 @@ -28,15 +29,17 @@ ENTRY(__vfork) LOADSYSCALL(vfork) ta 0x10 - bcs,a __syscall_error_handler - st %o5, [%g7 + PID] - SYSCALL_ERROR_HANDLER - sub %o1, 1, %o1 + bcc 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 andcc %o0, %o1, %o0 bne,a 1f st %o5, [%g7 + PID] 1: retl nop +END(__vfork) -PSEUDO_END (__vfork) weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h index 5edf4b377..ad650d040 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h @@ -17,64 +17,56 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include <sysdep.h> #include <tls.h> +#include <sysdep.h> #ifndef __ASSEMBLER__ -# include <nptl/pthreadP.h> +# include <pthreadP.h> #endif #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt # undef PSEUDO -# define PSEUDO(name, syscall_name, args) \ - .text; \ -ENTRY(name) \ - ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1; \ - cmp %g1, 0; \ - bne 1f; \ -.type __##syscall_name##_nocancel,@function; \ -.globl __##syscall_name##_nocancel; \ -__##syscall_name##_nocancel: \ - mov SYS_ify(syscall_name), %g1; \ - ta 0x10; \ - bcs __syscall_error_handler; \ - nop; \ -.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ - .subsection 2; \ - cfi_startproc; \ -1: save %sp, -96, %sp; \ - cfi_def_cfa_register (%fp); \ - cfi_window_save; \ - cfi_register (%o7, %i7); \ - CENABLE; \ - nop; \ - mov %o0, %l0; \ - COPY_ARGS_##args \ - mov SYS_ify(syscall_name), %g1; \ - ta 0x10; \ - bcs __syscall_error_handler2; \ - mov %o0, %l1; \ - CDISABLE; \ - mov %l0, %o0; \ - jmpl %i7 + 8, %g0; \ - restore %g0, %l1, %o0; \ - cfi_endproc; \ - .previous; \ - SYSCALL_ERROR_HANDLER \ - SYSCALL_ERROR_HANDLER2 - -#define SYSCALL_ERROR_HANDLER2 \ -SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler2) \ - .global __errno_location; \ - .type __errno_location,@function; \ - CDISABLE; \ - mov %l0, %o0; \ - call __errno_location; \ - nop; \ - st %l1, [%o0]; \ - jmpl %i7 + 8, %g0; \ - restore %g0, -1, %o0; \ - .previous; +# define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name) \ + ld [%g7 + MULTIPLE_THREADS_OFFSET], %g1;\ + cmp %g1, 0; \ + bne 1f; \ +.type __##syscall_name##_nocancel,@function; \ +.globl __##syscall_name##_nocancel; \ +__##syscall_name##_nocancel: \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcc 8f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +8: jmpl %o7 + 8, %g0; \ + nop; \ +.size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;\ +1: save %sp, -96, %sp; \ + cfi_def_cfa_register(%fp); \ + cfi_window_save; \ + cfi_register(%o7, %i7); \ + CENABLE; \ + nop; \ + mov %o0, %l0; \ + COPY_ARGS_##args \ + mov SYS_ify(syscall_name), %g1; \ + ta 0x10; \ + bcc 1f; \ + mov %o0, %l1; \ + CDISABLE; \ + mov %l0, %o0; \ + call __syscall_error; \ + mov %l1, %o0; \ + b 2f; \ + mov -1, %l1; \ +1: CDISABLE; \ + mov %l0, %o0; \ +2: jmpl %i7 + 8, %g0; \ + restore %g0, %l1, %o0; # ifdef IS_IN_libpthread # define CENABLE call __pthread_enable_asynccancel diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S index d804f0c4b..1a3827789 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S @@ -21,6 +21,7 @@ #include <tcb-offsets.h> .text + .globl __syscall_error ENTRY(__vfork) ld [%g7 + PID], %o5 cmp %o5, 0 @@ -31,16 +32,18 @@ ENTRY(__vfork) LOADSYSCALL(vfork) ta 0x10 - bcs,a __syscall_error_handler - st %o5, [%g7 + PID] - SYSCALL_ERROR_HANDLER - sub %o1, 1, %o1 + bcc 2f + mov %o7, %g1 + st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 +2: sub %o1, 1, %o1 andcc %o0, %o1, %o0 bne,a 1f st %o5, [%g7 + PID] 1: retl nop +END(__vfork) -PSEUDO_END (__vfork) -hidden_def (__vfork) +hidden_def (vfork) weak_alias (__vfork, vfork) diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h new file mode 100644 index 000000000..5be9beb92 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/sysdep-cancel.h" +#else +#include "sparc32/sysdep-cancel.h" +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h new file mode 100644 index 000000000..744e587a3 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h @@ -0,0 +1,65 @@ +#ifndef _LINUX_SPARC_SYSDEP_H +#define _LINUX_SPARC_SYSDEP_H 1 + +#include <sysdeps/unix/sysdep.h> + +#undef ENTRY +#undef END + +#ifdef __ASSEMBLER__ + +#define LOADSYSCALL(x) mov __NR_##x, %g1 + +#define ENTRY(name) \ + .align 4; \ + .global C_SYMBOL_NAME(name); \ + .type name, @function; \ +C_LABEL(name) \ + cfi_startproc; + +#define END(name) \ + cfi_endproc; \ + .size name, . - name + +#define LOC(name) .L##name + + /* If the offset to __syscall_error fits into a signed 22-bit + * immediate branch offset, the linker will relax the call into + * a normal branch. + */ +#undef PSEUDO +#undef PSEUDO_END +#undef PSEUDO_NOERRNO +#undef PSEUDO_ERRVAL + +#define PSEUDO(name, syscall_name, args) \ + .text; \ + .globl __syscall_error; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; \ + bcc 1f; \ + mov %o7, %g1; \ + call __syscall_error; \ + mov %g1, %o7; \ +1: + +#define PSEUDO_NOERRNO(name, syscall_name, args)\ + .text; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; + +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + .text; \ +ENTRY(name); \ + LOADSYSCALL(syscall_name); \ + ta 0x10; + +#define PSEUDO_END(name) \ + END(name) + + +#endif + +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S new file mode 100644 index 000000000..160cd0b10 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S @@ -0,0 +1,5 @@ +#if defined(__arch64__) +#include "sparc64/vfork.S" +#else +#include "sparc32/vfork.S" +#endif |