[PATCH 2/5] NPTL: ARC support

Vineet Gupta Vineet.Gupta1 at synopsys.com
Fri Jul 25 12:09:05 UTC 2014


Signed-off-by: Vineet Gupta <vgupta at synopsys.com>
---
 extra/Configs/defconfigs/arc/defconfig             |   2 +-
 include/elf.h                                      |  12 +-
 ldso/ldso/arc/dl-debug.h                           |  15 ++
 ldso/ldso/arc/dl-sysdep.h                          |   9 +-
 ldso/ldso/arc/elfinterp.c                          |  26 +-
 libc/sysdeps/linux/arc/bits/atomic.h               |  57 +++++
 libc/sysdeps/linux/arc/clone.S                     |  36 ++-
 libc/sysdeps/linux/arc/jmpbuf-unwind.h             |  17 ++
 libc/sysdeps/linux/arc/sysdep.h                    |   4 +
 libc/sysdeps/linux/arc/vfork.S                     |  13 +
 libpthread/nptl/sysdeps/arc/Makefile.arch          |  13 +
 libpthread/nptl/sysdeps/arc/dl-tls.h               |  28 +++
 libpthread/nptl/sysdeps/arc/jmpbuf-unwind.h        |  32 +++
 libpthread/nptl/sysdeps/arc/libc-tls.c             |  27 ++
 libpthread/nptl/sysdeps/arc/pthread_spin_lock.S    |  21 ++
 libpthread/nptl/sysdeps/arc/pthread_spin_trylock.S |  31 +++
 libpthread/nptl/sysdeps/arc/pthreaddef.h           |  40 +++
 libpthread/nptl/sysdeps/arc/tcb-offsets.sym        |   8 +
 libpthread/nptl/sysdeps/arc/tls.h                  | 160 ++++++++++++
 .../nptl/sysdeps/unix/sysv/linux/arc/Makefile      |  13 +
 .../nptl/sysdeps/unix/sysv/linux/arc/Makefile.arch |  32 +++
 .../unix/sysv/linux/arc/bits/pthreadtypes.h        | 181 +++++++++++++
 .../sysdeps/unix/sysv/linux/arc/bits/semaphore.h   |  35 +++
 .../nptl/sysdeps/unix/sysv/linux/arc/clone.S       |  10 +
 .../sysdeps/unix/sysv/linux/arc/createthread.c     |  25 ++
 libpthread/nptl/sysdeps/unix/sysv/linux/arc/fork.c |  30 +++
 .../unix/sysv/linux/arc/libc-lowlevellock.c        |  21 ++
 .../sysdeps/unix/sysv/linux/arc/lowlevellock.c     | 126 ++++++++++
 .../sysdeps/unix/sysv/linux/arc/lowlevellock.h     | 279 +++++++++++++++++++++
 .../unix/sysv/linux/arc/pt-__syscall_error.c       |   7 +
 .../sysv/linux/arc/pt-__syscall_rt_sigaction.c     |   7 +
 .../sysdeps/unix/sysv/linux/arc/pt-gettimeofday.c  |  11 +
 .../nptl/sysdeps/unix/sysv/linux/arc/pt-vfork.S    |   7 +
 .../sysdeps/unix/sysv/linux/arc/pthread_once.c     | 100 ++++++++
 .../sysdeps/unix/sysv/linux/arc/sysdep-cancel.h    | 115 +++++++++
 .../nptl/sysdeps/unix/sysv/linux/arc/vfork.S       |  11 +
 36 files changed, 1548 insertions(+), 13 deletions(-)
 create mode 100644 libc/sysdeps/linux/arc/bits/atomic.h
 create mode 100644 libpthread/nptl/sysdeps/arc/Makefile.arch
 create mode 100644 libpthread/nptl/sysdeps/arc/dl-tls.h
 create mode 100644 libpthread/nptl/sysdeps/arc/jmpbuf-unwind.h
 create mode 100644 libpthread/nptl/sysdeps/arc/libc-tls.c
 create mode 100644 libpthread/nptl/sysdeps/arc/pthread_spin_lock.S
 create mode 100644 libpthread/nptl/sysdeps/arc/pthread_spin_trylock.S
 create mode 100644 libpthread/nptl/sysdeps/arc/pthreaddef.h
 create mode 100644 libpthread/nptl/sysdeps/arc/tcb-offsets.sym
 create mode 100644 libpthread/nptl/sysdeps/arc/tls.h
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/Makefile
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/Makefile.arch
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/bits/pthreadtypes.h
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/bits/semaphore.h
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/clone.S
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/createthread.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/fork.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/libc-lowlevellock.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/lowlevellock.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/lowlevellock.h
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_error.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_rt_sigaction.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-gettimeofday.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-vfork.S
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/pthread_once.c
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h
 create mode 100644 libpthread/nptl/sysdeps/unix/sysv/linux/arc/vfork.S

diff --git a/extra/Configs/defconfigs/arc/defconfig b/extra/Configs/defconfigs/arc/defconfig
index 28356561242f..23058f353dc9 100644
--- a/extra/Configs/defconfigs/arc/defconfig
+++ b/extra/Configs/defconfigs/arc/defconfig
@@ -6,7 +6,7 @@ KERNEL_HEADERS="%KERNEL_HEADERS%"
 # LDSO_CACHE_SUPPORT is not set
 LDSO_RUNPATH=y
 # LDSO_SAFE_RUNPATH is not set
-LINUXTHREADS_OLD=y
+UCLIBC_HAS_THREADS_NATIVE=y
 PTHREADS_DEBUG_SUPPORT=y
 UCLIBC_SUSV2_LEGACY=y
 UCLIBC_SUSV3_LEGACY=y
diff --git a/include/elf.h b/include/elf.h
index 3bddcdccadf8..1979209cde83 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -3246,7 +3246,17 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_ARC_GOTOFF		0x39
 #define R_ARC_GOTPC		0x3A
 #define R_ARC_GOT32		0x3B
-#define R_ARC_NUM		0x3C
+
+#define R_ARC_TLS_DTPMOD	0x42
+#define R_ARC_TLS_DTPOFF	0x43
+#define R_ARC_TLS_TPOFF		0x44
+#define R_ARC_TLS_GD_GOT	0x45
+#define R_ARC_TLS_GD_LD	        0x46
+#define R_ARC_TLS_GD_CALL	0x47
+#define R_ARC_TLS_IE_GOT	0x48
+#define R_ARC_TLS_DTPOFF_S9	0x4a
+#define R_ARC_TLS_LE_S9		0x4a
+#define R_ARC_TLS_LE_32		0x4b
 
 #ifdef	__cplusplus
 }
diff --git a/ldso/ldso/arc/dl-debug.h b/ldso/ldso/arc/dl-debug.h
index ff559f27fa31..6573e5452a3d 100644
--- a/ldso/ldso/arc/dl-debug.h
+++ b/ldso/ldso/arc/dl-debug.h
@@ -65,4 +65,19 @@ static const char *_dl_reltypes_tab[] =
 	"R_ARC_GOTOFF",
 	"R_ARC_GOTPC",
 	"R_ARC_GOT32",
+	"",                     /* 60 */
+	"",
+	"",
+	"",
+	"",
+	"",                     /* 65 */
+        "R_ARC_TLS_DTPMOD",
+        "R_ARC_TLS_DTPOFF",
+        "R_ARC_TLS_TPOFF",
+        "R_ARC_TLS_GD_GOT",
+        "R_ARC_TLS_GD_LD",      /* 70 */
+        "R_ARC_TLS_GD_CALL",
+        "R_ARC_TLS_IE_GOT",
+        "",
+        "",
 };
diff --git a/ldso/ldso/arc/dl-sysdep.h b/ldso/ldso/arc/dl-sysdep.h
index af4b18064082..d71e16b3234e 100644
--- a/ldso/ldso/arc/dl-sysdep.h
+++ b/ldso/ldso/arc/dl-sysdep.h
@@ -96,12 +96,15 @@ extern unsigned __udivmodsi4(unsigned, unsigned) attribute_hidden;
 	})								\
 )
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries should not be allowed to define the value.
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+   TLS variable so PLT entries 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_ARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
+  ((((type) == R_ARC_JMP_SLOT || (type) == R_ARC_TLS_DTPMOD ||	\
+     (type) == R_ARC_TLS_DTPOFF || (type) == R_ARC_TLS_TPOFF)	\
+   * ELF_RTYPE_CLASS_PLT)					\
    | (((type) == R_ARC_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /*
diff --git a/ldso/ldso/arc/elfinterp.c b/ldso/ldso/arc/elfinterp.c
index ca0d2c16f266..d26c947058a0 100644
--- a/ldso/ldso/arc/elfinterp.c
+++ b/ldso/ldso/arc/elfinterp.c
@@ -92,6 +92,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	unsigned long old_val = 0;
 #endif
 	struct symbol_ref sym_ref;
+	struct elf_resolve *tls_tpnt = NULL;
 
 	reloc_addr   = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset);
 	reloc_type   = ELF_R_TYPE(rpnt->r_info);
@@ -118,15 +119,26 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		 */
 
 		if (unlikely(!symbol_addr
-		    && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
+		    && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK
+		    && ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)) {
 			/* Non-fatal if called from dlopen, hence different ret code */
 			return 1;
 		}
+
+		tls_tpnt = sym_ref.tpnt;
 	} else if (reloc_type == R_ARC_RELATIVE ) {
 		*reloc_addr += tpnt->loadaddr;
 		goto log_entry;
 	}
 
+#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_ARC_32:
 		*reloc_addr += symbol_addr + rpnt->r_addend;
@@ -142,6 +154,18 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		_dl_memcpy((void *) reloc_addr,(void *) symbol_addr,
 				symtab[symtab_index].st_size);
 		break;
+#if defined USE_TLS && USE_TLS
+	case R_ARC_TLS_DTPMOD:
+		*reloc_addr = tls_tpnt->l_tls_modid;
+		break;
+	case R_ARC_TLS_DTPOFF:
+		*reloc_addr = symbol_addr;
+		break;
+	case R_ARC_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;
 	}
diff --git a/libc/sysdeps/linux/arc/bits/atomic.h b/libc/sysdeps/linux/arc/bits/atomic.h
new file mode 100644
index 000000000000..d4abf4eb7896
--- /dev/null
+++ b/libc/sysdeps/linux/arc/bits/atomic.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <stdint.h>
+#include <sysdep.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+void __arc_link_error (void);
+
+#define atomic_full_barrier() \
+     __asm__ __volatile__("": : :"memory")
+
+/* Atomic compare and exchange. */
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+  ({ __arc_link_error (); oldval; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+  ({ __arc_link_error (); oldval; })
+
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval)     \
+  ({									\
+	__typeof(oldval) prev;						\
+									\
+	__asm__ __volatile__(						\
+	"1:	llock   %0, [%1]	\n"				\
+	"	brne    %0, %2, 2f	\n"				\
+	"	scond   %3, [%1]	\n"				\
+	"	bnz     1b		\n"				\
+	"2:				\n"				\
+	: "=&r"(prev)							\
+	: "r"(mem), "ir"(oldval),					\
+	  "r"(newval) /* can't be "ir". scond can't take limm for "b" */\
+	: "cc", "memory");						\
+									\
+	prev;								\
+  })
+
+#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+  ({ __arc_link_error (); oldval; })
diff --git a/libc/sysdeps/linux/arc/clone.S b/libc/sysdeps/linux/arc/clone.S
index 9aa8d92cd7b7..db5000caff96 100644
--- a/libc/sysdeps/linux/arc/clone.S
+++ b/libc/sysdeps/linux/arc/clone.S
@@ -19,25 +19,32 @@
 ;       Current (Jul 2012) upstream powerpc/clone.S assumes similarly.
 ;	Our LTP (from 2007) doesn't seem to have tests to prove otherwise
 
-; clone syscall in kernel
+; clone syscall in kernel (ABI: CONFIG_CLONE_BACKWARDS)
 ;
-; int sys_clone(unsigned long clone_flags, unsigned long newsp,
-;		int __user *parent_tidptr, void *tls,
+; int sys_clone(unsigned long clone_flags,
+;		unsigned long newsp,
+;		int __user *parent_tidptr,
+;		void *tls,
 ;		int __user *child_tidptr)
 
+#define CLONE_VM		0x00000100
+#define CLONE_THREAD		0x00010000
+#define CLONE_THREAD_N_VM	(CLONE_THREAD | CLONE_VM)
 
 ENTRY(clone)
 	cmp	r0, 0		; @fn can't be NULL
 	cmp.ne	r1, 0		; @child_stack can't be NULL
 	bz	.L__sys_err
 
-	; @fn and @args needed after the syscall for child
-	; However r3 containing @arg will be clobbered BEFORE syscall
+	; save some of the orig args
 	; r0 containg @fn will be clobbered AFTER syscall (with ret val)
-	mov	r10, r0
-	mov	r11, r3
+	; rest are clobbered BEFORE syscall due to different arg ordering
+	mov	r10, r0		; @fn
+	mov	r11, r3		; @args
+	mov	r12, r2		; @clone_flags
 
 	; adjust libc args for syscall
+
 	mov 	r0, r2		; libc @flags is 1st syscall arg
 	mov	r2, r4		; libc @ptid
 	mov	r3, r5		; libc @tls
@@ -49,6 +56,21 @@ ENTRY(clone)
 	blt	.L__sys_err2	; < 0 (signed) error
 	jnz	[blink]		; Parent returns
 
+	; ----- child starts here ---------
+#ifdef RESET_PID
+	mov_s	r2, CLONE_THREAD_N_VM
+	and_s	r2, r2, r12
+	brne	r2, r12, .Lgo_thread
+
+	mov	r8, __NR_clone
+	ARC_TRAP_INSN		; r0 has PID
+	THREAD_SELF r1		; Get to struct pthread (just before TCB)
+	st	r0, [r1, PTHREAD_PID]
+	st	r0, [r1, PTHREAD_TID]
+
+.Lgo_thread:
+#endif
+
 	; child jumps off to @fn with @arg as argument, and returns here
 	jl.d	[r10]
 	mov	r0, r11
diff --git a/libc/sysdeps/linux/arc/jmpbuf-unwind.h b/libc/sysdeps/linux/arc/jmpbuf-unwind.h
index e4ed8fe75f16..8c41816c5f6f 100644
--- a/libc/sysdeps/linux/arc/jmpbuf-unwind.h
+++ b/libc/sysdeps/linux/arc/jmpbuf-unwind.h
@@ -11,3 +11,20 @@
    containing a local variable at ADDRESS.  */
 #define _JMPBUF_UNWINDS(jmpbuf, address) \
   ((void *) (address) < (void *) (jmpbuf[__JMP_BUF_SP]))
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <stdint.h>
+#include <unwind.h>
+
+/* 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[__JMP_BUF_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)[__JMP_BUF_SP] - (_adj))
+#endif
diff --git a/libc/sysdeps/linux/arc/sysdep.h b/libc/sysdeps/linux/arc/sysdep.h
index 76d3788e5c10..d75d89100440 100644
--- a/libc/sysdeps/linux/arc/sysdep.h
+++ b/libc/sysdeps/linux/arc/sysdep.h
@@ -19,4 +19,8 @@ nm:
 
 #include <common/sysdep.h>
 
+/* Pointer mangling is not yet supported  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
 #endif
diff --git a/libc/sysdeps/linux/arc/vfork.S b/libc/sysdeps/linux/arc/vfork.S
index 11959b66b34c..573a29f26852 100644
--- a/libc/sysdeps/linux/arc/vfork.S
+++ b/libc/sysdeps/linux/arc/vfork.S
@@ -16,12 +16,25 @@
 #define CLONE_FLAGS_FOR_VFORK	(CLONE_VM|CLONE_VFORK|SIGCHLD)
 
 ENTRY(__vfork)
+#ifdef SAVE_PID
+	THREAD_SELF r1		; Get to struct pthread (just before TCB)
+	ld	r2, [r1, PTHREAD_PID]
+	neg.f	r3, r2
+	bset.z	r3, r3, 31
+	st	r3, [r1, PTHREAD_PID]
+#endif
 	mov	r0, CLONE_FLAGS_FOR_VFORK
 	mov_s	r1, sp
 	mov	r8, __NR_clone
 	ARC_TRAP_INSN
 
 	cmp	r0, 0
+#ifdef RESTORE_PID
+	bz	1f	; child continues
+	THREAD_SELF r1		; Get to struct pthread (just before TCB)
+	st	r2, [r1, PTHREAD_PID]
+1:
+#endif
 	jge	[blink]	; pid >=0 return, else detour via tailcall to errno
 
 	b   __syscall_error
diff --git a/libpthread/nptl/sysdeps/arc/Makefile.arch b/libpthread/nptl/sysdeps/arc/Makefile.arch
new file mode 100644
index 000000000000..1c728847e1eb
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/Makefile.arch
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill at uclibc.org>
+#
+# Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+#
+
+CFLAGS-pt-raise.c = -DNOT_IN_libc -DIS_IN_libpthread
+
+ASFLAGS-pthread_spin_lock.S = -DNOT_IN_libc -DIS_IN_libpthread
+ASFLAGS-pthread_spin_trylock.S = -DNOT_IN_libc -DIS_IN_libpthread
+
+libc_arch_a_CSRC = libc-tls.c
diff --git a/libpthread/nptl/sysdeps/arc/dl-tls.h b/libpthread/nptl/sysdeps/arc/dl-tls.h
new file mode 100644
index 000000000000..34e54e4d30c1
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/dl-tls.h
@@ -0,0 +1,28 @@
+/* Thread-local storage handling in the ELF dynamic linker.  ARC version.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* 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/arc/jmpbuf-unwind.h b/libpthread/nptl/sysdeps/arc/jmpbuf-unwind.h
new file mode 100644
index 000000000000..11a043b23fe8
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/jmpbuf-unwind.h
@@ -0,0 +1,32 @@
+/* Copyright (C) 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <setjmp.h>
+#include <stdint.h>
+#include <unwind.h>
+
+/* 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[__JMP_BUF_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)[__JMP_BUF_SP] - (_adj))
diff --git a/libpthread/nptl/sysdeps/arc/libc-tls.c b/libpthread/nptl/sysdeps/arc/libc-tls.c
new file mode 100644
index 000000000000..f53ad112e398
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/libc-tls.c
@@ -0,0 +1,27 @@
+/*
+ * Thread-local storage handling in statically linked binaries.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * Based on GNU C Library (file: libc/sysdeps/sh/libc-tls.c)
+ *
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ * Copyright (C) 2010 STMicroelectronics Ltd.
+ *
+ * Author: Filippo Arcidiacono <filippo.arcidiacono at st.com>
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sysdeps/generic/libc-tls.c>
+#include <dl-tls.h>
+
+#if defined(USE_TLS) && USE_TLS
+
+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/arc/pthread_spin_lock.S b/libpthread/nptl/sysdeps/arc/pthread_spin_lock.S
new file mode 100644
index 000000000000..7a5e630b80af
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/pthread_spin_lock.S
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sysdep.h>
+
+; int pthread_spin_lock(pthread_spinlock_t *lock)
+; 1 - locked, 0 - unlocked
+
+ENTRY(pthread_spin_lock)
+	mov_s	r1, 1
+	nop_s
+1:
+	ex	r1, [r0]
+	breq	r1, 1, 1b
+
+	j.d	[blink]
+	mov	r0, 0
+END(pthread_spin_lock)
diff --git a/libpthread/nptl/sysdeps/arc/pthread_spin_trylock.S b/libpthread/nptl/sysdeps/arc/pthread_spin_trylock.S
new file mode 100644
index 000000000000..25f5421a23d8
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/pthread_spin_trylock.S
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sysdep.h>
+
+#define _ERRNO_H 1
+#include <bits/errno.h>
+
+; int pthread_spin_trylock(pthread_spinlock_t *lock)
+; Return EBUSY is already locked, 0 if not
+
+ENTRY(pthread_spin_trylock)
+	mov_s	r1, 1
+	ex	r1, [r0]
+	tst	r1, r1
+	mov.z	r0, 0
+	j.d	[blink]
+	mov.nz	r0, EBUSY
+
+;	slightly faster, but difficult to follow
+;	mov_s	r1, r0
+;	mov_s	r0, 1
+;	ex	r0, [r1]
+;	tst	r0, r0
+;	j.d	[blink]
+;	mov.nz	r0, EBUSY
+
+END(pthread_spin_trylock)
diff --git a/libpthread/nptl/sysdeps/arc/pthreaddef.h b/libpthread/nptl/sysdeps/arc/pthreaddef.h
new file mode 100644
index 000000000000..51625e4e6f18
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/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 <sysdep.h>
+
+/* 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/arc/tcb-offsets.sym b/libpthread/nptl/sysdeps/arc/tcb-offsets.sym
new file mode 100644
index 000000000000..cbf0ae42ca61
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/tcb-offsets.sym
@@ -0,0 +1,8 @@
+#include <sysdep.h>
+#include <tls.h>
+
+PTHREAD_TID		offsetof (struct pthread, tid)
+PTHREAD_PID		offsetof (struct pthread, pid)
+MULTIPLE_THREADS_OFFSET	offsetof (struct pthread, header.multiple_threads)
+TLS_PRE_TCB_SIZE	sizeof (struct pthread)
+TLS_TCB_SIZE            sizeof(tcbhead_t)
diff --git a/libpthread/nptl/sysdeps/arc/tls.h b/libpthread/nptl/sysdeps/arc/tls.h
new file mode 100644
index 000000000000..63dd11398522
--- /dev/null
+++ b/libpthread/nptl/sysdeps/arc/tls.h
@@ -0,0 +1,160 @@
+/* Definition for thread-local data handling. NPTL/ARC version.
+ *
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+# include <stdlib.h>
+# include <list.h>
+# include <sysdep.h>
+# include <bits/kernel-features.h>
+
+/* 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 <tcb-offsets.h>
+
+.macro THREAD_SELF reg
+	# struct pthread is just ahead of TCB
+	sub     \reg, r25, TLS_PRE_TCB_SIZE
+.endm
+
+.macro SET_TP  tcb
+	mov    r25, \tcb
+.endm
+
+#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 <sysdep.h>
+
+/* 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.  */
+#ifndef TLS_TCB_SIZE
+# define TLS_TCB_SIZE sizeof (tcbhead_t)
+#endif
+
+/* 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 <descr.h>
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)          \
+  ({                                            \
+        __builtin_set_thread_pointer(tcbp);     \
+        NULL;                                   \
+   })
+
+/* Return the address of the dtv for the current thread.
+   TP points to TCB where 1st item is dtv pointer */
+# define THREAD_DTV() \
+  (((tcbhead_t *)__builtin_thread_pointer())->dtv)
+
+/* Return the thread descriptor for the current thread.
+   pthread sits right before TCB */
+# 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/arc/Makefile b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/Makefile
new file mode 100644
index 000000000000..729adf6f9d01
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/Makefile
@@ -0,0 +1,13 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2005 Steven J. Hill <sjhill at uclibc.org>
+#
+# 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/arc/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/Makefile.arch
new file mode 100644
index 000000000000..25e6fadbfdba
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/Makefile.arch
@@ -0,0 +1,32 @@
+# Makefile for uClibc NPTL
+#
+# Copyright (C) 2006 Steven J. Hill <sjhill at uclibc.org>
+#
+# 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 lowlevellock.c \
+	pt-__syscall_rt_sigaction.c pt-__syscall_error.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-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-pt-vfork.S = -DNOT_IN_libc -DIS_IN_libpthread
+
+ASFLAGS-vfork.S = -DIS_IN_libc -DNOT_IN_libpthread
+ASFLAGS-clone.S = -DIS_IN_libc -DNOT_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/arc/bits/pthreadtypes.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/bits/pthreadtypes.h
new file mode 100644
index 000000000000..e1b115c8ca1d
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/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 <endian.h>
+
+#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/arc/bits/semaphore.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/bits/semaphore.h
new file mode 100644
index 000000000000..dadfac2af2cb
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/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 <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T	16
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/clone.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/clone.S
new file mode 100644
index 000000000000..5fd1de3c2061
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/clone.S
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#define RESET_PID
+#include <tls.h>
+#include <tcb-offsets.h>
+#include "../../../../../../../libc/sysdeps/linux/arc/clone.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/createthread.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/createthread.c
new file mode 100644
index 000000000000..78719015fd2a
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/createthread.c
@@ -0,0 +1,25 @@
+/* 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.  */
+
+/* Internal clone callers pass struct pthread, but thread TP register
+ * needs to point to TLS block (struct tcbhead) which is right after */
+
+#define TLS_VALUE (pd + 1)
+
+/* Get the real implementation.	 */
+#include <sysdeps/pthread/createthread.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/fork.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/fork.c
new file mode 100644
index 000000000000..2578af6f4460
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/fork.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Phil Blundell <pb at nexus.co.uk>, 2005
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK()							\
+  INLINE_SYSCALL (clone, 5,						\
+		  CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD,	\
+		  NULL, NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/libc-lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/libc-lowlevellock.c
new file mode 100644
index 000000000000..b19282281c2b
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/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 <paulus at au.ibm.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.  */
+
+/* No difference to lowlevellock.c, except we lose a couple of functions.  */
+#include "lowlevellock.c"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/lowlevellock.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/lowlevellock.c
new file mode 100644
index 000000000000..1aa79609a713
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/lowlevellock.c
@@ -0,0 +1,126 @@
+/* low level locking for pthread library.  Generic futex-using version.
+   Copyright (C) 2003, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Mackerras <paulus at au.ibm.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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+#include <tls.h>
+#include <tcb-offsets.h>
+
+
+void
+__lll_lock_wait_private (int *futex)
+{
+  if (*futex == 2)
+    lll_futex_wait (futex, 2, LLL_PRIVATE);
+
+  while (atomic_exchange_acq (futex, 2) != 0)
+    lll_futex_wait (futex, 2, LLL_PRIVATE);
+}
+
+
+/* These functions don't get included in libc.so  */
+#ifdef IS_IN_libpthread
+void
+__lll_lock_wait (int *futex, int private)
+{
+  if (*futex == 2)
+    lll_futex_wait (futex, 2, private);
+
+  while (atomic_exchange_acq (futex, 2) != 0)
+    lll_futex_wait (futex, 2, private);
+}
+
+
+int
+__lll_timedlock_wait (int *futex, const struct timespec *abstime, int private)
+{
+  /* Reject invalid timeouts.  */
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  /* Try locking.  */
+  while (atomic_exchange_acq (futex, 2) != 0)
+    {
+      struct timeval tv;
+
+      /* Get the current time.  */
+      (void) gettimeofday (&tv, NULL);
+
+      /* Compute relative timeout.  */
+      struct timespec rt;
+      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;
+	}
+
+      if (rt.tv_sec < 0)
+	return ETIMEDOUT;
+
+      /* Wait.  */
+      lll_futex_timed_wait (futex, 2, &rt, private);
+    }
+
+  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.  The kernel so far does not use
+	 the private futex operations for this.  */
+      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/arc/lowlevellock.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/lowlevellock.h
new file mode 100644
index 000000000000..99ada5d50914
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/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 <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <bits/kernel-features.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)
+#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/arc/pt-__syscall_error.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_error.c
new file mode 100644
index 000000000000..8002e65c33af
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_error.c
@@ -0,0 +1,7 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <../../../../../../../libc/sysdeps/linux/arc/__syscall_error.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_rt_sigaction.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_rt_sigaction.c
new file mode 100644
index 000000000000..346651826ece
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-__syscall_rt_sigaction.c
@@ -0,0 +1,7 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <../../../../../../../libc/sysdeps/linux/arc/sigaction.c>
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-gettimeofday.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-gettimeofday.c
new file mode 100644
index 000000000000..d9fc3531fe12
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-gettimeofday.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+
+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/arc/pt-vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-vfork.S
new file mode 100644
index 000000000000..f222dca43b2f
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pt-vfork.S
@@ -0,0 +1,7 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include "vfork.S"
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pthread_once.c b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/pthread_once.c
new file mode 100644
index 000000000000..e977a7d0c11d
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/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 <lowlevellock.h>
+
+unsigned long int __fork_generation attribute_hidden;
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, 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/arc/sysdep-cancel.h b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h
new file mode 100644
index 000000000000..cddd754a8680
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/sysdep-cancel.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <tls.h>
+#include <sysdep.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+#ifdef __ASSEMBLER__
+
+#undef ret
+#define ret
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, nargs)			\
+   /* vanilla version */				`	\
+   ENTRY(name##_nocancel)				`	\
+      DO_CALL (__NR_##syscall_name)			`	\
+      jls  [blink]					`	\
+      b  __syscall_error at plt				`	\
+   END(name##_nocancel)					`	\
+   /* thread cancellation variant */			`	\
+   ENTRY(name)			    			`	\
+      SINGLE_THREAD_P					`	\
+      bz name##_nocancel				`	\
+      DOCARGS_##nargs  /* stash syscall args */		`	\
+      CENABLE          /* call enable_asynccancel */	`	\
+      mov r9, r0       /* Safe-keep mask */ 		`	\
+      UNDOCARGS_##nargs	/* restore syscall args */	`	\
+      DO_CALL (__NR_##syscall_name)			`	\
+      push  r0         /* save syscall return value */	`	\
+      mov   r0, r9     /* prep mask for disable_asynccancel */  `	\
+      CDISABLE	`	\
+      pop  r0           /* get syscall ret value back */  ` \
+      cmp  r0, -1024	`	\
+      jls  [blink]					`	\
+      b  __syscall_error at plt				`	\
+   END(name)
+
+#undef	PSEUDO_END
+#define	PSEUDO_END(name)	\
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	bl __pthread_enable_asynccancel
+#  define CDISABLE	bl __pthread_disable_asynccancel
+#  define __local_multiple_threads __pthread_multiple_threads
+# elif !defined NOT_IN_libc
+#  define CENABLE	bl __libc_enable_asynccancel
+#  define CDISABLE	bl __libc_disable_asynccancel
+#  define __local_multiple_threads __libc_multiple_threads
+# elif defined IS_IN_librt
+#  define CENABLE	bl __librt_enable_asynccancel
+#  define CDISABLE	bl __librt_disable_asynccancel
+# else
+#  error Unsupported library
+# endif
+
+#define DO_CALL(num)		\
+	mov	r8, num		`	\
+	ARC_TRAP_INSN		`	\
+	cmp r0, -1024
+
+.macro push reg
+	st.a \reg, [sp, -4]
+.endm
+
+.macro pop reg
+	ld.ab \reg, [sp, 4]
+.endm
+
+#define DOCARGS_0	push blink
+#define UNDOCARGS_0	pop  blink
+
+#define DOCARGS_1	DOCARGS_0`	push r0
+#define UNDOCARGS_1			pop  r0`	UNDOCARGS_0
+
+#define DOCARGS_2	DOCARGS_1`	push r1
+#define UNDOCARGS_2			pop  r1`	UNDOCARGS_1
+
+#define DOCARGS_3	DOCARGS_2`	push r2
+#define UNDOCARGS_3			pop  r2`	UNDOCARGS_2
+
+#define DOCARGS_4	DOCARGS_3`	push r3
+#define UNDOCARGS_4			pop  r3`	UNDOCARGS_3
+
+#define DOCARGS_5	DOCARGS_4`	push r4
+#define UNDOCARGS_5			pop  r4`	UNDOCARGS_4
+
+#define DOCARGS_6	DOCARGS_5`	push r5
+#define UNDOCARGS_6			pop  r5`	UNDOCARGS_5
+
+#define DOCARGS_7	DOCARGS_6`	push r6
+#define UNDOCARGS_7			pop  r6`	UNDOCARGS_6
+
+#  define SINGLE_THREAD_P 			\
+    THREAD_SELF r1   `				\
+    ld	   r2, [r1, MULTIPLE_THREADS_OFFSET]`	\
+    cmp    r2, 0
+
+/*    ld	   r2, [r1, -TLS_PRE_TCB_SIZE + MULTIPLE_THREADS_OFFSET] */
+#else	/* !__ASSEMBLER__ */
+
+/* TBD: Can use @__local_multiple_threads for libc/libpthread like ARM */
+#   define SINGLE_THREAD_P	\
+    likely(THREAD_GETMEM (THREAD_SELF, header.multiple_threads) == 0)
+
+#endif /* __ASSEMBLER__ */
+
+#endif
diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/arc/vfork.S b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/vfork.S
new file mode 100644
index 000000000000..d29e05a8a871
--- /dev/null
+++ b/libpthread/nptl/sysdeps/unix/sysv/linux/arc/vfork.S
@@ -0,0 +1,11 @@
+/*
+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#define SAVE_PID
+#define RESTORE_PID
+#include <tls.h>
+#include <tcb-offsets.h>
+#include "../../../../../../../libc/sysdeps/linux/arc/vfork.S"
-- 
1.8.3.2



More information about the uClibc mailing list