summaryrefslogtreecommitdiff
path: root/ports/sysdeps/unix/sysv/linux/tile/nptl
diff options
context:
space:
mode:
Diffstat (limited to 'ports/sysdeps/unix/sysv/linux/tile/nptl')
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/Makefile2
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/bits/pthreadtypes.h223
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/bits/semaphore.h41
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/clone.S220
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/createthread.c24
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/fork.c31
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/lowlevellock.h280
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/pt-vfork.S2
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c94
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/sysdep-cancel.h154
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/vfork.S80
-rw-r--r--ports/sysdeps/unix/sysv/linux/tile/nptl/waitpid.S20
12 files changed, 1171 insertions, 0 deletions
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/Makefile b/ports/sysdeps/unix/sysv/linux/tile/nptl/Makefile
new file mode 100644
index 0000000000..e98c9bd866
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/Makefile
@@ -0,0 +1,2 @@
+# pull in __syscall_error routine
+libpthread-routines += sysdep
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/bits/pthreadtypes.h b/ports/sysdeps/unix/sysv/linux/tile/nptl/bits/pthreadtypes.h
new file mode 100644
index 0000000000..ac51e3b93c
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/bits/pthreadtypes.h
@@ -0,0 +1,223 @@
+/* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Based on work contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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/>. */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_PTHREAD_ATTR_T 56
+# define __SIZEOF_PTHREAD_MUTEX_T 40
+# define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+# define __SIZEOF_PTHREAD_COND_T 48
+# define __SIZEOF_PTHREAD_CONDATTR_T 4
+# define __SIZEOF_PTHREAD_RWLOCK_T 56
+# define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+# define __SIZEOF_PTHREAD_BARRIER_T 32
+# define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+#else
+# 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_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
+#endif
+
+
+/* Thread identifiers. The structure of the attribute type is not
+ exposed on purpose. */
+typedef unsigned long int pthread_t;
+
+
+union pthread_attr_t
+{
+ char __size[__SIZEOF_PTHREAD_ATTR_T];
+ long int __align;
+};
+#ifndef __have_pthread_attr_t
+typedef union pthread_attr_t pthread_attr_t;
+# define __have_pthread_attr_t 1
+#endif
+
+#if __WORDSIZE == 64
+typedef struct __pthread_internal_list
+{
+ struct __pthread_internal_list *__prev;
+ struct __pthread_internal_list *__next;
+} __pthread_list_t;
+#else
+typedef struct __pthread_internal_slist
+{
+ struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+#endif
+
+
+/* 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;
+#if __WORDSIZE == 64
+ unsigned int __nusers;
+#endif
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility. */
+ int __kind;
+#if __WORDSIZE == 64
+ int __spins;
+ __pthread_list_t __list;
+# define __PTHREAD_MUTEX_HAVE_PREV 1
+#else
+ unsigned int __nusers;
+ __extension__ union
+ {
+ int __spins;
+ __pthread_slist_t __list;
+ };
+#endif
+ } __data;
+ char __size[__SIZEOF_PTHREAD_MUTEX_T];
+ long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+ 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];
+ 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
+{
+# if __WORDSIZE == 64
+ 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;
+ int __writer;
+ int __shared;
+ unsigned long int __pad1;
+ unsigned long int __pad2;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned int __flags;
+ } __data;
+# else
+ 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;
+ /* 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;
+ int __writer;
+ } __data;
+# endif
+ 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/ports/sysdeps/unix/sysv/linux/tile/nptl/bits/semaphore.h b/ports/sysdeps/unix/sysv/linux/tile/nptl/bits/semaphore.h
new file mode 100644
index 0000000000..8ed81da69e
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/bits/semaphore.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+ Based on work 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+#include <bits/wordsize.h>
+
+#if __WORDSIZE == 64
+# define __SIZEOF_SEM_T 32
+#else
+# define __SIZEOF_SEM_T 16
+#endif
+
+
+/* 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/ports/sysdeps/unix/sysv/linux/tile/nptl/clone.S b/ports/sysdeps/unix/sysv/linux/tile/nptl/clone.S
new file mode 100644
index 0000000000..de4fa136d3
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/clone.S
@@ -0,0 +1,220 @@
+/* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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/>. */
+
+/* clone() is even more special than fork() as it mucks with stacks
+ and invokes a function in the right context after it's all over. */
+
+#include <sysdep.h>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+
+#include <asm/unistd.h>
+#include <arch/abi.h>
+#include <tls.h>
+#include <linux/sched.h>
+
+/* What we save where in the stack frame; must include all callee-saves. */
+#define FRAME_NEXT_LR (0 * REGSIZE) /* reserved by ABI; not used here */
+#define FRAME_SP (1 * REGSIZE)
+#define FRAME_R30 (2 * REGSIZE)
+#define FRAME_R31 (3 * REGSIZE)
+#define FRAME_R32 (4 * REGSIZE)
+#define FRAME_SIZE (5 * REGSIZE)
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+ pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
+
+ .text
+ENTRY (__clone)
+ /* sanity check arguments */
+ BEQZ r0, .Linvalid
+ BEQZ r1, .Linvalid
+
+ /* Create a stack frame so we can pass callee-saves to new task. */
+ {
+ move r10, sp
+ ST sp, lr
+ ADDI_PTR sp, sp, -FRAME_SIZE
+ }
+ cfi_offset (lr, 0)
+ cfi_def_cfa_offset (FRAME_SIZE)
+ ADDI_PTR r11, sp, FRAME_SP
+ {
+ ST r11, r10
+ ADDI_PTR r11, sp, FRAME_R30
+ }
+ {
+ ST r11, r30
+ ADDI_PTR r11, sp, FRAME_R31
+ }
+ cfi_offset (r30, FRAME_R30 - FRAME_SIZE)
+ {
+ ST r11, r31
+ ADDI_PTR r11, sp, FRAME_R32
+ }
+ cfi_offset (r31, FRAME_R31 - FRAME_SIZE)
+ ST r11, r32
+ cfi_offset (r32, FRAME_R32 - FRAME_SIZE)
+
+ /* Make sure child stack is properly aligned, and set up the
+ top frame so that we can call out of it immediately in the
+ child. Setting it up here means we fault in the parent if
+ it's bogus, which is probably cleaner than faulting first
+ thing in the child. */
+ ADDI_PTR r1, r1, -C_ABI_SAVE_AREA_SIZE
+ andi r1, r1, -C_ABI_SAVE_AREA_SIZE
+ ADDI_PTR r9, r1, REGSIZE /* sp of this frame on entry, i.e. zero */
+ ST r9, zero
+
+ /* We need to switch the argument convention around from
+ libc to kernel:
+
+ libc:
+ r0 fn
+ r1 child_stack
+ r2 flags
+ r3 arg
+ r4 ptid
+ r5 tls
+ r6 ctid
+
+ kernel:
+ r0 flags
+ r1 child_stack [same as libc]
+ r2 ptid
+ r3 ctid
+ r4 tls
+
+ Plus the callee-saves as described at .Lthread_start, below. */
+ {
+ move r32, r0
+ move r0, r2
+ }
+ {
+ move r31, r3
+ move r3, r6
+ }
+ {
+ move r30, r2
+ move r2, r4
+ }
+ {
+ move r4, r5
+ moveli TREG_SYSCALL_NR_NAME, __NR_clone
+ }
+ swint1
+ BEQZ r0, .Lthread_start /* If in child task. */
+
+ /* Restore the callee-saved registers and return. */
+ ADDLI_PTR lr, sp, FRAME_SIZE
+ {
+ LD lr, lr
+ ADDLI_PTR r30, sp, FRAME_R30
+ }
+ {
+ LD r30, r30
+ ADDLI_PTR r31, sp, FRAME_R31
+ }
+ {
+ LD r31, r31
+ ADDLI_PTR r32, sp, FRAME_R32
+ }
+ {
+ LD r32, r32
+ ADDI_PTR sp, sp, FRAME_SIZE
+ }
+ cfi_def_cfa_offset (0)
+
+ BNEZ r1, .Lerror
+ jrp lr
+
+.Lerror:
+ j SYSCALL_ERROR_NAME
+
+.Linvalid:
+ {
+ movei r1, EINVAL
+ j SYSCALL_ERROR_NAME
+ }
+
+/* This function expects to receive:
+
+ sp: the top of a valid stack area
+ r30: clone() flags
+ r31: the argument to pass to the user function
+ r32: the user function pointer */
+
+.Lthread_start:
+ /* Check and see if we need to reset the PID, which we do if
+ CLONE_THREAD isn't set, i.e. we're not staying in the thread group.
+ If CLONE_VM is set, we're doing some kind of thread-like clone,
+ so we set the tid/pid to -1 to disable using the cached values
+ in getpid(). Otherwise (if CLONE_VM isn't set), it's a
+ fork-like clone, and we go ahead and write the cached values
+ from the true system pid (retrieved via __NR_getpid syscall). */
+ cfi_def_cfa_offset (FRAME_SIZE)
+#ifdef __tilegx__
+ {
+ moveli r0, hw1_last(CLONE_VM)
+ moveli r1, hw1_last(CLONE_THREAD)
+ }
+ {
+ shl16insli r0, r0, hw0(CLONE_VM)
+ shl16insli r1, r1, hw0(CLONE_THREAD)
+ }
+#else
+ {
+ moveli r0, lo16(CLONE_VM)
+ moveli r1, lo16(CLONE_THREAD)
+ }
+ {
+ auli r0, r0, ha16(CLONE_VM)
+ auli r1, r1, ha16(CLONE_THREAD)
+ }
+#endif
+ {
+ and r0, r30, r0
+ and r1, r30, r1
+ }
+ BNEZ r1, .Lno_reset_pid /* CLONE_THREAD is set */
+ {
+ movei r0, -1
+ BNEZ r0, .Lgotpid /* CLONE_VM is set */
+ }
+ moveli TREG_SYSCALL_NR_NAME, __NR_getpid
+ swint1
+.Lgotpid:
+ ADDLI_PTR r2, tp, PID_OFFSET
+ {
+ ST4 r2, r0
+ ADDLI_PTR r2, tp, TID_OFFSET
+ }
+ ST4 r2, r0
+.Lno_reset_pid:
+ {
+ /* Invoke user function with specified argument. */
+ move r0, r31
+ jalr r32
+ }
+ {
+ j HIDDEN_JUMPTARGET(_exit)
+ info INFO_OP_CANNOT_BACKTRACE /* Notify backtracer to stop. */
+ }
+PSEUDO_END (__clone)
+
+weak_alias (__clone, clone)
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/createthread.c b/ports/sysdeps/unix/sysv/linux/tile/nptl/createthread.c
new file mode 100644
index 0000000000..3794e52dae
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/createthread.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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/>. */
+
+/* Value passed to 'clone' for initialization of the thread register. */
+#define TLS_VALUE ((void *) (pd) \
+ + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation. */
+#include <sysdeps/pthread/createthread.c>
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/fork.c b/ports/sysdeps/unix/sysv/linux/tile/nptl/fork.c
new file mode 100644
index 0000000000..a778238f86
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/fork.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+ Based on work 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+ INLINE_SYSCALL (clone, 4, \
+ CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \
+ 0, NULL, &THREAD_SELF->tid)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/lowlevellock.h b/ports/sysdeps/unix/sysv/linux/tile/nptl/lowlevellock.h
new file mode 100644
index 0000000000..8690c7be4a
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/lowlevellock.h
@@ -0,0 +1,280 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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/>. */
+
+#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 <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); \
+ INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAIT, private), \
+ (val), (timespec)); \
+ })
+
+#define lll_futex_wake(futexp, nr, private) \
+ ({ \
+ INTERNAL_SYSCALL_DECL (__err); \
+ INTERNAL_SYSCALL (futex, __err, 4, (futexp), \
+ __lll_private_flag (FUTEX_WAKE, private), \
+ (nr), 0); \
+ })
+
+#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); \
+ })
+
+
+
+
+static inline int __attribute__ ((always_inline))
+__lll_trylock (int *futex)
+{
+ return atomic_compare_and_exchange_val_acq (futex, 1, 0) != 0;
+}
+#define lll_trylock(lock) __lll_trylock (&(lock))
+
+
+static inline int __attribute__ ((always_inline))
+__lll_cond_trylock (int *futex)
+{
+ return atomic_compare_and_exchange_val_acq (futex, 2, 0) != 0;
+}
+#define lll_cond_trylock(lock) __lll_cond_trylock (&(lock))
+
+
+static inline int __attribute__ ((always_inline))
+__lll_robust_trylock (int *futex, int id)
+{
+ return atomic_compare_and_exchange_val_acq (futex, id, 0) != 0;
+}
+#define lll_robust_trylock(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;
+
+static inline void __attribute__ ((always_inline))
+__lll_lock (int *futex, int private)
+{
+ if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 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)
+
+
+static inline int __attribute__ ((always_inline))
+__lll_robust_lock (int *futex, int id, int private)
+{
+ int result = 0;
+ if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+ result = __lll_robust_lock_wait (futex, private);
+ return result;
+}
+#define lll_robust_lock(futex, id, private) \
+ __lll_robust_lock (&(futex), id, private)
+
+
+static inline void __attribute__ ((always_inline))
+__lll_cond_lock (int *futex, int private)
+{
+ if (atomic_compare_and_exchange_bool_acq (futex, 2, 0) != 0)
+ __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;
+
+static inline int __attribute__ ((always_inline))
+__lll_timedlock (int *futex, const struct timespec *abstime, int private)
+{
+ int result = 0;
+ if (atomic_compare_and_exchange_bool_acq (futex, 1, 0) != 0)
+ result = __lll_timedlock_wait (futex, abstime, private);
+ return result;
+}
+#define lll_timedlock(futex, abstime, private) \
+ __lll_timedlock (&(futex), abstime, private)
+
+
+static inline int __attribute__ ((always_inline))
+__lll_robust_timedlock (int *futex, const struct timespec *abstime,
+ int id, int private)
+{
+ int result = 0;
+ if (atomic_compare_and_exchange_bool_acq (futex, id, 0) != 0)
+ result = __lll_robust_timedlock_wait (futex, abstime, private);
+ return result;
+}
+#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 (__builtin_expect (__oldval > 1, 0)) \
+ 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 (__builtin_expect (__oldval & FUTEX_WAITERS, 0)) \
+ lll_futex_wake (__futex, 1, private); \
+ })
+#define lll_robust_unlock(futex, private) \
+ __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+ (futex != 0)
+
+/* Initializers for lock. */
+#define LLL_LOCK_INITIALIZER (0)
+#define LLL_LOCK_INITIALIZER_LOCKED (1)
+
+
+/* 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/ports/sysdeps/unix/sysv/linux/tile/nptl/pt-vfork.S b/ports/sysdeps/unix/sysv/linux/tile/nptl/pt-vfork.S
new file mode 100644
index 0000000000..a6ccb1f51f
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/pt-vfork.S
@@ -0,0 +1,2 @@
+#define PT_VFORK 1 /* pid is never zero */
+#include "vfork.S"
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c b/ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c
new file mode 100644
index 0000000000..93ac29b24c
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/pthread_once.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+ Based on work 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, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <nptl/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
+__pthread_once (once_control, init_routine)
+ pthread_once_t *once_control;
+ void (*init_routine) (void);
+{
+ while (1)
+ {
+ int oldval, val, newval;
+
+ val = *once_control;
+ do
+ {
+ /* Check if the initialized has already been done. */
+ if ((val & 2) != 0)
+ return 0;
+
+ oldval = val;
+ newval = (oldval & 3) | __fork_generation | 1;
+ val = atomic_compare_and_exchange_val_acq (once_control, newval,
+ oldval);
+ }
+ while (__builtin_expect (val != oldval, 0));
+
+ /* Check if another thread already runs the initializer. */
+ if ((oldval & 1) != 0)
+ {
+ /* Check whether the initializer execution was interrupted
+ by a fork. */
+ if (((oldval ^ newval) & -4) == 0)
+ {
+ /* Same generation, some other thread was faster. Wait. */
+ lll_futex_wait (once_control, newval, LLL_PRIVATE);
+ continue;
+ }
+ }
+
+ /* 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);
+
+
+ /* Add one to *once_control. */
+ atomic_increment (once_control);
+
+ /* Wake up all other threads. */
+ lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+ break;
+ }
+
+ return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+hidden_def (__pthread_once)
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/sysdep-cancel.h b/ports/sysdeps/unix/sysv/linux/tile/nptl/sysdep-cancel.h
new file mode 100644
index 0000000000..8db7a40a54
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/sysdep-cancel.h
@@ -0,0 +1,154 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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 <sysdep.h>
+#include <tls.h>
+#ifndef __ASSEMBLER__
+# include <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+/* Allow hacking in some extra code if desired. */
+#ifndef PSEUDO_EXTRA
+#define PSEUDO_EXTRA
+#endif
+
+#undef PSEUDO
+#define PSEUDO(name, syscall_name, args) \
+ ENTRY(__##syscall_name##_nocancel); \
+ PSEUDO_EXTRA \
+ moveli TREG_SYSCALL_NR_NAME, SYS_ify(syscall_name); \
+ swint1; \
+ BNEZ r1, 0f; \
+ jrp lr; \
+ END(__##syscall_name##_nocancel); \
+ ENTRY (name) \
+ SINGLE_THREAD_P(r11); \
+ BEQZ r11, L(pseudo_cancel); \
+ PSEUDO_EXTRA \
+ moveli TREG_SYSCALL_NR_NAME, SYS_ify(syscall_name); \
+ swint1; \
+ BNEZ r1, 0f; \
+ jrp lr; \
+ L(pseudo_cancel): \
+ { \
+ move r11, sp; \
+ ST sp, lr; \
+ ADDI_PTR sp, sp, -STKSPACE; \
+ }; \
+ cfi_offset (lr, 0); \
+ cfi_def_cfa_offset (STKSPACE); \
+ { \
+ ADDI_PTR r12, sp, REGSIZE; \
+ ADDI_PTR r13, sp, 2 * REGSIZE; /* set up for PUSHARGS_0 */ \
+ }; \
+ ST r12, r11; \
+ PUSHARGS_##args /* save syscall args */ \
+ CENABLE; \
+ ADDI_PTR r12, sp, 10 * REGSIZE; \
+ { \
+ ST r12, r0; /* save mask */ \
+ ADDI_PTR r13, sp, 2 * REGSIZE; /* set up for POPARGS_0 */ \
+ }; \
+ POPARGS_##args /* restore syscall args */ \
+ PSEUDO_EXTRA \
+ moveli TREG_SYSCALL_NR_NAME, SYS_ify(syscall_name); \
+ swint1; \
+ ADDI_PTR r12, sp, 12 * REGSIZE; \
+ { \
+ ST r12, r1; /* save syscall result */ \
+ ADDI_PTR r12, sp, 11 * REGSIZE; \
+ }; \
+ { \
+ ST r12, r0; \
+ ADDI_PTR r13, sp, 10 * REGSIZE; \
+ }; \
+ LD r0, r13; /* pass mask as arg1 */ \
+ CDISABLE; \
+ { \
+ ADDI_PTR lr, sp, STKSPACE; \
+ ADDI_PTR r0, sp, 11 * REGSIZE; \
+ }; \
+ { \
+ LD r0, r0; \
+ ADDI_PTR r1, sp, 12 * REGSIZE; \
+ }; \
+ LD r1, r1; \
+ { \
+ LD lr, lr; \
+ ADDI_PTR sp, sp, STKSPACE; \
+ }; \
+ cfi_def_cfa_offset (0); \
+ BNEZ r1, 0f
+
+# define PUSHARGS_0 /* nothing to do */
+# define PUSHARGS_1 PUSHARGS_0 { ADDI_PTR r14, sp, 3 * REGSIZE; ST r13, r0 };
+# define PUSHARGS_2 PUSHARGS_1 { ADDI_PTR r13, sp, 4 * REGSIZE; ST r14, r1 };
+# define PUSHARGS_3 PUSHARGS_2 { ADDI_PTR r14, sp, 5 * REGSIZE; ST r13, r2 };
+# define PUSHARGS_4 PUSHARGS_3 { ADDI_PTR r13, sp, 6 * REGSIZE; ST r14, r3 };
+# define PUSHARGS_5 PUSHARGS_4 { ADDI_PTR r14, sp, 7 * REGSIZE; ST r13, r4 };
+# define PUSHARGS_6 PUSHARGS_5 { ADDI_PTR r13, sp, 8 * REGSIZE; ST r14, r5 };
+# define PUSHARGS_7 PUSHARGS_6 { ADDI_PTR r14, sp, 9 * REGSIZE; ST r13, r6 };
+
+# define POPARGS_0 /* nothing to do */
+# define POPARGS_1 POPARGS_0 { ADDI_PTR r14, sp, 3 * REGSIZE; LD r0, r13 };
+# define POPARGS_2 POPARGS_1 { ADDI_PTR r13, sp, 4 * REGSIZE; LD r1, r14 };
+# define POPARGS_3 POPARGS_2 { ADDI_PTR r14, sp, 5 * REGSIZE; LD r2, r13 };
+# define POPARGS_4 POPARGS_3 { ADDI_PTR r13, sp, 6 * REGSIZE; LD r3, r14 };
+# define POPARGS_5 POPARGS_4 { ADDI_PTR r14, sp, 7 * REGSIZE; LD r4, r13 };
+# define POPARGS_6 POPARGS_5 { ADDI_PTR r13, sp, 8 * REGSIZE; LD r5, r14 };
+# define POPARGS_7 POPARGS_6 { ADDI_PTR r14, sp, 9 * REGSIZE; LD r6, r13 };
+
+# define STKSPACE (13 * REGSIZE)
+
+# ifdef IS_IN_libpthread
+# define CENABLE jal __pthread_enable_asynccancel
+# define CDISABLE jal __pthread_disable_asynccancel
+# elif defined IS_IN_librt
+# define CENABLE jal __librt_enable_asynccancel
+# define CDISABLE jal __librt_disable_asynccancel
+# else
+# define CENABLE jal __libc_enable_asynccancel
+# define CDISABLE jal __libc_disable_asynccancel
+# endif
+
+# ifndef __ASSEMBLER__
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) \
+ == 0, 1)
+# else
+# define SINGLE_THREAD_P(reg) \
+ ADDLI_PTR reg, tp, MULTIPLE_THREADS_OFFSET; \
+ LD reg, reg; \
+ CMPEQI reg, reg, 0
+#endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P 1
+# define NO_CANCELLATION 1
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
+#endif
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/vfork.S b/ports/sysdeps/unix/sysv/linux/tile/nptl/vfork.S
new file mode 100644
index 0000000000..ddf9a7ae6e
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/vfork.S
@@ -0,0 +1,80 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ 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 <sysdep.h>
+#define __ASSEMBLY__ /* for kernel headers */
+#include <linux/sched.h>
+#include <asm/signal.h>
+#include <tcb-offsets.h>
+
+/* Clone the calling process, but without copying the whole address space.
+ The calling process is suspended until the new process exits or is
+ replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+
+ .text
+ENTRY (__vfork)
+ {
+ addli r11, tp, PID_OFFSET /* Point at PID. */
+ movei r13, 1
+ }
+ {
+ LD4U r12, r11 /* Load the saved PID. */
+ shli r13, r13, 31 /* Build 0x80000000. */
+ }
+ sub r12, zero, r12 /* Negate it. */
+#ifndef PT_VFORK
+ CMOVEQZ r12, r12, r13 /* Replace zero pids. */
+#endif
+ ST4 r11, r12 /* Store the temporary PID. */
+
+ {
+ moveli r0, CLONE_VFORK | CLONE_VM | SIGCHLD
+ move r1, zero
+ }
+ {
+ move r2, zero
+ move r3, zero
+ }
+ moveli TREG_SYSCALL_NR_NAME, __NR_clone
+ swint1
+
+ BEQZ r0, 1f /* If we are the parent... */
+ {
+ addli r11, tp, PID_OFFSET /* Point at PID. */
+ movei r13, 1
+ }
+ {
+ LD4U r12, r11 /* Load the saved PID. */
+ shli r13, r13, 31 /* Build 0x80000000. */
+ }
+ {
+ CMPEQ r13, r12, r12 /* Test for that value. */
+ sub r12, zero, r12 /* Re-negate it. */
+ }
+#ifndef PT_VFORK
+ CMOVNEZ r12, r13, zero /* Replace zero pids. */
+#endif
+ ST4 r11, r12 /* Restore the PID. */
+1:
+ BNEZ r1, 0f
+ jrp lr
+PSEUDO_END (__vfork)
+libc_hidden_def (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/ports/sysdeps/unix/sysv/linux/tile/nptl/waitpid.S b/ports/sysdeps/unix/sysv/linux/tile/nptl/waitpid.S
new file mode 100644
index 0000000000..9aa793e12b
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/tile/nptl/waitpid.S
@@ -0,0 +1,20 @@
+/*
+extern pid_t __waitpid_nocancel (pid_t, int *, int) attribute_hidden;
+*/
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+/* Call __NR_wait4, providing fourth argument (struct rusage *) as NULL. */
+#define PSEUDO_EXTRA move r3, zero;
+#include <sysdep-cancel.h>
+
+PSEUDO (__waitpid, wait4, 3)
+ret
+PSEUDO_END(__waitpid)
+
+libc_hidden_def (__waitpid)
+weak_alias (__waitpid, waitpid)
+libc_hidden_weak (waitpid)
+weak_alias (__waitpid, __libc_waitpid)
+libc_hidden_weak (__libc_waitpid)
+
+#endif