summaryrefslogtreecommitdiff
path: root/libpthread
diff options
context:
space:
mode:
authorMarkos Chandras <markos.chandras@imgtec.com>2010-11-18 14:58:01 +0000
committerBernhard Reutner-Fischer <rep.dot.nop@gmail.com>2013-03-14 22:47:08 +0100
commitdaecc9a410a6f23d80daf8ce3afd280fea329e63 (patch)
tree8d603dd538809431cc01b9e656c827d1f0709052 /libpthread
parent20221281b3d67880439cd1d16c151f4528d034fb (diff)
metag: Add NPTL support
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Diffstat (limited to 'libpthread')
-rw-r--r--libpthread/nptl/sysdeps/metag/Makefile.arch17
-rw-r--r--libpthread/nptl/sysdeps/metag/dl-tls.h29
-rw-r--r--libpthread/nptl/sysdeps/metag/jmpbuf-unwind.h36
-rw-r--r--libpthread/nptl/sysdeps/metag/libc-tls.c33
-rw-r--r--libpthread/nptl/sysdeps/metag/metag_load_tp.S7
-rw-r--r--libpthread/nptl/sysdeps/metag/pthread_spin_init.c20
-rw-r--r--libpthread/nptl/sysdeps/metag/pthread_spin_lock.S20
-rw-r--r--libpthread/nptl/sysdeps/metag/pthread_spin_trylock.S24
-rw-r--r--libpthread/nptl/sysdeps/metag/pthread_spin_unlock.S16
-rw-r--r--libpthread/nptl/sysdeps/metag/pthreaddef.h40
-rw-r--r--libpthread/nptl/sysdeps/metag/tcb-offsets.sym15
-rw-r--r--libpthread/nptl/sysdeps/metag/tls.h163
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile13
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/Makefile.arch34
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/pthreadtypes.h181
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/bits/semaphore.h35
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/clone.S9
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/createthread.c23
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/fork.c31
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/libc-lowlevellock.c21
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.c134
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/lowlevellock.h279
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_error.c7
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-__syscall_rt_sigaction.c7
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-gettimeofday.c11
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/pt-vfork.S51
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/pthread_once.c100
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/sysdep-cancel.h152
-rw-r--r--libpthread/nptl/sysdeps/unix/sysv/linux/metag/vfork.S56
29 files changed, 1564 insertions, 0 deletions
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 <sjhill@uclibc.org>
+#
+# 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 <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#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[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 <filippo.arcidiacono@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)
+
+/* 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 <drepper@redhat.com>, 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 <pthread-errnos.h>
+
+ .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 <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/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 <sysdep.h>
+#include <tls.h>
+
+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 <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>
+#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. */
+# 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 <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) \
+ (((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 <sjhill@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/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 <sjhill@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 \
+ 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 <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/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 <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/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 <tcb-offsets.h>
+#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 <sysdeps/pthread/createthread.c>
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 <pb@nexus.co.uk>, 2005
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+#define ARCH_FORK() \
+ INLINE_SYSCALL (clone, 5, \
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \
+ NULL, NULL, &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 <paulus@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/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 <errno.h>
+#include <sysdep.h>
+#include <lowlevellock.h>
+#include <sys/time.h>
+#include <tls.h>
+
+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 <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/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 <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/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 <tcb-offsets.h>
+#include <asm/unistd.h>
+
+#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 <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/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 <tls.h>
+#include <sysdep.h>
+#ifndef __ASSEMBLER__
+# include <pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+/* NOTE: We do mark syscalls with unwind annotations, for the benefit of
+ cancellation; but they're really only accurate at the point of the
+ syscall. The ARM unwind directives are not rich enough without adding
+ a custom personality function. */
+
+#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 <tcb-offsets.h>
+#include <asm/unistd.h>
+
+#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>