summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldso/ldso/sparc/elfinterp.c6
-rw-r--r--libc/sysdeps/linux/common/Makefile.in4
-rw-r--r--libc/sysdeps/linux/sparc/Makefile.arch2
-rw-r--r--libc/sysdeps/linux/sparc/bits/atomic.h327
-rw-r--r--libc/sysdeps/linux/sparc/bits/syscalls.h189
-rw-r--r--libc/sysdeps/linux/sparc/bits/uClibc_arch_features.h3
-rw-r--r--libc/sysdeps/linux/sparc/clone.S97
-rw-r--r--libpthread/nptl/sysdeps/sparc/Makefile.arch49
-rw-r--r--libpthread/nptl/sysdeps/sparc/jmpbuf-unwind.h6
-rw-r--r--libpthread/nptl/sysdeps/sparc/pthreaddef.h6
-rw-r--r--libpthread/nptl/sysdeps/sparc/tls.h12
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/Makefile.in2
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/__syscall_error.c18
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/createthread.c2
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile13
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/Makefile.arch58
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/clone.S5
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/lowlevellock.h190
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/not-cancel.h1
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/pt-vfork.S5
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S2
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/pt-vfork.S13
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h94
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S15
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep-cancel.h5
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/sysdep.h65
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/sparc/vfork.S5
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