From daecc9a410a6f23d80daf8ce3afd280fea329e63 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 18 Nov 2010 14:58:01 +0000 Subject: metag: Add NPTL support Signed-off-by: Markos Chandras Signed-off-by: Bernhard Reutner-Fischer --- include/elf.h | 5 + ldso/ldso/metag/dl-debug.h | 8 +- ldso/ldso/metag/dl-startup.h | 5 + ldso/ldso/metag/dl-sysdep.h | 19 +- ldso/ldso/metag/elfinterp.c | 119 +++++---- ldso/ldso/metag/metag_load_tp.S | 20 ++ libc/sysdeps/linux/common/Makefile.in | 1 + libc/sysdeps/linux/metag/Makefile.arch | 4 +- libc/sysdeps/linux/metag/bits/atomic.h | 66 +++++ libc/sysdeps/linux/metag/bits/syscalls.h | 73 ++++-- libc/sysdeps/linux/metag/clone.S | 50 +++- libc/sysdeps/linux/metag/crt1.S | 3 +- libc/sysdeps/linux/metag/libc-metag_load_tp.S | 7 + libc/sysdeps/linux/metag/sysdep.h | 59 +++++ libc/sysdeps/linux/metag/vfork.S | 67 +++++ libpthread/nptl/sysdeps/metag/Makefile.arch | 17 ++ libpthread/nptl/sysdeps/metag/dl-tls.h | 29 +++ libpthread/nptl/sysdeps/metag/jmpbuf-unwind.h | 36 +++ libpthread/nptl/sysdeps/metag/libc-tls.c | 33 +++ libpthread/nptl/sysdeps/metag/metag_load_tp.S | 7 + libpthread/nptl/sysdeps/metag/pthread_spin_init.c | 20 ++ libpthread/nptl/sysdeps/metag/pthread_spin_lock.S | 20 ++ .../nptl/sysdeps/metag/pthread_spin_trylock.S | 24 ++ .../nptl/sysdeps/metag/pthread_spin_unlock.S | 16 ++ libpthread/nptl/sysdeps/metag/pthreaddef.h | 40 +++ libpthread/nptl/sysdeps/metag/tcb-offsets.sym | 15 ++ libpthread/nptl/sysdeps/metag/tls.h | 163 ++++++++++++ .../nptl/sysdeps/unix/sysv/linux/metag/Makefile | 13 + .../sysdeps/unix/sysv/linux/metag/Makefile.arch | 34 +++ .../unix/sysv/linux/metag/bits/pthreadtypes.h | 181 +++++++++++++ .../sysdeps/unix/sysv/linux/metag/bits/semaphore.h | 35 +++ .../nptl/sysdeps/unix/sysv/linux/metag/clone.S | 9 + .../sysdeps/unix/sysv/linux/metag/createthread.c | 23 ++ .../nptl/sysdeps/unix/sysv/linux/metag/fork.c | 31 +++ .../unix/sysv/linux/metag/libc-lowlevellock.c | 21 ++ .../sysdeps/unix/sysv/linux/metag/lowlevellock.c | 134 ++++++++++ .../sysdeps/unix/sysv/linux/metag/lowlevellock.h | 279 +++++++++++++++++++++ .../unix/sysv/linux/metag/pt-__syscall_error.c | 7 + .../sysv/linux/metag/pt-__syscall_rt_sigaction.c | 7 + .../unix/sysv/linux/metag/pt-gettimeofday.c | 11 + .../nptl/sysdeps/unix/sysv/linux/metag/pt-vfork.S | 51 ++++ .../sysdeps/unix/sysv/linux/metag/pthread_once.c | 100 ++++++++ .../sysdeps/unix/sysv/linux/metag/sysdep-cancel.h | 152 +++++++++++ .../nptl/sysdeps/unix/sysv/linux/metag/vfork.S | 56 +++++ 44 files changed, 1975 insertions(+), 95 deletions(-) create mode 100644 ldso/ldso/metag/metag_load_tp.S create mode 100644 libc/sysdeps/linux/metag/bits/atomic.h create mode 100644 libc/sysdeps/linux/metag/libc-metag_load_tp.S create mode 100644 libc/sysdeps/linux/metag/sysdep.h create mode 100644 libc/sysdeps/linux/metag/vfork.S create mode 100644 libpthread/nptl/sysdeps/metag/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/metag/dl-tls.h create mode 100644 libpthread/nptl/sysdeps/metag/jmpbuf-unwind.h create mode 100644 libpthread/nptl/sysdeps/metag/libc-tls.c create mode 100644 libpthread/nptl/sysdeps/metag/metag_load_tp.S create mode 100644 libpthread/nptl/sysdeps/metag/pthread_spin_init.c create mode 100644 libpthread/nptl/sysdeps/metag/pthread_spin_lock.S create mode 100644 libpthread/nptl/sysdeps/metag/pthread_spin_trylock.S create mode 100644 libpthread/nptl/sysdeps/metag/pthread_spin_unlock.S create mode 100644 libpthread/nptl/sysdeps/metag/pthreaddef.h create mode 100644 libpthread/nptl/sysdeps/metag/tcb-offsets.sym create mode 100644 libpthread/nptl/sysdeps/metag/tls.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile.arch create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/pthreadtypes.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/semaphore.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/clone.S create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/createthread.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/fork.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/libc-lowlevellock.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_error.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_rt_sigaction.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-gettimeofday.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-vfork.S create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/pthread_once.c create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/sysdep-cancel.h create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/metag/vfork.S diff --git a/include/elf.h b/include/elf.h index 877d08194..cbb4da218 100644 --- a/include/elf.h +++ b/include/elf.h @@ -3184,6 +3184,11 @@ typedef Elf32_Addr Elf32_Conflict; #define R_METAG_RELATIVE 45 #define R_METAG_GLOB_DAT 46 +/* TLS relocations */ +#define R_METAG_TLS_TPOFF 56 +#define R_METAG_TLS_DTPMOD 57 +#define R_METAG_TLS_DTPOFF 58 + #ifdef __cplusplus } #endif diff --git a/ldso/ldso/metag/dl-debug.h b/ldso/ldso/metag/dl-debug.h index 5981d7c73..46c257c5c 100644 --- a/ldso/ldso/metag/dl-debug.h +++ b/ldso/ldso/metag/dl-debug.h @@ -17,11 +17,17 @@ static const char *_dl_reltypes_tab[] = { [6] "R_METAG_REG32OP1", "R_METAG_REG32OP2", "R_METAG_REG32OP3", [9] "R_METAG_REG16OP1", "R_METAG_REG16OP2", "R_METAG_REG16OP3", [12] "R_METAG_REG32OP4", "R_METAG_HIOG", "R_METAG_LOOG", - [30] "R_METAG_VTINHERIT", "R_METAG_VTENTRY", + [30] "R_METAG_GNU_VTINHERIT", "R_METAG_GNU_VTENTRY", [32] "R_METAG_HI16_GOTOFF", "R_METAG_LO16_GOTOFF", [34] "R_METAG_GETSET_GOTOFF", "R_METAG_GETSET_GOT", [36] "R_METAG_HI16_GOTPC", "R_METAG_LO16_GOTPC", [38] "R_METAG_HI16_PLT", "R_METAG_LO16_PLT", [40] "R_METAG_RELBRANCH_PLT", "R_METAG_GOTOFF", [42] "R_METAG_PLT", "R_METAG_COPY", "R_METAG_JMP_SLOT", + [45] "R_METAG_RELATIVE", "R_METAG_GLOB_DAT", "R_METAG_TLS_GD", + [48] "R_METAG_TLS_LDM", "R_METAG_TLS_LDO_HI16", "R_METAG_TLS_LDO_LO16", + [51] "R_METAG_TLS_LDO", "R_METAG_TLS_IE", "R_METAG_TLS_IENONPIC", + [54] "R_METAG_TLS_IENONPIC_HI16", "R_METAG_TLS_IENONPIC_LO16", + [56] "R_METAG_TLS_TPOFF", "R_METAG_TLS_DTPMOD", "R_METAG_TLS_DTPOFF", + [59] "R_METAG_TLS_LE", "R_METAG_TLS_LE_HI16", "R_METAG_TLS_LE_LO16" }; diff --git a/ldso/ldso/metag/dl-startup.h b/ldso/ldso/metag/dl-startup.h index 8dbf747e1..32b2e4b74 100644 --- a/ldso/ldso/metag/dl-startup.h +++ b/ldso/ldso/metag/dl-startup.h @@ -21,6 +21,11 @@ __asm__ ( " CALLR D1RtP,__dl_start\n" " GETL D0Ar2,D1Ar1,[A0StP+#-(1*8)]\n" " GETL D0Ar4,D1Ar3,[A0StP+#-(2*8)]\n" +" ADDT A1LbP,CPC1,#HI(__GLOBAL_OFFSET_TABLE__)\n" +" ADD A1LbP,A1LbP,#LO(__GLOBAL_OFFSET_TABLE__+4)\n" +" ADDT A1LbP,A1LbP,#HI(__dl_fini@GOTOFF)\n" +" ADD A1LbP,A1LbP,#LO(__dl_fini@GOTOFF)\n" +" MOV D0Ar4, A1LbP\n" " SUB A0StP,A0StP,#(2*8)\n" " MOV PC,D0Re0\n" " .size __start,.-__start\n" diff --git a/ldso/ldso/metag/dl-sysdep.h b/ldso/ldso/metag/dl-sysdep.h index 29547cb34..257ca610f 100644 --- a/ldso/ldso/metag/dl-sysdep.h +++ b/ldso/ldso/metag/dl-sysdep.h @@ -36,14 +36,17 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entr #define PAGE_ALIGN (~ADDR_ALIGN) #define OFFS_ALIGN (PAGE_ALIGN & ~(1ul << (sizeof(_dl_pagesize) * 8 - 1))) -/* The union of reloc-type-classes where the reloc TYPE is a member. - - TYPE is in the class ELF_RTYPE_CLASS_NOCOPY if it should not be allowed - to resolve to one of the main executable's symbols, as for a COPY - reloc. */ -#define elf_machine_type_class(type) \ - (((((type) == R_METAG_JMP_SLOT)) * ELF_RTYPE_CLASS_PLT) \ - | (((type) == R_METAG_COPY) * ELF_RTYPE_CLASS_COPY)) +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or + TLS variable, so undefined references should not be allowed to + define the value. + + ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one + of the main executable's symbols, as for a COPY reloc. */ +#define elf_machine_type_class(type) \ + ((((type) == R_METAG_JMP_SLOT || (type) == R_METAG_TLS_DTPMOD \ + || (type) == R_METAG_TLS_DTPOFF || (type) == R_METAG_TLS_TPOFF) \ + * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_METAG_COPY) * ELF_RTYPE_CLASS_COPY)) static inline Elf32_Addr elf_machine_dynamic(Elf32_Ehdr *header) diff --git a/ldso/ldso/metag/elfinterp.c b/ldso/ldso/metag/elfinterp.c index 78434167b..e0f981741 100644 --- a/ldso/ldso/metag/elfinterp.c +++ b/ldso/ldso/metag/elfinterp.c @@ -43,43 +43,36 @@ static inline void __put_unaligned_reloc(unsigned long *addr, unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { - int reloc_type; int symtab_index; char *strtab; char *symname; char *new_addr; char *rel_addr; char **got_addr; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; ELF_RELOC *this_reloc; unsigned long instr_addr; rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry); - reloc_type = ELF32_R_TYPE(this_reloc->r_info); - symtab_index = ELF32_R_SYM(this_reloc->r_info); + symtab_index = ELF_R_SYM(this_reloc->r_info); - symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; symname = strtab + symtab[symtab_index].st_name; - if (unlikely(reloc_type != R_METAG_JMP_SLOT)) { - _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", - _dl_progname); - _dl_exit(1); - } - /* Address of the jump instruction to fix up. */ instr_addr = ((unsigned long)this_reloc->r_offset + (unsigned long)tpnt->loadaddr); got_addr = (char **)instr_addr; /* Get the address of the GOT entry. */ - new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, + new_addr = _dl_find_hash(symname, &_dl_loaded_modules->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_dprintf(2, "%s: Can't resolve symbol '%s'\n", + _dl_progname, symname); _dl_exit(1); } @@ -102,28 +95,28 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) } static int -_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size, - int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) + int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) { int symtab_index; unsigned int i; char *strtab; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; ELF_RELOC *rpnt; /* Parse the relocation information. */ rpnt = (ELF_RELOC *)(intptr_t)rel_addr; rel_size /= sizeof(ELF_RELOC); - symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; for (i = 0; i < rel_size; i++, rpnt++) { int res; - symtab_index = ELF32_R_SYM(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); debug_sym(symtab, strtab, symtab_index); debug_reloc(symtab, strtab, rpnt); @@ -141,7 +134,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, strtab + symtab[symtab_index].st_name); if (unlikely(res < 0)) { - int reloc_type = ELF32_R_TYPE(rpnt->r_info); + int reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) _dl_dprintf(2, "can't handle reloc type %s\n", @@ -161,8 +154,8 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +_dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; int symtab_index; @@ -170,30 +163,35 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long *reloc_addr; unsigned long symbol_addr; #if defined (__SUPPORT_LD_DEBUG__) - unsigned long old_val; + unsigned long old_val = 0; #endif + struct elf_resolve *tls_tpnt = NULL; + struct symbol_ref sym_ref; - reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - symtab_index = ELF32_R_SYM(rpnt->r_info); + reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); symbol_addr = 0; - symname = strtab + symtab[symtab_index].st_name; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; if (symtab_index) { - if (symtab[symtab_index].st_shndx != SHN_UNDEF && - ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) { - symbol_addr = (unsigned long)tpnt->loadaddr; - } else { - symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, - elf_machine_type_class(reloc_type), NULL); - } - - if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); - _dl_exit(1); + symname = strtab + symtab[symtab_index].st_name; + symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + if (!symbol_addr + && ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS + && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, symname); + return 1; }; - - symbol_addr += rpnt->r_addend; + if (_dl_trace_prelink) { + _dl_debug_lookup(symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } + tls_tpnt = sym_ref.tpnt; } #if defined (__SUPPORT_LD_DEBUG__) @@ -201,13 +199,21 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, old_val = __get_unaligned_reloc(reloc_addr); #endif +#if defined USE_TLS && USE_TLS + /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous' + symbol. This is the case for a static tls variable, so the lookup + module is just that one is referencing the tls variable. */ + if (!tls_tpnt) + tls_tpnt = tpnt; +#endif switch (reloc_type) { case R_METAG_NONE: break; case R_METAG_GLOB_DAT: case R_METAG_JMP_SLOT: case R_METAG_ADDR32: - __put_unaligned_reloc(reloc_addr, symbol_addr); + __put_unaligned_reloc(reloc_addr, + symbol_addr + rpnt->r_addend); break; case R_METAG_COPY: #if defined (__SUPPORT_LD_DEBUG__) @@ -215,11 +221,12 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, _dl_dprintf(_dl_debug_file, "\t%s move %d bytes from %x to %x\n", symname, symtab[symtab_index].st_size, - symbol_addr, reloc_addr); + symbol_addr + rpnt->r_addend, + reloc_addr); #endif _dl_memcpy((char *)reloc_addr, - (char *)symbol_addr, + (char *)symbol_addr + rpnt->r_addend, symtab[symtab_index].st_size); break; case R_METAG_RELATIVE: @@ -227,13 +234,24 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, (unsigned long)tpnt->loadaddr + rpnt->r_addend); break; +#if defined USE_TLS && USE_TLS + case R_METAG_TLS_DTPMOD: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_METAG_TLS_DTPOFF: + *reloc_addr = symbol_addr; + break; + case R_METAG_TLS_TPOFF: + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend; + break; +#endif default: return -1; /* Calls _dl_exit(1). */ } #if defined (__SUPPORT_LD_DEBUG__) - if (_dl_debug_reloc && _dl_debug_detail && - (reloc_type != R_METAG_NONE)) { + if (_dl_debug_reloc && _dl_debug_detail && reloc_type != R_METAG_NONE) { unsigned long new_val = __get_unaligned_reloc(reloc_addr); _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, new_val, reloc_addr); @@ -244,8 +262,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; unsigned long *reloc_addr; @@ -253,8 +271,8 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long old_val; #endif - reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); + reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) old_val = *reloc_addr; @@ -291,9 +309,10 @@ _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, int _dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) { - return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } diff --git a/ldso/ldso/metag/metag_load_tp.S b/ldso/ldso/metag/metag_load_tp.S new file mode 100644 index 000000000..2f00a9fef --- /dev/null +++ b/ldso/ldso/metag/metag_load_tp.S @@ -0,0 +1,20 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +#include + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + +#include + + .text + .global ___metag_load_tp + .type ___metag_load_tp,@function + +___metag_load_tp: + MOVT D1Ar1,#HI(0x6ffff000) + JUMP D1Ar1,#LO(0x6ffff000) + .size ___metag_load_tp,.-___metag_load_tp + +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index f7083a48b..dbf0b0fd4 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -69,6 +69,7 @@ CSRC- += fork.c getpid.c raise.c #open.c close.c read.c write.c CSRC- += $(if $(findstring =arm=,=$(TARGET_ARCH)=),vfork.c) CSRC- += $(if $(findstring =x86_64=,=$(TARGET_ARCH)=),vfork.c) #CSRC- += $(if $(findstring =mips=y=,=$(TARGET_ARCH)=$(CONFIG_MIPS_O32_ABI)=),waitpid.c) +CSRC- += $(if $(findstring =metag=,=$(TARGET_ARCH)=),vfork.c) endif ifneq ($(ARCH_HAS_DEPRECATED_SYSCALLS),y) # No conversion is needed for new architectures diff --git a/libc/sysdeps/linux/metag/Makefile.arch b/libc/sysdeps/linux/metag/Makefile.arch index 0e6fbfe12..3f11d6da8 100644 --- a/libc/sysdeps/linux/metag/Makefile.arch +++ b/libc/sysdeps/linux/metag/Makefile.arch @@ -7,4 +7,6 @@ CSRC-y := brk.c syscall.c metag.c __syscall_error.c -SSRC-y := _longjmp.S clone.S setjmp.S +SSRC-y := _longjmp.S clone.S setjmp.S vfork.S + +SSRC-$(UCLIBC_HAS_THREADS_NATIVE) += libc-metag_load_tp.S diff --git a/libc/sysdeps/linux/metag/bits/atomic.h b/libc/sysdeps/linux/metag/bits/atomic.h new file mode 100644 index 000000000..64aa50bc4 --- /dev/null +++ b/libc/sysdeps/linux/metag/bits/atomic.h @@ -0,0 +1,66 @@ +/* + * Copyrith (C) 2013 Imagination Technologies Ltd. + * + * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + * + */ + +#include +#include + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + +void __metag_link_error (void); + +#define atomic_full_barrier() \ + __asm__ __volatile__("": : :"memory") + +/* Atomic compare and exchange. This sequence relies on the kernel to + provide a compare and exchange operation which is atomic. */ + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __metag_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __metag_link_error (); oldval; }) + +/* This code uses the kernel helper to do cmpxchg. It relies on the fact + the helper code only clobbers D0Re0. */ +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ({ register __typeof (oldval) a_current __asm__ ("D1Ar1"); \ + register __typeof (oldval) a_newval __asm__ ("D0Ar2") = (newval); \ + register __typeof (mem) a_ptr __asm__ ("D1Ar3") = (mem); \ + register __typeof (oldval) a_oldval __asm__ ("D0Ar4") = (oldval); \ + __asm__ __volatile__ \ + ("0:\n\t" \ + "GETD %[cur], [%[ptr]]\n\t" \ + "CMP %[cur], %[old]\n\t" \ + "BNE 1f\n\t" \ + "MOVT D1RtP, #0x6fff\n\t" \ + "ADD D1RtP, D1RtP, #0xf040\n\t" \ + "SWAP D1RtP, PC\n\t" \ + "MOV %[cur], %[old]\n\t" \ + "CMP D0Re0, #0\n\t" \ + "BNE 0b\n\t" \ + "1:" \ + : [cur] "=&r" (a_current) \ + : [new] "r" (a_newval), [ptr] "r" (a_ptr), \ + [old] "r" (a_oldval) \ + : "D0Re0", "D1RtP", "cc", "memory"); \ + a_current; }) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __metag_link_error (); oldval; }) diff --git a/libc/sysdeps/linux/metag/bits/syscalls.h b/libc/sysdeps/linux/metag/bits/syscalls.h index b5c8fc58c..7ea09c2c3 100644 --- a/libc/sysdeps/linux/metag/bits/syscalls.h +++ b/libc/sysdeps/linux/metag/bits/syscalls.h @@ -49,8 +49,9 @@ (__extension__ \ ({unsigned int __sys_result; \ { \ + PREP_ARGS_##nr (args); \ register int _result __asm__ ("D0Re0"), _nr __asm__ ("D1Re0"); \ - LOAD_ARGS_##nr (args); \ + LOAD_ARGS_##nr; \ _nr = (name); \ __asm__ volatile ("SWITCH #0x440001 ! syscall " #name \ : "=r" (_result) \ @@ -68,32 +69,52 @@ #undef INTERNAL_SYSCALL_ERRNO #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) -#define LOAD_ARGS_0() +#define PREP_ARGS_0() +#define PREP_ARGS_1(a1) \ + int _t1 = (int) (a1); \ + PREP_ARGS_0 () +#define PREP_ARGS_2(a1, a2) \ + int _t2 = (int) (a2); \ + PREP_ARGS_1 (a1) +#define PREP_ARGS_3(a1, a2, a3) \ + int _t3 = (int) (a3); \ + PREP_ARGS_2 (a1, a2) +#define PREP_ARGS_4(a1, a2, a3, a4) \ + int _t4 = (int) (a4); \ + PREP_ARGS_3 (a1, a2, a3) +#define PREP_ARGS_5(a1, a2, a3, a4, a5) \ + int _t5 = (int) (a5); \ + PREP_ARGS_4 (a1, a2, a3, a4) +#define PREP_ARGS_6(a1, a2, a3, a4, a5, a6) \ + int _t6 = (int) (a6); \ + PREP_ARGS_5 (a1, a2, a3, a4, a5) + +#define LOAD_ARGS_0 #define ASM_ARGS_0 -#define LOAD_ARGS_1(a1) \ - register int _a1 __asm__ ("D1Ar1") = (int) (a1); \ - LOAD_ARGS_0 () -#define ASM_ARGS_1 ASM_ARGS_0, "d" (_a1) -#define LOAD_ARGS_2(a1, a2) \ - register int _a2 __asm__ ("D0Ar2") = (int) (a2); \ - LOAD_ARGS_1 (a1) -#define ASM_ARGS_2 ASM_ARGS_1, "d" (_a2) -#define LOAD_ARGS_3(a1, a2, a3) \ - register int _a3 __asm__ ("D1Ar3") = (int) (a3); \ - LOAD_ARGS_2 (a1, a2) -#define ASM_ARGS_3 ASM_ARGS_2, "d" (_a3) -#define LOAD_ARGS_4(a1, a2, a3, a4) \ - register int _a4 __asm__ ("D0Ar4") = (int) (a4); \ - LOAD_ARGS_3 (a1, a2, a3) -#define ASM_ARGS_4 ASM_ARGS_3, "d" (_a4) -#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ - register int _a5 __asm__ ("D1Ar5") = (int) (a5); \ - LOAD_ARGS_4 (a1, a2, a3, a4) -#define ASM_ARGS_5 ASM_ARGS_4, "d" (_a5) -#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ - register int _a6 __asm__ ("D0Ar6") = (int) (a6); \ - LOAD_ARGS_5 (a1, a2, a3, a4, a5) -#define ASM_ARGS_6 ASM_ARGS_5, "d" (_a6) +#define LOAD_ARGS_1 \ + register int _a1 __asm__ ("D1Ar1") = (int) (_t1); \ + LOAD_ARGS_0 +#define ASM_ARGS_1 ASM_ARGS_0, "d" (_a1) +#define LOAD_ARGS_2 \ + register int _a2 __asm__ ("D0Ar2") = (int) (_t2); \ + LOAD_ARGS_1 +#define ASM_ARGS_2 ASM_ARGS_1, "d" (_a2) +#define LOAD_ARGS_3 \ + register int _a3 __asm__ ("D1Ar3") = (int) (_t3); \ + LOAD_ARGS_2 +#define ASM_ARGS_3 ASM_ARGS_2, "d" (_a3) +#define LOAD_ARGS_4 \ + register int _a4 __asm__ ("D0Ar4") = (int) (_t4); \ + LOAD_ARGS_3 +#define ASM_ARGS_4 ASM_ARGS_3, "d" (_a4) +#define LOAD_ARGS_5 \ + register int _a5 __asm__ ("D1Ar5") = (int) (_t5); \ + LOAD_ARGS_4 +#define ASM_ARGS_5 ASM_ARGS_4, "d" (_a5) +#define LOAD_ARGS_6 \ + register int _a6 __asm__ ("D0Ar6") = (int) (_t6); \ + LOAD_ARGS_5 +#define ASM_ARGS_6 ASM_ARGS_5, "d" (_a6) #endif /* __ASSEMBLER__ */ #endif /* _BITS_SYSCALLS_H */ diff --git a/libc/sysdeps/linux/metag/clone.S b/libc/sysdeps/linux/metag/clone.S index 8fff56710..d9d836338 100644 --- a/libc/sysdeps/linux/metag/clone.S +++ b/libc/sysdeps/linux/metag/clone.S @@ -8,7 +8,17 @@ #include #include -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 + +#ifdef __PIC__ +#define __CLONE_METAG_LOAD_TP ___metag_load_tp@PLT +#else +#define __CLONE_METAG_LOAD_TP ___metag_load_tp +#endif + +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + pid_t *ptid, struct user_desc *tls, pid_t *ctid); */ .text .global __clone @@ -25,8 +35,12 @@ __clone: MOV D0FrT, D1Ar1 ! do the system call - ! get flags MOV D1Ar1, D1Ar3 + MOV D1Ar3, D1Ar5 + MOV D1Ar5, D0Ar6 + MOV D0Ar6, D0Ar4 + GETD D0Ar4, [A0StP+#-4] + ! new sp is already in D0Ar2 MOV D1Re0, #__NR_clone SWITCH #0x440001 @@ -38,14 +52,36 @@ __clone: ! BRKPNT ! We are the child - ! pick the function arg and call address off the stack and execute - MOV D0Ar2, D0FrT - MOV D1Ar1, D0Ar4 - MOV D1RtP, PC +#ifdef RESET_PID + SETL [A0StP++], D0FrT, D1RtP + MOVT D0FrT, #HI(CLONE_THREAD) + ADD D0FrT, D0FrT, #LO(CLONE_THREAD) + ANDS D0FrT, D0FrT, D1Ar1 + BNZ 3f + MOVT D0FrT, #HI(CLONE_VM) + ADD D0FrT, D0FrT, #LO(CLONE_VM) + ANDS D0FrT, D0FrT, D1Ar1 + BZ 1f + MOV D1Ar1, #-1 + BA 2f +1: MOV D1Re0, #__NR_getpid + SWITCH #0x440001 + MOV D1Ar1, D0Re0 +2: CALLR D1RtP, __CLONE_METAG_LOAD_TP + SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE + SETD [D0Re0 + #PID], D1Ar1 + SETD [D0Re0 + #TID], D1Ar1 +3: GETL D0FrT, D1RtP, [--A0StP] +#endif + ! Rearrange the function arg and call address from registers + MOV D0Ar2, D0FrT + MOV D1Ar1, D0Ar6 + MOV D1RtP, PC ADD D1RtP, D1RtP, #8 MOV PC, D0Ar2 - ! and we are done, passing the return value through D0Re0 + ! and we are done, passing the return value D0Re0 through D1Ar1 + MOV D1Ar1, D0Re0 #ifdef __PIC__ B _exit@PLT #else diff --git a/libc/sysdeps/linux/metag/crt1.S b/libc/sysdeps/linux/metag/crt1.S index 74adc1fdb..e8561a46b 100644 --- a/libc/sysdeps/linux/metag/crt1.S +++ b/libc/sysdeps/linux/metag/crt1.S @@ -29,6 +29,7 @@ __start: MOV D1Ar3,D0Ar2 ! argv MOV D0Ar2,D1Ar1 ! argc + MOV D0Ar6,D0Ar4 ! rtld_fini #ifdef __PIC__ ADDT A1LbP,CPC1,#HI(__GLOBAL_OFFSET_TABLE__) @@ -54,8 +55,6 @@ __start: ADD D1Ar5,D1Ar5,#LO(__fini) #endif - MOV D0Ar6,#0 ! rtld_fini - MOVT D1Re0,#0x80 SETL [A0StP++],D0Re0,D1Re0 ! stack_end (8Mb) diff --git a/libc/sysdeps/linux/metag/libc-metag_load_tp.S b/libc/sysdeps/linux/metag/libc-metag_load_tp.S new file mode 100644 index 000000000..a91f162ec --- /dev/null +++ b/libc/sysdeps/linux/metag/libc-metag_load_tp.S @@ -0,0 +1,7 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include diff --git a/libc/sysdeps/linux/metag/sysdep.h b/libc/sysdeps/linux/metag/sysdep.h new file mode 100644 index 000000000..a12f393ce --- /dev/null +++ b/libc/sysdeps/linux/metag/sysdep.h @@ -0,0 +1,59 @@ +/* + * Assembler macros for Meta. + * + * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include + +#include +#include + +#ifdef __ASSEMBLER__ + +#ifdef SHARED +#define PLTJMP(_x) _x##@PLT +#else +#define PLTJMP(_x) _x +#endif + +#undef PSEUDO_END +#define PSEUDO_END(name) \ + SYSCALL_ERROR_HANDLER \ + END (name) + +#if defined NOT_IN_libc +# define SYSCALL_ERROR __local_syscall_error +# ifdef RTLD_PRIVATE_ERRNO +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + NEG D0Re0, D0Re0; \ + ADDT D1Re0, CPC1, #HI(_rtld_errno); \ + ADD D1Re0, D1Re0, #LO(_rtld_errno) + 4; \ + SETD [D1Re0], D0Re0; \ + NEG D0Re0, #0x1; \ + MOV PC, D1RtP; +# else +# define SYSCALL_ERROR_HANDLER \ +__local_syscall_error: \ + MOV D1Re0, D1RtP; \ + SETL [A0StP++], D0Re0, D1Re0; \ + CALLR D1RtP, PLTJMP(___errno_location); \ + GETD D1Re0, [A0StP+#-8]; \ + NEG D1Re0, D1Re0; \ + SETD [D0Re0], D1Re0; \ + NEG D0Re0, #0x1; \ + GETD D1RtP, [A0StP+#-4]; \ + SUB A0StP, A0StP, #0x8; \ + MOV PC, D1RtP; +# endif +#else +# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */ +# define SYSCALL_ERROR ___syscall_error +#endif + +#endif /* __ASSEMBLER __*/ + +/* Pointer mangling is not yet supported for META. */ +#define PTR_MANGLE(var) (void) (var) +#define PTR_DEMANGLE(var) (void) (var) diff --git a/libc/sysdeps/linux/metag/vfork.S b/libc/sysdeps/linux/metag/vfork.S new file mode 100644 index 000000000..8573dedd3 --- /dev/null +++ b/libc/sysdeps/linux/metag/vfork.S @@ -0,0 +1,67 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +#include + +#define _ERRNO_H +#include +#include + +#ifndef SAVE_PID +#define SAVE_PID +#endif + +#ifndef RESTORE_PID +#define RESTORE_PID +#endif + +#ifdef __NR_vfork +#define __VFORK_NR __NR_vfork +#else +#define __VFORK_NR __NR_fork +#endif + +/* Clone the calling process, but without copying the whole address space. + The calling process is suspended until the new process exits or is + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + + .balign 4 + .global ___vfork + .hidden ___vfork + .type ___vfork, @function +___vfork: + + SAVE_PID + + MOV D1Ar1, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + MOV D0Ar2, #0 + MOV D1Ar3, #0 + MOV D0Ar4, #0 + MOV D1Ar5, #0 + MOV D0Ar6, #0 + MOV D1Re0, #__NR_clone + SWITCH #0x440001 + + RESTORE_PID + + MOVT D1Re0, #HI(-4096) + ADD D1Re0, D1Re0, #LO(-4096) + CMP D1Re0, D0Re0 + BCS error + + /* Syscall worked. Return to child/parent */ + MOV PC, D1RtP + +error: + MOV D1Ar1, D0Re0 +#ifdef __PIC__ + B ___syscall_error@PLT +#else + B ___syscall_error +#endif + .size ___vfork,.-___vfork + +weak_alias(__vfork,vfork) +libc_hidden_weak(vfork) diff --git a/libpthread/nptl/sysdeps/metag/Makefile.arch b/libpthread/nptl/sysdeps/metag/Makefile.arch new file mode 100644 index 000000000..0a42e686a --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/Makefile.arch @@ -0,0 +1,17 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill +# +# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. +# + +CFLAGS-pthread_spin_init.c = -DNOT_IN_libc -DIS_IN_libpthread +ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc -DIS_IN_libpthread +ASFLAGS-pthread_spin_unlock.S = -DNOT_IN_libc -DIS_IN_libpthread +ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc -DIS_IN_libpthread + +ASFLAGS-pthread_spin_lock.c += -D_GNU_SOURCE + +CFLAGS-metag = $(SSP_ALL_CFLAGS) + +libc_arch_a_CSRC := libc-tls.c diff --git a/libpthread/nptl/sysdeps/metag/dl-tls.h b/libpthread/nptl/sysdeps/metag/dl-tls.h new file mode 100644 index 000000000..cba8fcb3b --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/dl-tls.h @@ -0,0 +1,29 @@ +/* Thread-local storage handling in the ELF dynamic linker. Meta version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +/* Type used for the representation of TLS information in the GOT. */ +typedef struct +{ + unsigned long int ti_module; + unsigned long int ti_offset; +} tls_index; + + +extern void *__tls_get_addr (tls_index *ti); diff --git a/libpthread/nptl/sysdeps/metag/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/metag/jmpbuf-unwind.h new file mode 100644 index 000000000..eedf79427 --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/jmpbuf-unwind.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 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. */ + +#include +#include +#include + +/* Test if longjmp to JMPBUF would unwind the frame + containing a local variable at ADDRESS. */ +#undef _JMPBUF_UNWINDS +#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \ + ((void *) (address) > (void *) demangle (jmpbuf[JB_SP])) + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) > (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) + +#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val) diff --git a/libpthread/nptl/sysdeps/metag/libc-tls.c b/libpthread/nptl/sysdeps/metag/libc-tls.c new file mode 100644 index 000000000..abc7c58db --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/libc-tls.c @@ -0,0 +1,33 @@ +/* + * Thread-local storage handling in statically linked binaries. Meta version. + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * Based on GNU C Library (file: libc/sysdeps/sh/libc-tls.c) + * + * Copyright (C) 2010 STMicroelectronics Ltd. + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Author: Filippo Arcidiacono + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + * + */ + +#include +#include + +#if defined (USE_TLS) && (USE_TLS) + +/* On Meta, linker optimizations are not required, so __tls_get_addr + can be called even in statically linked binaries. In this case module + must be always 1 and PT_TLS segment exist in the binary, otherwise it + would not link. */ + +void * +__tls_get_addr (tls_index *ti) +{ + dtv_t *dtv = THREAD_DTV (); + return (char *) dtv[1].pointer.val + ti->ti_offset; +} + +#endif diff --git a/libpthread/nptl/sysdeps/metag/metag_load_tp.S b/libpthread/nptl/sysdeps/metag/metag_load_tp.S new file mode 100644 index 000000000..f17f7decd --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/metag_load_tp.S @@ -0,0 +1,7 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include <../../../../ldso/ldso/metag/metag_load_tp.S> diff --git a/libpthread/nptl/sysdeps/metag/pthread_spin_init.c b/libpthread/nptl/sysdeps/metag/pthread_spin_init.c new file mode 100644 index 000000000..0a47981aa --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/pthread_spin_init.c @@ -0,0 +1,20 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + 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. */ + +/* Not needed. pthread_spin_init is an alias for pthread_spin_unlock. */ diff --git a/libpthread/nptl/sysdeps/metag/pthread_spin_lock.S b/libpthread/nptl/sysdeps/metag/pthread_spin_lock.S new file mode 100644 index 000000000..66e94c7a9 --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/pthread_spin_lock.S @@ -0,0 +1,20 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + + .text + .global _pthread_spin_lock + .type _pthread_spin_lock,function +_pthread_spin_lock: +1: LNKGETD D0Ar2, [D1Ar1] + CMP D0Ar2, #0 + ADD D0Ar2, D0Ar2, #1 + LNKSETDEQ [D1Ar1], D0Ar2 + BNE 1b + DEFR D0Ar2, TXSTAT + ANDT D0Ar2, D0Ar2, #HI(0x3f000000) + CMPT D0Ar2, #HI(0x02000000) + BNZ 1b + MOV D0Re0, #0 + MOV PC, D1RtP + .size _pthread_spin_lock,.-_pthread_spin_lock diff --git a/libpthread/nptl/sysdeps/metag/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/metag/pthread_spin_trylock.S new file mode 100644 index 000000000..e0b9b5083 --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/pthread_spin_trylock.S @@ -0,0 +1,24 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +#include + + .text + .global _pthread_spin_trylock + .type _pthread_spin_trylock,function +_pthread_spin_trylock: +1: MOVT D0Re0, #HI(#EBUSY) + ADD D0Re0, D0Re0, #LO(#EBUSY) + LNKGETD D0Ar2, [D1Ar1] + CMP D0Ar2, #0 + ADD D0Ar2, D0Ar2, #1 + LNKSETDEQ [D1Ar1], D0Ar2 + BNE 2f + DEFR D0Ar2, TXSTAT + ANDT D0Ar2, D0Ar2, #HI(0x3f000000) + CMPT D0Ar2, #HI(0x02000000) + BNZ 1b + MOV D0Re0, #0 +2: MOV PC, D1RtP + .size _pthread_spin_trylock,.-_pthread_spin_trylock diff --git a/libpthread/nptl/sysdeps/metag/pthread_spin_unlock.S b/libpthread/nptl/sysdeps/metag/pthread_spin_unlock.S new file mode 100644 index 000000000..9bd95e675 --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/pthread_spin_unlock.S @@ -0,0 +1,16 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + + .text + .global _pthread_spin_unlock + .type _pthread_spin_unlock,function +_pthread_spin_unlock: + MOV D0Re0, #0 + SETD [D1Ar1], D0Re0 + MOV PC, D1RtP + .size _pthread_spin_unlock,.-_pthread_spin_unlock + + /* The implementation of pthread_spin_init is identical. */ + .global _pthread_spin_init +_pthread_spin_init = _pthread_spin_unlock diff --git a/libpthread/nptl/sysdeps/metag/pthreaddef.h b/libpthread/nptl/sysdeps/metag/pthreaddef.h new file mode 100644 index 000000000..51625e4e6 --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/pthreaddef.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +/* Default stack size. */ +#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024) + +/* Required stack pointer alignment at beginning. */ +#define STACK_ALIGN 8 + +/* Minimal stack size after allocating thread descriptor and guard size. */ +#define MINIMAL_REST_STACK 2048 + +/* Alignment requirement for TCB. */ +#define TCB_ALIGNMENT 8 + + +/* Location of current stack frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* XXX Until we have a better place keep the definitions here. */ +#define __exit_thread_inline(val) \ + INLINE_SYSCALL (exit, 1, (val)) diff --git a/libpthread/nptl/sysdeps/metag/tcb-offsets.sym b/libpthread/nptl/sysdeps/metag/tcb-offsets.sym new file mode 100644 index 000000000..753b72b2d --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/tcb-offsets.sym @@ -0,0 +1,15 @@ +#include +#include + +RESULT offsetof (struct pthread, result) +TID offsetof (struct pthread, tid) +PID offsetof (struct pthread, pid) +CANCELHANDLING offsetof (struct pthread, cancelhandling) +CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) +MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +TLS_PRE_TCB_SIZE sizeof (struct pthread) +MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) +POINTER_GUARD offsetof (tcbhead_t, pointer_guard) +#ifndef __ASSUME_PRIVATE_FUTEX +PRIVATE_FUTEX offsetof (struct pthread, header.private_futex) +#endif diff --git a/libpthread/nptl/sysdeps/metag/tls.h b/libpthread/nptl/sysdeps/metag/tls.h new file mode 100644 index 000000000..07702beca --- /dev/null +++ b/libpthread/nptl/sysdeps/metag/tls.h @@ -0,0 +1,163 @@ +/* Definition for thread-local data handling. NPTL/Meta version. + Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ +# include +# include +# include +# include +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + +typedef struct +{ + dtv_t *dtv; + uintptr_t pointer_guard; +} tcbhead_t; + +# define TLS_MULTIPLE_THREADS_IN_TCB 1 + +#else /* __ASSEMBLER__ */ +# include +#endif /* __ASSEMBLER__ */ + + +/* We require TLS support in the tools. */ +#define HAVE_TLS_SUPPORT +#define HAVE___THREAD 1 +#define HAVE_TLS_MODEL_ATTRIBUTE 1 +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +#ifndef __ASSEMBLER__ + +/* Get system call information. */ +# include + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (tcbhead_t) + +/* This is the size we need before TCB. */ +# define TLS_PRE_TCB_SIZE sizeof (struct pthread) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct pthread) + +/* The TLS blocks start right after the TCB. */ +# define TLS_DTV_AT_TP 1 + +/* Get the thread descriptor definition. */ +# include + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(tcbp, dtvp) \ + ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + (((tcbhead_t *)__builtin_thread_pointer ())->dtv = (dtv)) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(tcbp) \ + (((tcbhead_t *) (tcbp))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(tcbp, secondcall) \ + ({ INTERNAL_SYSCALL_DECL (err); \ + long result_var; \ + result_var = INTERNAL_SYSCALL (metag_set_tls, err, 1, (tcbp)); \ + INTERNAL_SYSCALL_ERROR_P (result_var, err) \ + ? "unknown error" : NULL; }) + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + (((tcbhead_t *)__builtin_thread_pointer ())->dtv) + +/* Return the thread descriptor for the current thread. + The contained asm must *not* be marked volatile since otherwise + assignments like + struct pthread *self = thread_self(); + do not get optimized away. */ +# define THREAD_SELF \ + ((struct pthread *)__builtin_thread_pointer () - 1) + +/* Magic for libthread_db to know how to do THREAD_SELF. */ +# define DB_THREAD_SELF \ + CONST_THREAD_AREA (32, sizeof (struct pthread)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + descr->member +#define THREAD_GETMEM_NC(descr, member, idx) \ + descr->member[idx] +#define THREAD_SETMEM(descr, member, value) \ + descr->member = (value) +#define THREAD_SETMEM_NC(descr, member, idx, value) \ + descr->member[idx] = (value) + +/* Get and set the global scope generation counter in struct pthread. */ +#define THREAD_GSCOPE_FLAG_UNUSED 0 +#define THREAD_GSCOPE_FLAG_USED 1 +#define THREAD_GSCOPE_FLAG_WAIT 2 +#define THREAD_GSCOPE_RESET_FLAG() \ + do \ + { int __res \ + = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \ + THREAD_GSCOPE_FLAG_UNUSED); \ + if (__res == THREAD_GSCOPE_FLAG_WAIT) \ + lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \ + } \ + while (0) +#define THREAD_GSCOPE_SET_FLAG() \ + do \ + { \ + THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \ + atomic_write_barrier (); \ + } \ + while (0) +#define THREAD_GSCOPE_WAIT() \ + GL(dl_wait_lookup_done) () + +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile new file mode 100644 index 000000000..729adf6f9 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile @@ -0,0 +1,13 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2005 Steven J. Hill +# +# Licensed under the LGPL v2.1 or later, 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/metag/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile.arch new file mode 100644 index 000000000..bcee1685c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile.arch @@ -0,0 +1,34 @@ +# Makefile for uClibc NPTL +# +# Copyright (C) 2006 Steven J. Hill +# +# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. +# + +libpthread_linux_arch_SSRC = pt-vfork.S +libpthread_linux_arch_CSRC = pthread_once.c \ + pt-__syscall_rt_sigaction.c pt-__syscall_error.c \ + lowlevellock.c + +libc_linux_arch_CSRC = fork.c libc-lowlevellock.c +libc_linux_arch_SSRC = clone.S vfork.S +libc_linux_arch_SSRC-OMIT = waitpid.S + +CFLAGS += $(SSP_ALL_CFLAGS) + +CFLAGS-pthread_once.c = -DNOT_IN_libc -DIS_IN_libpthread +CFLAGS-pt-__syscall_rt_sigaction.c = -DNOT_IN_libc -DIS_IN_libpthread +CFLAGS-lowlevellock.c = -DNOT_IN_libc -DIS_IN_libpthread +CFLAGS-pt-__syscall_error.c = -DNOT_IN_libc -DIS_IN_libpthread +ASFLAGS-vfork.S = -DIS_IN_libc -DNOT_IN_libpthread +ASFLAGS-clone.S = -DIS_IN_libc -DNOT_IN_libpthread +ASFLAGS-pt-vfork.S = -DNOT_IN_libc -DIS_IN_libpthread + +ifeq ($(UCLIBC_HAS_STDIO_FUTEXES),y) +CFLAGS-fork.c = -D__USE_STDIO_FUTEXES__ +endif +CFLAGS-OMIT-fork.c = -DNOT_IN_libc -DIS_IN_libpthread +CFLAGS-OMIT-libc-lowlevellock.c = -DNOT_IN_libc -DIS_IN_libpthread +# We always compile it in arm mode because of SAVE_PID macro +# This macro should be alternatively implemented in THUMB +# assembly. diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/pthreadtypes.h new file mode 100644 index 000000000..e1b115c8c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/pthreadtypes.h @@ -0,0 +1,181 @@ +/* Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#include + +#define __SIZEOF_PTHREAD_ATTR_T 36 +#define __SIZEOF_PTHREAD_MUTEX_T 24 +#define __SIZEOF_PTHREAD_MUTEXATTR_T 4 +#define __SIZEOF_PTHREAD_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 +#define __SIZEOF_PTHREAD_CONDATTR_T 4 +#define __SIZEOF_PTHREAD_RWLOCK_T 32 +#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 +#define __SIZEOF_PTHREAD_BARRIER_T 20 +#define __SIZEOF_PTHREAD_BARRIERATTR_T 4 + + +/* Thread identifiers. The structure of the attribute type is not + exposed on purpose. */ +typedef unsigned long int pthread_t; + + +typedef union +{ + char __size[__SIZEOF_PTHREAD_ATTR_T]; + long int __align; +} pthread_attr_t; + + +typedef struct __pthread_internal_slist +{ + struct __pthread_internal_slist *__next; +} __pthread_slist_t; + + +/* Data structures for mutex handling. The structure of the attribute + type is not exposed on purpose. */ +typedef union +{ + struct __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + /* KIND must stay at this position in the structure to maintain + binary compatibility. */ + int __kind; + unsigned int __nusers; + __extension__ union + { + int __spins; + __pthread_slist_t __list; + }; + } __data; + char __size[__SIZEOF_PTHREAD_MUTEX_T]; + long int __align; +} pthread_mutex_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_MUTEXATTR_T]; + long int __align; +} pthread_mutexattr_t; + + +/* Data structure for conditional variable handling. The structure of + the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __futex; + __extension__ unsigned long long int __total_seq; + __extension__ unsigned long long int __wakeup_seq; + __extension__ unsigned long long int __woken_seq; + void *__mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[__SIZEOF_PTHREAD_COND_T]; + __extension__ long long int __align; +} pthread_cond_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_CONDATTR_T]; + long int __align; +} pthread_condattr_t; + + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Data structure for read-write lock variable handling. The + structure of the attribute type is not exposed on purpose. */ +typedef union +{ + struct + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned char __pad1; + unsigned char __pad2; + unsigned char __shared; + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned char __flags; +#else + /* FLAGS must stay at this position in the structure to maintain + binary compatibility. */ + unsigned char __flags; + unsigned char __shared; + unsigned char __pad1; + unsigned char __pad2; +#endif + int __writer; + } __data; + char __size[__SIZEOF_PTHREAD_RWLOCK_T]; + long int __align; +} pthread_rwlock_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T]; + long int __align; +} pthread_rwlockattr_t; +#endif + + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + + +/* POSIX barriers data type. The structure of the type is + deliberately not exposed. */ +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIER_T]; + long int __align; +} pthread_barrier_t; + +typedef union +{ + char __size[__SIZEOF_PTHREAD_BARRIERATTR_T]; + int __align; +} pthread_barrierattr_t; +#endif + + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/semaphore.h new file mode 100644 index 000000000..dadfac2af --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/semaphore.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2002, 2005, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _SEMAPHORE_H +# error "Never use directly; include instead." +#endif + + +#define __SIZEOF_SEM_T 16 + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + + +typedef union +{ + char __size[__SIZEOF_SEM_T]; + long int __align; +} sem_t; diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/clone.S new file mode 100644 index 000000000..f5c5c7c5d --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/clone.S @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#define RESET_PID +#include +#include "../../../../../../../libc/sysdeps/linux/metag/clone.S" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/createthread.c new file mode 100644 index 000000000..2d4355980 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/createthread.c @@ -0,0 +1,23 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* Value passed to 'clone' for initialization of the thread register. */ +#define TLS_VALUE (pd + 1) + +/* Get the real implementation. */ +#include diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/fork.c new file mode 100644 index 000000000..41776f9bc --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/fork.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Phil Blundell , 2005 + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + + +#define ARCH_FORK() \ + INLINE_SYSCALL (clone, 5, \ + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \ + NULL, NULL, &THREAD_SELF->tid, NULL) + +#include "../fork.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/libc-lowlevellock.c new file mode 100644 index 000000000..b19282281 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/libc-lowlevellock.c @@ -0,0 +1,21 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Paul Mackerras , 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. */ + +/* No difference to lowlevellock.c, except we lose a couple of functions. */ +#include "lowlevellock.c" diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.c new file mode 100644 index 000000000..8c8955e05 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.c @@ -0,0 +1,134 @@ +/* low level locking for pthread library. Generic futex-using version. + Copyright (C) 2003, 2005, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + +void +__lll_lock_wait_private (int *futex) +{ + do + { + int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_wait (futex, 2, LLL_PRIVATE); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +/* These functions don't get included in libc.so */ +#ifdef IS_IN_libpthread +void +__lll_lock_wait (int *futex, int private) +{ + do + { + int oldval = atomic_compare_and_exchange_val_acq (futex, 2, 1); + if (oldval != 0) + lll_futex_wait (futex, 2, private); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); +} + + +int +__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private) +{ + struct timespec rt; + + /* Reject invalid timeouts. */ + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Upgrade the lock. */ + if (atomic_exchange_acq (futex, 2) == 0) + return 0; + + do + { + struct timeval tv; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + // XYZ: Lost the lock to check whether it was private. + lll_futex_timed_wait (futex, 2, &rt, private); + } + while (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0); + + return 0; +} + + +int +__lll_timedwait_tid (int *tidp, const struct timespec *abstime) +{ + int tid; + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) + return EINVAL; + + /* Repeat until thread terminated. */ + while ((tid = *tidp) != 0) + { + struct timeval tv; + struct timespec rt; + + /* Get the current time. */ + (void) gettimeofday (&tv, NULL); + + /* Compute relative timeout. */ + rt.tv_sec = abstime->tv_sec - tv.tv_sec; + rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000; + if (rt.tv_nsec < 0) + { + rt.tv_nsec += 1000000000; + --rt.tv_sec; + } + + /* Already timed out? */ + if (rt.tv_sec < 0) + return ETIMEDOUT; + + /* Wait until thread terminates. */ + // XYZ: Lost the lock to check whether it was private. + if (lll_futex_timed_wait (tidp, tid, &rt, LLL_SHARED) == -ETIMEDOUT) + return ETIMEDOUT; + } + + return 0; +} +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.h new file mode 100644 index 000000000..99ada5d50 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.h @@ -0,0 +1,279 @@ +/* Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _LOWLEVELLOCK_H +#define _LOWLEVELLOCK_H 1 + +#include +#include +#include +#include +#include +#include + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE ((4 << 24) | 1) +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 +#define FUTEX_WAIT_BITSET 9 +#define FUTEX_WAKE_BITSET 10 +#define FUTEX_PRIVATE_FLAG 128 +#define FUTEX_CLOCK_REALTIME 256 + +#define FUTEX_BITSET_MATCH_ANY 0xffffffff + +/* Values for 'private' parameter of locking macros. Yes, the + definition seems to be backwards. But it is not. The bit will be + reversed before passing to the system call. */ +#define LLL_PRIVATE 0 +#define LLL_SHARED FUTEX_PRIVATE_FLAG + + +#if !defined NOT_IN_libc || defined IS_IN_rtld +/* In libc.so or ld.so all futexes are private. */ +# ifdef __ASSUME_PRIVATE_FUTEX +# define __lll_private_flag(fl, private) \ + ((fl) | FUTEX_PRIVATE_FLAG) +# else +# define __lll_private_flag(fl, private) \ + ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) +# endif +#else +# ifdef __ASSUME_PRIVATE_FUTEX +# define __lll_private_flag(fl, private) \ + (((fl) | FUTEX_PRIVATE_FLAG) ^ (private)) +# else +# define __lll_private_flag(fl, private) \ + (__builtin_constant_p (private) \ + ? ((private) == 0 \ + ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex)) \ + : (fl)) \ + : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG) \ + & THREAD_GETMEM (THREAD_SELF, header.private_futex)))) +# endif +#endif + + +#define lll_futex_wait(futexp, val, private) \ + lll_futex_timed_wait(futexp, val, NULL, private) + +#define lll_futex_timed_wait(futexp, val, timespec, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + __lll_private_flag (FUTEX_WAIT, private), \ + (val), (timespec)); \ + __ret; \ + }) + +#define lll_futex_wake(futexp, nr, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp), \ + __lll_private_flag (FUTEX_WAKE, private), \ + (nr), 0); \ + __ret; \ + }) + +#define lll_robust_dead(futexv, private) \ + do \ + { \ + int *__futexp = &(futexv); \ + atomic_or (__futexp, FUTEX_OWNER_DIED); \ + lll_futex_wake (__futexp, 1, private); \ + } \ + while (0) + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (FUTEX_CMP_REQUEUE, private),\ + (nr_wake), (nr_move), (mutex), (val)); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +/* Returns non-zero if error happened, zero if success. */ +#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \ + ({ \ + INTERNAL_SYSCALL_DECL (__err); \ + long int __ret; \ + __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \ + __lll_private_flag (FUTEX_WAKE_OP, private), \ + (nr_wake), (nr_wake2), (futexp2), \ + FUTEX_OP_CLEAR_WAKE_IF_GT_ONE); \ + INTERNAL_SYSCALL_ERROR_P (__ret, __err); \ + }) + + +#define lll_trylock(lock) \ + atomic_compare_and_exchange_val_acq(&(lock), 1, 0) + +#define lll_cond_trylock(lock) \ + atomic_compare_and_exchange_val_acq(&(lock), 2, 0) + +#define __lll_robust_trylock(futex, id) \ + (atomic_compare_and_exchange_val_acq (futex, id, 0) != 0) +#define lll_robust_trylock(lock, id) \ + __lll_robust_trylock (&(lock), id) + +extern void __lll_lock_wait_private (int *futex) attribute_hidden; +extern void __lll_lock_wait (int *futex, int private) attribute_hidden; +extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden; + +#define __lll_lock(futex, private) \ + ((void) ({ \ + int *__futex = (futex); \ + if (unlikely(atomic_compare_and_exchange_val_acq (__futex, 1, 0))) \ + { \ + if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \ + __lll_lock_wait_private (__futex); \ + else \ + __lll_lock_wait (__futex, private); \ + } \ + })) +#define lll_lock(futex, private) __lll_lock (&(futex), private) + + +#define __lll_robust_lock(futex, id, private) \ + ({ \ + int *__futex = (futex); \ + int __val = 0; \ + \ + if (unlikely(atomic_compare_and_exchange_bool_acq (__futex, id, 0))) \ + __val = __lll_robust_lock_wait (__futex, private); \ + __val; \ + }) +#define lll_robust_lock(futex, id, private) \ + __lll_robust_lock (&(futex), id, private) + + +#define __lll_cond_lock(futex, private) \ + ((void) ({ \ + int *__futex = (futex); \ + if (unlikely(atomic_exchange_acq (__futex, 2))) \ + __lll_lock_wait (__futex, private); \ + })) +#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private) + + +#define lll_robust_cond_lock(futex, id, private) \ + __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private) + + +extern int __lll_timedlock_wait (int *futex, const struct timespec *, + int private) attribute_hidden; +extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *, + int private) attribute_hidden; + +#define __lll_timedlock(futex, abstime, private) \ + ({ \ + int *__futex = (futex); \ + int __val = 0; \ + \ + if (unlikely(atomic_exchange_acq (__futex, 1))) \ + __val = __lll_timedlock_wait (__futex, abstime, private); \ + __val; \ + }) +#define lll_timedlock(futex, abstime, private) \ + __lll_timedlock (&(futex), abstime, private) + + +#define __lll_robust_timedlock(futex, abstime, id, private) \ + ({ \ + int *__futex = (futex); \ + int __val = 0; \ + \ + if (unlikely(atomic_compare_and_exchange_bool_acq (__futex, id, 0))) \ + __val = __lll_robust_timedlock_wait (__futex, abstime, private); \ + __val; \ + }) +#define lll_robust_timedlock(futex, abstime, id, private) \ + __lll_robust_timedlock (&(futex), abstime, id, private) + + +#define __lll_unlock(futex, private) \ + (void) \ + ({ int *__futex = (futex); \ + int __oldval = atomic_exchange_rel (__futex, 0); \ + if (unlikely(__oldval > 1)) \ + lll_futex_wake (__futex, 1, private); \ + }) +#define lll_unlock(futex, private) __lll_unlock(&(futex), private) + + +#define __lll_robust_unlock(futex, private) \ + (void) \ + ({ int *__futex = (futex); \ + int __oldval = atomic_exchange_rel (__futex, 0); \ + if (unlikely(__oldval & FUTEX_WAITERS)) \ + lll_futex_wake (__futex, 1, private); \ + }) +#define lll_robust_unlock(futex, private) \ + __lll_robust_unlock(&(futex), private) + + +#define lll_islocked(futex) \ + (futex != 0) + + +/* Our internal lock implementation is identical to the binary-compatible + mutex implementation. */ + +/* Initializers for lock. */ +#define LLL_LOCK_INITIALIZER (0) +#define LLL_LOCK_INITIALIZER_LOCKED (1) + +/* The states of a lock are: + 0 - untaken + 1 - taken by one user + >1 - taken by more users */ + +/* The kernel notifies a process which uses CLONE_CLEARTID via futex + wakeup when the clone terminates. The memory location contains the + thread ID while the clone is running and is reset to zero + afterwards. */ +#define lll_wait_tid(tid) \ + do { \ + __typeof (tid) __tid; \ + while ((__tid = (tid)) != 0) \ + lll_futex_wait (&(tid), __tid, LLL_SHARED);\ + } while (0) + +extern int __lll_timedwait_tid (int *, const struct timespec *) + attribute_hidden; + +#define lll_timedwait_tid(tid, abstime) \ + ({ \ + int __res = 0; \ + if ((tid) != 0) \ + __res = __lll_timedwait_tid (&(tid), (abstime)); \ + __res; \ + }) + +#endif /* lowlevellock.h */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_error.c new file mode 100644 index 000000000..8f97734e5 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_error.c @@ -0,0 +1,7 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include <../../../../../../../libc/sysdeps/linux/metag/__syscall_error.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_rt_sigaction.c new file mode 100644 index 000000000..18769cac7 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_rt_sigaction.c @@ -0,0 +1,7 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include <../../../../../../../libc/sysdeps/linux/common/__syscall_rt_sigaction.c> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-gettimeofday.c new file mode 100644 index 000000000..4dcb8b564 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-gettimeofday.c @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + */ + +#include +#include + +int gettimeofday (struct timeval *, struct timezone *) attribute_hidden; +_syscall2(int, gettimeofday, struct timeval *, tv, struct timezone *, tz); diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-vfork.S new file mode 100644 index 000000000..489c74936 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-vfork.S @@ -0,0 +1,51 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#ifdef __PIC__ +#define __VFORK_METAG_LOAD_TP ___metag_load_tp@PLT +#else +#define __VFORK_METAG_LOAD_TP ___metag_load_tp +#endif + +/* Save the PID value. */ +#define SAVE_PID \ + SETL [A0StP++], D0FrT, D1RtP; \ + CALLR D1RtP, __VFORK_METAG_LOAD_TP; \ + SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE; \ + GETD D0FrT, [D0Re0 + #PID]; \ + NEG D0FrT, D0FrT; \ + SETD [D0Re0 + #PID], D0FrT; \ + GETL D0FrT, D1RtP, [--A0StP]; + +#define RESTORE_PID \ + CMP D0Re0, #0; \ + BEQ 1f; \ + MSETL [A0StP++], D0Re0, D0FrT; \ + CALLR D1RtP, __VFORK_METAG_LOAD_TP; \ + SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE; \ + GETD D0FrT, [D0Re0 + #PID]; \ + NEG D0FrT, D0FrT; \ + SETD [D0Re0 + #PID], D0FrT; \ + GETL D0FrT, D1RtP, [--A0StP]; \ + GETL D0Re0, D1Re0, [--A0StP]; \ +1: + +#include <../../../../../../../libc/sysdeps/linux/metag/vfork.S> diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pthread_once.c new file mode 100644 index 000000000..e977a7d0c --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/pthread_once.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "pthreadP.h" +#include + +unsigned long int __fork_generation attribute_hidden; + +static void +clear_once_control (void *arg) +{ + pthread_once_t *once_control = (pthread_once_t *) arg; + + *once_control = 0; + lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); +} + +int +attribute_protected +__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +{ + for (;;) + { + int oldval; + int newval; + + /* Pseudo code: + newval = __fork_generation | 1; + oldval = *once_control; + if ((oldval & 2) == 0) + *once_control = newval; + Do this atomically. + */ + do + { + newval = __fork_generation | 1; + oldval = *once_control; + if (oldval & 2) + break; + } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval); + + /* Check if the initializer has already been done. */ + if ((oldval & 2) != 0) + return 0; + + /* Check if another thread already runs the initializer. */ + if ((oldval & 1) == 0) + break; + + /* Check whether the initializer execution was interrupted by a fork. */ + if (oldval != newval) + break; + + /* Same generation, some other thread was faster. Wait. */ + lll_futex_wait (once_control, oldval, LLL_PRIVATE); + } + + /* This thread is the first here. Do the initialization. + Register a cleanup handler so that in case the thread gets + interrupted the initialization can be restarted. */ + pthread_cleanup_push (clear_once_control, once_control); + + init_routine (); + + pthread_cleanup_pop (0); + + /* Say that the initialisation is done. */ + *once_control = __fork_generation | 2; + + /* Wake up all other threads. */ + lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE); + + return 0; +} +weak_alias (__pthread_once, pthread_once) +strong_alias (__pthread_once, __pthread_once_internal) + +#if defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__PIC__) +/* When statically linked, if pthread_create is used, this file + will be brought in. The exception handling code in GCC assumes + that if pthread_create is available, so are these. */ +const void *include_pthread_getspecific attribute_hidden = pthread_getspecific; +const void *include_pthread_setspecific attribute_hidden = pthread_setspecific; +const void *include_pthread_key_create attribute_hidden = pthread_key_create; +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/sysdep-cancel.h new file mode 100644 index 000000000..0be330b73 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/sysdep-cancel.h @@ -0,0 +1,152 @@ +/* Copyright (C) 2003, 2004, 2005, 2009 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#ifndef __ASSEMBLER__ +# include +#endif + +#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt + +/* NOTE: We do mark syscalls with unwind annotations, for the benefit of + cancellation; but they're really only accurate at the point of the + syscall. The ARM unwind directives are not rich enough without adding + a custom personality function. */ + +#ifdef __ASSEMBLER__ +#undef ret +#define ret \ + CMP D0Re0, #-4095; \ + MOVLO PC, D1RtP; \ + MOV D1Ar1, D0Re0; \ + B SYSCALL_ERROR; +#endif /* __ASSEMBLER__ */ + +# undef PSEUDO +# define PSEUDO(name, syscall_name, args) \ + .section ".text"; \ + .type ___##syscall_name##_nocancel,%function; \ + .globl ___##syscall_name##_nocancel; \ + ___##syscall_name##_nocancel: \ + cfi_startproc; \ + DO_CALL (syscall_name, args); \ + MOV PC, D1RtP; \ + cfi_endproc; \ + .size ___##syscall_name##_nocancel,.-___##syscall_name##_nocancel; \ + .globl _##name; \ + .type _##name, @function; \ +name##: \ +_##name##: \ + DOCARGS_##args; \ + SINGLE_THREAD_P; \ + UNDOCARGS_##args; \ + BNE .Lpseudo_cancel; \ + cfi_remember_state; \ + DO_CALL (syscall_name, 0); \ + ret \ + cfi_restore_state; \ + .Lpseudo_cancel: \ + MSETL [A0StP++], D0FrT, D0.5; \ + DOCARGS_##args; /* save syscall args etc. around CENABLE. */ \ + CENABLE; \ + MOV D0FrT, D0Re0; /* put mask in safe place. */ \ + UNDOCARGS_##args; /* restore syscall args. */ \ + DO_CALL(syscall_name, 0); /* do the call. */ \ + MOV D0.5, D0Re0; /* save syscall return value. */ \ + MOV D1Ar1, D0FrT; /* get mask back. */ \ + CDISABLE; \ + MOV D0Re0, D0.5; /* retrieve return value. */ \ + GETL D0.5, D1.5, [--A0StP]; \ + GETL D0FrT, D1RtP, [--A0StP]; + +# define DOCARGS_0 +# define UNDOCARGS_0 + +# define DOCARGS_1 \ + SETL [A0StP++], D1Ar1, D0Ar2 +# define UNDOCARGS_1 \ + GETL D1Ar1, D0Ar2, [--A0StP] + +# define DOCARGS_2 DOCARGS_1 + +# define UNDOCARGS_2 UNDOCARGS_2 + +# define DOCARGS_3 \ + MSETL [A0StP++], D1Ar1, D1Ar3 + +# define UNDOCARGS_3 \ + GETL D1Ar1, D0Ar2, [--A0StP]; \ + GETL D1Ar3, D0Ar4, [--A0StP] + +# define DOCARGS_4 DOCARGS_3 +# define UNDOCARGS_4 UNDOCARGS_3 + +# define DOCARGS_5 \ + MSETL [A0StP++], D1Ar1, D1Ar3, D1Ar5 +# define UNDOCARGS_5 \ + GETL D1Ar1, D0Ar2, [--A0StP]; \ + GETL D1Ar3, D0Ar4, [--A0StP]; \ + GETL D1Ar5, D0Ar6, [--A0StP] + +# define DOCARGS_6 DOCARGS_5 +# define UNDOCARGS_6 UNDOCARGS_5 + +# ifdef IS_IN_libpthread +# define CENABLE CALLR D1RtP, ___pthread_enable_asynccancel@PLT +# define CDISABLE CALLR D1RtP, ___pthread_disable_asynccancel@PLT +# define __local_multiple_threads __pthread_multiple_threads +# elif !defined NOT_IN_libc +# define CENABLE CALLR D1RtP, ___libc_enable_asynccancel@PLT +# define CDISABLE CALLR D1RtP, ___libc_disable_asynccancel@PLT +# define __local_multiple_threads __libc_multiple_threads +# elif defined IS_IN_librt +# define CENABLE CALLR D1RtP, ___librt_enable_asynccancel@PLT +# define CDISABLE CALLR D1RtP, ___librt_disable_asynccancel@PLT +# else +# error Unsupported library +# endif + +#ifndef __ASSEMBLER__ +# define SINGLE_THREAD_P \ + likely(THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0) +#else +# define SINGLE_THREAD_P \ + SETL [A0StP++], D0FrT, D1RtP; \ + CALLR D1RtP, ___metag_load_tp@PLT; \ + SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE; \ + GETD D0Re0, [D0Re0 + #MULTIPLE_THREADS_OFFSET]; \ + CMP D0Re0, #0; \ + GETL D0FrT, D1RtP, [--A0StP] +#endif + + +#elif !defined __ASSEMBLER__ + +/* For rtld, et cetera. */ +# define SINGLE_THREAD_P 1 +# define NO_CANCELLATION 1 + +#endif + +#ifndef __ASSEMBLER__ +# define RTLD_SINGLE_THREAD_P \ + likely(THREAD_GETMEM (THREAD_SELF, \ + header.multiple_threads) == 0) +#endif diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/metag/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/vfork.S new file mode 100644 index 000000000..51fcfbbe4 --- /dev/null +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/metag/vfork.S @@ -0,0 +1,56 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#ifdef __PIC__ +#define __VFORK_METAG_LOAD_TP ___metag_load_tp@PLT +#else +#define __VFORK_METAG_LOAD_TP ___metag_load_tp +#endif + +/* Save the PID value. */ +#define SAVE_PID \ + SETL [A0StP++], D0FrT, D1RtP; \ + CALLR D1RtP, __VFORK_METAG_LOAD_TP; \ + SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE; \ + GETD D0FrT, [D0Re0 + #PID]; \ + NEGS D0FrT, D0FrT; \ + BNZ 1f; \ + MOVT D0FrT, #0x8000; \ +1: SETD [D0Re0 + #PID], D0FrT; \ + GETL D0FrT, D1RtP, [--A0StP]; + +#define RESTORE_PID \ + CMP D0Re0, #0; \ + BEQ 1f; \ + MSETL [A0StP++], D0Re0, D0FrT; \ + CALLR D1RtP, __VFORK_METAG_LOAD_TP; \ + SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE; \ + GETD D0FrT, [D0Re0 + #PID]; \ + NEG D0FrT, D0FrT; \ + MOVT D1Re0, #0x8000; \ + CMP D0FrT, D1Re0; \ + XOREQ D0FrT, D0FrT, D0FrT; \ + SETD [D0Re0 + #PID], D0FrT; \ + GETL D0FrT, D1RtP, [--A0StP]; \ + GETL D0Re0, D1Re0, [--A0StP]; \ +1: + +#include <../../../../../../../libc/sysdeps/linux/metag/vfork.S> -- cgit v1.2.3