summaryrefslogtreecommitdiff
path: root/nptl/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps')
-rw-r--r--nptl/sysdeps/generic/lowlevellock.h89
-rw-r--r--nptl/sysdeps/generic/pt-raise.c30
-rw-r--r--nptl/sysdeps/i386/i686/bits/atomic.h340
-rw-r--r--nptl/sysdeps/i386/i686/pthread_spin_trylock.S34
-rw-r--r--nptl/sysdeps/i386/i686/tls.h36
-rw-r--r--nptl/sysdeps/i386/pthread_sigmask.c34
-rw-r--r--nptl/sysdeps/i386/pthread_spin_destroy.c29
-rw-r--r--nptl/sysdeps/i386/pthread_spin_init.c20
-rw-r--r--nptl/sysdeps/i386/pthread_spin_lock.c48
-rw-r--r--nptl/sysdeps/i386/pthread_spin_unlock.S32
-rw-r--r--nptl/sysdeps/i386/pthreaddef.h55
-rw-r--r--nptl/sysdeps/i386/tls.h332
-rw-r--r--nptl/sysdeps/pthread/Makefile33
-rw-r--r--nptl/sysdeps/pthread/Subdirs1
-rw-r--r--nptl/sysdeps/pthread/allocalim.h29
-rw-r--r--nptl/sysdeps/pthread/bits/libc-lock.h335
-rw-r--r--nptl/sysdeps/pthread/bits/sigthread.h38
-rw-r--r--nptl/sysdeps/pthread/list.h116
-rw-r--r--nptl/sysdeps/pthread/posix-timer.h210
-rw-r--r--nptl/sysdeps/pthread/pt-initfini.c124
-rw-r--r--nptl/sysdeps/pthread/pthread.h743
-rw-r--r--nptl/sysdeps/pthread/pthread_getcpuclockid.c43
-rw-r--r--nptl/sysdeps/pthread/pthread_once.c54
-rw-r--r--nptl/sysdeps/pthread/pthread_sigmask.c44
-rw-r--r--nptl/sysdeps/pthread/sigaction.c24
-rw-r--r--nptl/sysdeps/pthread/timer_create.c179
-rw-r--r--nptl/sysdeps/pthread/timer_delete.c70
-rw-r--r--nptl/sysdeps/pthread/timer_getoverr.c45
-rw-r--r--nptl/sysdeps/pthread/timer_gettime.c71
-rw-r--r--nptl/sysdeps/pthread/timer_routines.c592
-rw-r--r--nptl/sysdeps/pthread/timer_settime.c137
-rw-r--r--nptl/sysdeps/pthread/tst-timer.c114
-rw-r--r--nptl/sysdeps/unix/sysv/linux/Implies1
-rw-r--r--nptl/sysdeps/unix/sysv/linux/Makefile24
-rw-r--r--nptl/sysdeps/unix/sysv/linux/Versions12
-rw-r--r--nptl/sysdeps/unix/sysv/linux/allocrtsig.c54
-rw-r--r--nptl/sysdeps/unix/sysv/linux/bits/local_lim.h80
-rw-r--r--nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h144
-rw-r--r--nptl/sysdeps/unix/sysv/linux/configure3
-rw-r--r--nptl/sysdeps/unix/sysv/linux/fork-gen.c37
-rw-r--r--nptl/sysdeps/unix/sysv/linux/fork.c124
-rw-r--r--nptl/sysdeps/unix/sysv/linux/fork.h60
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h150
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h39
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/createthread.c146
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/fork.c31
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S279
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S180
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S176
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S566
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S311
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S122
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S20
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h257
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h101
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S49
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S171
-rw-r--r--nptl/sysdeps/unix/sysv/linux/internaltypes.h130
-rw-r--r--nptl/sysdeps/unix/sysv/linux/jmp-unwind.c33
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pt-fork.c28
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pt-raise.c31
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_kill.c36
-rw-r--r--nptl/sysdeps/unix/sysv/linux/pthread_yield.c30
-rw-r--r--nptl/sysdeps/unix/sysv/linux/raise.c39
-rw-r--r--nptl/sysdeps/unix/sysv/linux/register-atfork.c87
-rw-r--r--nptl/sysdeps/unix/sysv/linux/unregister-atfork.c49
77 files changed, 7901 insertions, 0 deletions
diff --git a/nptl/sysdeps/generic/lowlevellock.h b/nptl/sysdeps/generic/lowlevellock.h
new file mode 100644
index 0000000000..9cffca83e6
--- /dev/null
+++ b/nptl/sysdeps/generic/lowlevellock.h
@@ -0,0 +1,89 @@
+/* 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. */
+
+#include <atomic.h>
+
+
+/* Implement generic mutex. Basic futex syscall support is required:
+
+ lll_futex_wait(futex, value) - call sys_futex with FUTEX_WAIT
+ and third parameter VALUE
+
+ lll_futex_wake(futex, value) - call sys_futex with FUTEX_WAKE
+ and third parameter VALUE
+*/
+
+
+/* Mutex lock counter:
+ bit 31 clear means unlocked;
+ bit 31 set means locked.
+
+ All code that looks at bit 31 first increases the 'number of
+ interested threads' usage counter, which is in bits 0-30.
+
+ All negative mutex values indicate that the mutex is still locked. */
+
+
+static inline void
+__generic_mutex_lock (int *mutex)
+{
+ unsigned int v;
+
+ /* Bit 31 was clear, we got the mutex. (this is the fastpath). */
+ if (atomic_bit_test_set (mutex, 31) == 0)
+ return;
+
+ atomic_increment (mutex);
+
+ while (1)
+ {
+ if (atomic_bit_test_set (mutex, 31) == 0)
+ {
+ atomic_decrement (mutex);
+ return;
+ }
+
+ /* We have to wait now. First make sure the futex value we are
+ monitoring is truly negative (i.e. locked). */
+ v = *mutex;
+ if (v >= 0)
+ continue;
+
+ lll_futex_wait (mutex, v);
+ }
+}
+
+
+static inline void
+__generic_mutex_unlock (int *mutex)
+{
+ /* Adding 0x80000000 to the counter results in 0 if and only if
+ there are not other interested threads - we can return (this is
+ the fastpath). */
+ if (atomic_add_zero (0x80000000, mutex))
+ return;
+
+ /* There are other threads waiting for this mutex, wake one of them
+ up. */
+ lll_futex_wake (mutex, 1);
+}
+
+
+#define lll_mutex_lock(futex) __generic_mutex_lock (&(futex))
+#define lll_mutex_unlock(futex) __generic_mutex_unlock (&(futex))
diff --git a/nptl/sysdeps/generic/pt-raise.c b/nptl/sysdeps/generic/pt-raise.c
new file mode 100644
index 0000000000..59d9590e6e
--- /dev/null
+++ b/nptl/sysdeps/generic/pt-raise.c
@@ -0,0 +1,30 @@
+/* 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. */
+
+#include <pthread.h>
+#include <signal.h>
+
+
+int
+raise (sig)
+ int sig;
+{
+ /* This is what POSIX says must happen. */
+ return pthread_kill (pthread_self (), sig);
+}
diff --git a/nptl/sysdeps/i386/i686/bits/atomic.h b/nptl/sysdeps/i386/i686/bits/atomic.h
new file mode 100644
index 0000000000..7eb7573265
--- /dev/null
+++ b/nptl/sysdeps/i386/i686/bits/atomic.h
@@ -0,0 +1,340 @@
+/* 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. */
+
+#include <stdint.h>
+
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int16_t atomic16_t;
+typedef uint16_t uatomic16_t;
+typedef int_fast16_t atomic_fast16_t;
+typedef uint_fast16_t uatomic_fast16_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+
+#ifndef LOCK
+# ifdef UP
+# define LOCK /* nothing */
+# else
+# define LOCK "lock;"
+# endif
+#endif
+
+
+#define __arch_compare_and_exchange_8_acq(mem, newval, oldval) \
+ ({ unsigned char ret; \
+ __asm __volatile (LOCK "cmpxchgb %2, %1; setne %0" \
+ : "=a" (ret), "=m" (*mem) \
+ : "q" (newval), "1" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_16_acq(mem, newval, oldval) \
+ ({ unsigned char ret; \
+ __asm __volatile (LOCK "cmpxchgw %2, %1; setne %0" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" (newval), "1" (*mem), "0" (oldval)); \
+ ret; })
+
+#define __arch_compare_and_exchange_32_acq(mem, newval, oldval) \
+ ({ unsigned char ret; \
+ __asm __volatile (LOCK "cmpxchgl %2, %1; setne %0" \
+ : "=a" (ret), "=m" (*mem) \
+ : "r" (newval), "1" (*mem), "0" (oldval)); \
+ ret; })
+
+/* XXX We do not really need 64-bit compare-and-exchange. At least
+ not in the moment. Using it would mean causing portability
+ problems since not many other 32-bit architectures have support for
+ such an operation. So don't define any code for now. If it is
+ really going to be used the code below can be used. */
+#if 1
+# define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+ (abort (), 0)
+#else
+# ifdef __PIC__
+# define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+ ({ unsigned char ret; \
+ int ignore; \
+ __asm __volatile ("xchgl %3, %%ebx\n\t" \
+ LOCK "cmpxchg8b %2, %1\n\t" \
+ "setne %0\n\t" \
+ "xchgl %3, %%ebx" \
+ : "=a" (ret), "=m" (*mem), "=d" (ignore) \
+ : "DS" (((unsigned long long int) (newval)) \
+ & 0xffffffff), \
+ "c" (((unsigned long long int) (newval)) >> 32), \
+ "1" (*mem), "0" (((unsigned long long int) (oldval)) \
+ & 0xffffffff), \
+ "2" (((unsigned long long int) (oldval)) >> 32)); \
+ ret; })
+# else
+# define __arch_compare_and_exchange_64_acq(mem, newval, oldval) \
+ ({ unsigned char ret; \
+ int ignore; \
+ __asm __volatile (LOCK "cmpxchg8b %2, %1; setne %0" \
+ : "=a" (ret), "=m" (*mem), "=d" (ignore) \
+ : "b" (((unsigned long long int) (newval)) \
+ & 0xffffffff), \
+ "c" (((unsigned long long int) (newval)) >> 32), \
+ "1" (*mem), "0" (((unsigned long long int) (oldval)) \
+ & 0xffffffff), \
+ "2" (((unsigned long long int) (oldval)) >> 32)); \
+ ret; })
+# endif
+#endif
+
+
+#define atomic_exchange_and_add(mem, value) \
+ ({ __typeof (*mem) result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "xaddb %0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (value), "1" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "xaddw %0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (value), "1" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "xaddl %0, %1" \
+ : "=r" (result), "=m" (*mem) \
+ : "0" (value), "1" (*mem)); \
+ else \
+ { \
+ __typeof (value) addval = (value); \
+ __typeof (*mem) oldval; \
+ __typeof (mem) memp = (mem); \
+ do \
+ result = (oldval = *memp) + addval; \
+ while (! __arch_compare_and_exchange_64_acq (memp, result, oldval)); \
+ } \
+ result; })
+
+
+#define atomic_add(mem, value) \
+ (void) ({ if (__builtin_constant_p (value) && (value) == 1) \
+ atomic_increment (mem); \
+ else if (__builtin_constant_p (value) && (value) == 1) \
+ atomic_decrement (mem); \
+ else if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "addb %1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "addw %1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "addl %1, %0" \
+ : "=m" (*mem) \
+ : "ir" (value), "0" (*mem)); \
+ else \
+ { \
+ __typeof (value) addval = (value); \
+ __typeof (*mem) oldval; \
+ __typeof (mem) memp = (mem); \
+ do \
+ oldval = *memp; \
+ while (! __arch_compare_and_exchange_64_acq (memp, \
+ oldval + addval, \
+ oldval)); \
+ } \
+ })
+
+
+#define atomic_add_negative(mem, value) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "addb %2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "addw %2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "addl %2, %0; sets %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "0" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_add_zero(mem, value) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "addb %2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "addw %2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "addl %2, %0; setz %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "ir" (value), "0" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_increment(mem) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "incb %0" \
+ : "=m" (*mem) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "incw %0" \
+ : "=m" (*mem) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "incl %0" \
+ : "=m" (*mem) \
+ : "0" (*mem)); \
+ else \
+ { \
+ __typeof (*mem) oldval; \
+ __typeof (mem) memp = (mem); \
+ do \
+ oldval = *memp; \
+ while (! __arch_compare_and_exchange_64_acq (memp, \
+ oldval + 1, \
+ oldval)); \
+ } \
+ })
+
+
+#define atomic_increment_and_test(mem) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "incb %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "incw %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "incl %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "0" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_decrement(mem) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "decb %0" \
+ : "=m" (*mem) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "decw %0" \
+ : "=m" (*mem) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "decl %0" \
+ : "=m" (*mem) \
+ : "0" (*mem)); \
+ else \
+ { \
+ __typeof (*mem) oldval; \
+ __typeof (mem) memp = (mem); \
+ do \
+ oldval = *memp; \
+ while (! __arch_compare_and_exchange_64_acq (memp, \
+ oldval - 1, \
+ oldval)); \
+ } \
+ })
+
+
+#define atomic_decrement_and_test(mem) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "decb %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "decw %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "0" (*mem)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "decl %0; sete %1" \
+ : "=m" (*mem), "=qm" (__result) \
+ : "0" (*mem)); \
+ else \
+ abort (); \
+ __result; })
+
+
+#define atomic_bit_set(mem, bit) \
+ (void) ({ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "orb %2, %0" \
+ : "=m" (*mem) \
+ : "0" (*mem), "i" (1 << (bit))); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "orw %2, %0" \
+ : "=m" (*mem) \
+ : "0" (*mem), "i" (1 << (bit))); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "orl %2, %0" \
+ : "=m" (*mem) \
+ : "0" (*mem), "i" (1 << (bit))); \
+ else \
+ abort (); \
+ })
+
+
+#define atomic_bit_test_set(mem, bit) \
+ ({ unsigned char __result; \
+ if (sizeof (*mem) == 1) \
+ __asm __volatile (LOCK "btsb %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "1" (*mem), "i" (bit)); \
+ else if (sizeof (*mem) == 2) \
+ __asm __volatile (LOCK "btsw %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "1" (*mem), "i" (bit)); \
+ else if (sizeof (*mem) == 4) \
+ __asm __volatile (LOCK "btsl %3, %1; setc %0" \
+ : "=q" (__result), "=m" (*mem) \
+ : "1" (*mem), "i" (bit)); \
+ else \
+ abort (); \
+ __result; })
diff --git a/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/nptl/sysdeps/i386/i686/pthread_spin_trylock.S
new file mode 100644
index 0000000000..881976c4fe
--- /dev/null
+++ b/nptl/sysdeps/i386/i686/pthread_spin_trylock.S
@@ -0,0 +1,34 @@
+/* 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. */
+
+#define EBUSY 16
+
+ .globl pthread_spin_trylock
+ .type pthread_spin_trylock,@function
+ .align 16
+pthread_spin_trylock:
+ movl 4(%esp), %edx
+ movl $1, %eax
+ xorl %ecx, %ecx
+ cmpxchgl %ecx, (%edx)
+ movl $EBUSY, %ecx
+ movl $0, %eax
+ cmovne %ecx, %eax
+ ret
+ .size pthread_spin_trylock,.-pthread_spin_trylock
diff --git a/nptl/sysdeps/i386/i686/tls.h b/nptl/sysdeps/i386/i686/tls.h
new file mode 100644
index 0000000000..4025ed8d21
--- /dev/null
+++ b/nptl/sysdeps/i386/i686/tls.h
@@ -0,0 +1,36 @@
+/* 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. */
+
+#ifndef _TLS_H
+
+/* Additional definitions for <tls.h> on i686 and up. */
+
+
+/* Macros to load from and store into segment registers. We can use
+ the 32-bit instructions. */
+#define TLS_GET_GS() \
+ ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; })
+#define TLS_SET_GS(val) \
+ __asm ("movl %0, %%gs" :: "q" (val))
+
+
+/* Get the full set of definitions. */
+#include "../tls.h"
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/i386/pthread_sigmask.c b/nptl/sysdeps/i386/pthread_sigmask.c
new file mode 100644
index 0000000000..2ae9198c02
--- /dev/null
+++ b/nptl/sysdeps/i386/pthread_sigmask.c
@@ -0,0 +1,34 @@
+/* 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. */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthreadP.h>
+#include <tls.h>
+#include <sysdep.h>
+
+
+int
+pthread_sigmask (how, newmask, oldmask)
+ int how;
+ const sigset_t *newmask;
+ sigset_t *oldmask;
+{
+ return INLINE_SYSCALL (sigprocmask, 3, how, newmask, oldmask);
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_destroy.c b/nptl/sysdeps/i386/pthread_spin_destroy.c
new file mode 100644
index 0000000000..4d0109cf02
--- /dev/null
+++ b/nptl/sysdeps/i386/pthread_spin_destroy.c
@@ -0,0 +1,29 @@
+/* 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. */
+
+#include "pthreadP.h"
+
+
+int
+pthread_spin_destroy (lock)
+ pthread_spinlock_t *lock;
+{
+ /* Nothing to do. */
+ return 0;
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_init.c b/nptl/sysdeps/i386/pthread_spin_init.c
new file mode 100644
index 0000000000..0a47981aa2
--- /dev/null
+++ b/nptl/sysdeps/i386/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/nptl/sysdeps/i386/pthread_spin_lock.c b/nptl/sysdeps/i386/pthread_spin_lock.c
new file mode 100644
index 0000000000..43a1831131
--- /dev/null
+++ b/nptl/sysdeps/i386/pthread_spin_lock.c
@@ -0,0 +1,48 @@
+/* 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. */
+
+#include "pthreadP.h"
+
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK "lock;"
+#endif
+
+
+int
+pthread_spin_lock (lock)
+ pthread_spinlock_t *lock;
+{
+ asm ("\n"
+ "1:\t" LOCK "decl %0\n\t"
+ "jne 2f\n\t"
+ ".subsection 1\n\t"
+ ".align 16\n"
+ "2:\trep; nop\n\t"
+ "cmpl $0, %0\n\t"
+ "jg 1b\n\t"
+ "jmp 2b\n\t"
+ ".previous"
+ : "=m" (*lock)
+ : "0" (*lock));
+
+ return 0;
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_unlock.S b/nptl/sysdeps/i386/pthread_spin_unlock.S
new file mode 100644
index 0000000000..d94f1e7b8c
--- /dev/null
+++ b/nptl/sysdeps/i386/pthread_spin_unlock.S
@@ -0,0 +1,32 @@
+/* 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. */
+
+ .globl pthread_spin_unlock
+ .type pthread_spin_unlock,@function
+ .align 16
+pthread_spin_unlock:
+ movl 4(%esp), %eax
+ movl $1, (%eax)
+ xorl %eax, %eax
+ ret
+ .size pthread_spin_unlock,.-pthread_spin_unlock
+
+ /* The implementation of pthread_spin_init is identical. */
+ .globl pthread_spin_init
+pthread_spin_init = pthread_spin_unlock
diff --git a/nptl/sysdeps/i386/pthreaddef.h b/nptl/sysdeps/i386/pthreaddef.h
new file mode 100644
index 0000000000..6efa1b6d82
--- /dev/null
+++ b/nptl/sysdeps/i386/pthreaddef.h
@@ -0,0 +1,55 @@
+/* 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. */
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. SSE requires 16
+ bytes. */
+#define STACK_ALIGN 16
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 16
+
+/* The signal used for asynchronous cancelation. */
+#define SIGCANCEL __SIGRTMIN
+
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here. */
+
+/* While there is no such syscall. */
+#define __exit_thread_inline(val) \
+ while (1) { \
+ if (__builtin_constant_p (val) && (val) == 0) \
+ asm volatile ("xorl %%ebx, %%ebx; int $0x80" :: "a" (__NR_exit)); \
+ else \
+ asm volatile ("movl %1, %%ebx; int $0x80" \
+ :: "a" (__NR_exit), "r" (val)); \
+ }
+#define gettid() \
+ ({ int tid; \
+ __asm __volatile ("int $0x80" : "=a" (tid) : "0" (__NR_gettid)); \
+ tid; })
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
new file mode 100644
index 0000000000..244a487bcb
--- /dev/null
+++ b/nptl/sysdeps/i386/tls.h
@@ -0,0 +1,332 @@
+/* Definition for thread-local data handling. linuxthreads/i386 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. */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#ifndef __ASSEMBLER__
+# include <stddef.h>
+# include <stdint.h>
+
+
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ void *pointer;
+} dtv_t;
+
+
+typedef struct
+{
+ void *tcb; /* Pointer to the TCB. Not necessary the
+ thread descriptor used by libpthread. */
+ dtv_t *dtv;
+ void *self; /* Pointer to the thread descriptor. */
+} tcbhead_t;
+#endif
+
+
+/* We require TLS support in the tools. */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* Signal that TLS support is available. */
+#define USE_TLS 1
+
+/* Alignment requirement for the stack. For IA-32 this is govern by
+ the SSE memory functions. */
+#define STACK_ALIGN 16
+
+
+#ifndef __ASSEMBLER__
+/* Get system call information. */
+# include <sysdep.h>
+
+/* The old way: using LDT. */
+
+/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls. */
+struct user_desc
+{
+ unsigned int entry_number;
+ unsigned long int base_addr;
+ unsigned int limit;
+ unsigned int seg_32bit:1;
+ unsigned int contents:2;
+ unsigned int read_exec_only:1;
+ unsigned int limit_in_pages:1;
+ unsigned int seg_not_present:1;
+ unsigned int useable:1;
+ unsigned int empty:25;
+};
+
+/* Initializing bit fields is slow. We speed it up by using a union. */
+union user_desc_init
+{
+ struct user_desc desc;
+ unsigned int vals[4];
+};
+
+
+/* Get the thread descriptor definition. */
+# include <nptl/descr.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 (struct pthread)
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* The TCB can have any size and the memory following the address the
+ thread pointer points to is unspecified. Allocate the TCB there. */
+# define TLS_TCB_AT_TP 1
+
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(descr, dtvp) \
+ ((tcbhead_t *) (descr))->dtv = dtvp + 1
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) \
+ ({ struct pthread *__pd; \
+ THREAD_SETMEM (__pd, header.data.dtvp, dtv); })
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(descr) \
+ (((tcbhead_t *) (descr))->dtv)
+
+
+/* Macros to load from and store into segment registers. */
+# ifndef TLS_GET_GS
+# define TLS_GET_GS() \
+ ({ int __seg; __asm ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; })
+# endif
+# ifndef TLS_SET_GS
+# define TLS_SET_GS(val) \
+ __asm ("movw %w0, %%gs" :: "q" (val))
+# endif
+
+
+# ifndef __NR_set_thread_area
+# define __NR_set_thread_area 243
+# endif
+# ifndef TLS_FLAG_WRITABLE
+# define TLS_FLAG_WRITABLE 0x00000001
+# endif
+
+// XXX Enable for the real world.
+#if 0
+# ifndef __ASSUME_SET_THREAD_AREA
+# error "we need set_thread_area"
+# endif
+#endif
+
+# ifdef __PIC__
+# define TLS_EBX_ARG "r"
+# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
+# else
+# define TLS_EBX_ARG "b"
+# define TLS_LOAD_EBX
+# endif
+
+/* 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(thrdescr, secondcall) \
+ ({ void *_thrdescr = (thrdescr); \
+ tcbhead_t *_head = _thrdescr; \
+ union user_desc_init _segdescr; \
+ int _result; \
+ \
+ _head->tcb = _thrdescr; \
+ /* For now the thread descriptor is at the same address. */ \
+ _head->self = _thrdescr; \
+ \
+ /* The 'entry_number' field. Let the kernel pick a value. */ \
+ if (secondcall) \
+ _segdescr.vals[0] = TLS_GET_GS () >> 3; \
+ else \
+ _segdescr.vals[0] = -1; \
+ /* The 'base_addr' field. Pointer to the TCB. */ \
+ _segdescr.vals[1] = (unsigned long int) _thrdescr; \
+ /* The 'limit' field. We use 4GB which is 0xfffff pages. */ \
+ _segdescr.vals[2] = 0xfffff; \
+ /* Collapsed value of the bitfield: \
+ .seg_32bit = 1 \
+ .contents = 0 \
+ .read_exec_only = 0 \
+ .limit_in_pages = 1 \
+ .seg_not_present = 0 \
+ .useable = 1 */ \
+ _segdescr.vals[3] = 0x51; \
+ \
+ /* Install the TLS. */ \
+ asm volatile (TLS_LOAD_EBX \
+ "int $0x80\n\t" \
+ TLS_LOAD_EBX \
+ : "=a" (_result), "=m" (_segdescr.desc.entry_number) \
+ : "0" (__NR_set_thread_area), \
+ TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \
+ \
+ if (_result == 0) \
+ /* We know the index in the GDT, now load the segment register. \
+ The use of the GDT is described by the value 3 in the lower \
+ three bits of the segment descriptor value. \
+ \
+ Note that we have to do this even if the numeric value of \
+ the descriptor does not change. Loading the segment register \
+ causes the segment information from the GDT to be loaded \
+ which is necessary since we have changed it. */ \
+ TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3); \
+ \
+ _result; })
+
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ ({ struct pthread *__pd; \
+ THREAD_GETMEM (__pd, header.data.dtvp); })
+
+
+/* Return the thread descriptor for the current thread.
+
+ The contained asm must *not* be marked volatile since otherwise
+ assignments like
+ pthread_descr self = thread_self();
+ do not get optimized away. */
+# define THREAD_SELF \
+ ({ struct pthread *__self; \
+ asm ("movl %%gs:%c1,%0" : "=r" (__self) \
+ : "i" (offsetof (struct pthread, header.data.self))); \
+ __self;})
+
+
+/* Read member of the thread descriptor directly. */
+# define THREAD_GETMEM(descr, member) \
+ ({ __typeof (descr->member) __value; \
+ if (sizeof (__value) == 1) \
+ asm ("movb %%gs:%P2,%b0" \
+ : "=q" (__value) \
+ : "0" (0), "i" (offsetof (struct pthread, member))); \
+ else if (sizeof (__value) == 4) \
+ asm ("movl %%gs:%P1,%0" \
+ : "=r" (__value) \
+ : "i" (offsetof (struct pthread, member))); \
+ else \
+ { \
+ if (sizeof (__value) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm ("movl %%gs:%P1,%%eax\n\t" \
+ "movl %%gs:%P2,%%edx" \
+ : "=A" (__value) \
+ : "i" (offsetof (struct pthread, member)), \
+ "i" (offsetof (struct pthread, member) + 4)); \
+ } \
+ __value; })
+
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
+# define THREAD_GETMEM_NC(descr, member) \
+ ({ __typeof (descr->member) __value; \
+ if (sizeof (__value) == 1) \
+ asm ("movb %%gs:(%2),%b0" \
+ : "=q" (__value) \
+ : "0" (0), "r" (offsetof (struct pthread, member))); \
+ else if (sizeof (__value) == 4) \
+ asm ("movl %%gs:(%1),%0" \
+ : "=r" (__value) \
+ : "r" (offsetof (struct pthread, member))); \
+ else \
+ { \
+ if (sizeof (__value) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm ("movl %%gs:(%1),%%eax\n\t" \
+ "movl %%gs:4(%1),%%edx" \
+ : "=&A" (__value) \
+ : "r" (offsetof (struct pthread, member))); \
+ } \
+ __value; })
+
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
+# define THREAD_SETMEM(descr, member, value) \
+ ({ if (sizeof (value) == 1) \
+ asm volatile ("movb %0,%%gs:%P1" : \
+ : "iq" (value), \
+ "i" (offsetof (struct pthread, member))); \
+ else if (sizeof (value) == 4) \
+ asm volatile ("movl %0,%%gs:%P1" : \
+ : "ir" (value), \
+ "i" (offsetof (struct pthread, member))); \
+ else \
+ { \
+ if (sizeof (value) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm volatile ("movl %%eax,%%gs:%P1\n\n" \
+ "movl %%edx,%%gs:%P2" : \
+ : "A" (value), \
+ "i" (offsetof (struct pthread, member)), \
+ "i" (offsetof (struct pthread, member) + 4)); \
+ }})
+
+
+/* Set member of the thread descriptor directly. */
+# define THREAD_SETMEM_NC(descr, member, value) \
+ ({ if (sizeof (value) == 1) \
+ asm volatile ("movb %0,%%gs:(%1)" : \
+ : "iq" (value), \
+ "r" (offsetof (struct pthread, member))); \
+ else if (sizeof (value) == 4) \
+ asm volatile ("movl %0,%%gs:(%1)" : \
+ : "ir" (value), \
+ "r" (offsetof (struct pthread, member))); \
+ else \
+ { \
+ if (sizeof (value) != 8) \
+ /* There should not be any value with a size other than 1, \
+ 4 or 8. */ \
+ abort (); \
+ \
+ asm volatile ("movl %%eax,%%gs:(%1)\n\t" \
+ "movl %%edx,%%gs:4(%1)" : \
+ : "A" (value), \
+ "r" (offsetof (struct pthread, member))); \
+ }})
+
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/pthread/Makefile b/nptl/sysdeps/pthread/Makefile
new file mode 100644
index 0000000000..fade787877
--- /dev/null
+++ b/nptl/sysdeps/pthread/Makefile
@@ -0,0 +1,33 @@
+# 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.
+
+ifeq ($(subdir),nptl)
+libpthread-sysdep_routines += errno-loc
+endif
+
+ifeq ($(subdir),rt)
+librt-sysdep_routines += timer_routines
+CPPFLAGS-timer_routines.c = -I../nptl
+
+ifeq (yes,$(build-shared))
+$(objpfx)tst-timer: $(objpfx)librt.so $(shared-thread-library)
+else
+$(objpfx)tst-timer: $(objpfx)librt.a $(static-thread-library)
+endif
+endif
diff --git a/nptl/sysdeps/pthread/Subdirs b/nptl/sysdeps/pthread/Subdirs
new file mode 100644
index 0000000000..4d1f4d876b
--- /dev/null
+++ b/nptl/sysdeps/pthread/Subdirs
@@ -0,0 +1 @@
+nptl_db
diff --git a/nptl/sysdeps/pthread/allocalim.h b/nptl/sysdeps/pthread/allocalim.h
new file mode 100644
index 0000000000..2d666c0b0a
--- /dev/null
+++ b/nptl/sysdeps/pthread/allocalim.h
@@ -0,0 +1,29 @@
+/* Determine whether block of given size can be allocated on the stack or not.
+ 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <alloca.h>
+#include <limits.h>
+
+
+extern inline int
+__libc_use_alloca (size_t size)
+{
+ return (__builtin_expect (size <= PTHREAD_STACK_MIN / 4, 1)
+ || __libc_alloca_cutoff (size));
+}
diff --git a/nptl/sysdeps/pthread/bits/libc-lock.h b/nptl/sysdeps/pthread/bits/libc-lock.h
new file mode 100644
index 0000000000..0001676a3b
--- /dev/null
+++ b/nptl/sysdeps/pthread/bits/libc-lock.h
@@ -0,0 +1,335 @@
+/* libc-internal interface for mutex locks. LinuxThreads version.
+ Copyright (C) 1996-2001, 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_LIBC_LOCK_H
+#define _BITS_LIBC_LOCK_H 1
+
+#include <pthread.h>
+#define __need_NULL
+#include <stddef.h>
+
+/* Mutex type. */
+#if defined(_LIBC) || defined(_IO_MTSAFE_IO)
+typedef pthread_mutex_t __libc_lock_t;
+typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t;
+# ifdef __USE_UNIX98
+typedef pthread_rwlock_t __libc_rwlock_t;
+# else
+typedef struct __libc_rwlock_opaque__ __libc_rwlock_t;
+# endif
+#else
+typedef struct __libc_lock_opaque__ __libc_lock_t;
+typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
+typedef struct __libc_rwlock_opaque__ __libc_rwlock_t;
+#endif
+
+/* Type for key to thread-specific data. */
+typedef pthread_key_t __libc_key_t;
+
+/* Define a lock variable NAME with storage class CLASS. The lock must be
+ initialized with __libc_lock_init before it can be used (or define it
+ with __libc_lock_define_initialized, below). Use `extern' for CLASS to
+ declare a lock defined in another module. In public structure
+ definitions you must use a pointer to the lock structure (i.e., NAME
+ begins with a `*'), because its storage size will not be known outside
+ of libc. */
+#define __libc_lock_define(CLASS,NAME) \
+ CLASS __libc_lock_t NAME;
+#define __libc_rwlock_define(CLASS,NAME) \
+ CLASS __libc_rwlock_t NAME;
+#define __libc_lock_define_recursive(CLASS,NAME) \
+ CLASS __libc_lock_recursive_t NAME;
+
+/* Define an initialized lock variable NAME with storage class CLASS.
+
+ For the C library we take a deeper look at the initializer. For
+ this implementation all fields are initialized to zero. Therefore
+ we don't initialize the variable which allows putting it into the
+ BSS section. (Except on PA-RISC and other odd architectures, where
+ initialized locks must be set to one due to the lack of normal
+ atomic operations.) */
+
+#if __LT_SPINLOCK_INIT == 0
+# define __libc_lock_define_initialized(CLASS,NAME) \
+ CLASS __libc_lock_t NAME;
+#else
+# define __libc_lock_define_initialized(CLASS,NAME) \
+ CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#define __libc_rwlock_define_initialized(CLASS,NAME) \
+ CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER;
+
+/* Define an initialized recursive lock variable NAME with storage
+ class CLASS. */
+#define __libc_lock_define_initialized_recursive(CLASS,NAME) \
+ CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
+#define _LIBC_LOCK_RECURSIVE_INITIALIZER \
+ {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}
+
+/* Initialize the named lock variable, leaving it in a consistent, unlocked
+ state. */
+#define __libc_lock_init(NAME) \
+ (__pthread_mutex_init != NULL ? __pthread_mutex_init (&(NAME), NULL) : 0);
+#define __libc_rwlock_init(NAME) \
+ (__pthread_rwlock_init != NULL ? __pthread_rwlock_init (&(NAME), NULL) : 0);
+
+/* Same as last but this time we initialize a recursive mutex. */
+#define __libc_lock_init_recursive(NAME) \
+ do { \
+ if (__pthread_mutex_init != NULL) \
+ { \
+ pthread_mutexattr_t __attr; \
+ __pthread_mutexattr_init (&__attr); \
+ __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \
+ __pthread_mutex_init (&(NAME).mutex, &__attr); \
+ __pthread_mutexattr_destroy (&__attr); \
+ } \
+ } while (0);
+
+/* Finalize the named lock variable, which must be locked. It cannot be
+ used again until __libc_lock_init is called again on it. This must be
+ called on a lock variable before the containing storage is reused. */
+#define __libc_lock_fini(NAME) \
+ (__pthread_mutex_destroy != NULL ? __pthread_mutex_destroy (&(NAME)) : 0);
+#define __libc_rwlock_fini(NAME) \
+ (__pthread_rwlock_destroy != NULL ? __pthread_rwlock_destroy (&(NAME)) : 0);
+
+/* Finalize recursive named lock. */
+#define __libc_lock_fini_recursive(NAME) __libc_lock_fini ((NAME).mutex)
+
+/* Lock the named lock variable. */
+#define __libc_lock_lock(NAME) \
+ (__pthread_mutex_lock != NULL ? __pthread_mutex_lock (&(NAME)) : 0);
+#define __libc_rwlock_rdlock(NAME) \
+ (__pthread_rwlock_rdlock != NULL ? __pthread_rwlock_rdlock (&(NAME)) : 0);
+#define __libc_rwlock_wrlock(NAME) \
+ (__pthread_rwlock_wrlock != NULL ? __pthread_rwlock_wrlock (&(NAME)) : 0);
+
+/* Lock the recursive named lock variable. */
+#define __libc_lock_lock_recursive(NAME) __libc_lock_lock ((NAME).mutex)
+
+/* Try to lock the named lock variable. */
+#define __libc_lock_trylock(NAME) \
+ (__pthread_mutex_trylock != NULL ? __pthread_mutex_trylock (&(NAME)) : 0)
+#define __libc_rwlock_tryrdlock(NAME) \
+ (__pthread_rwlock_tryrdlock != NULL \
+ ? __pthread_rwlock_tryrdlock (&(NAME)) : 0)
+#define __libc_rwlock_trywrlock(NAME) \
+ (__pthread_rwlock_trywrlock != NULL \
+ ? __pthread_rwlock_trywrlock (&(NAME)) : 0)
+
+/* Try to lock the recursive named lock variable. */
+#define __libc_lock_trylock_recursive(NAME) __libc_lock_trylock ((NAME).mutex)
+
+/* Unlock the named lock variable. */
+#define __libc_lock_unlock(NAME) \
+ (__pthread_mutex_unlock != NULL ? __pthread_mutex_unlock (&(NAME)) : 0);
+#define __libc_rwlock_unlock(NAME) \
+ (__pthread_rwlock_unlock != NULL ? __pthread_rwlock_unlock (&(NAME)) : 0);
+
+/* Unlock the recursive named lock variable. */
+#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex)
+
+
+/* Define once control variable. */
+#if PTHREAD_ONCE_INIT == 0
+/* Special case for static variables where we can avoid the initialization
+ if it is zero. */
+# define __libc_once_define(CLASS, NAME) \
+ CLASS pthread_once_t NAME
+#else
+# define __libc_once_define(CLASS, NAME) \
+ CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT
+#endif
+
+/* Call handler iff the first call. */
+#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
+ do { \
+ if (__pthread_once != NULL) \
+ __pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \
+ else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \
+ INIT_FUNCTION (); \
+ (ONCE_CONTROL) = !PTHREAD_ONCE_INIT; \
+ } \
+ } while (0)
+
+
+/* Start critical region with cleanup. */
+#define __libc_cleanup_region_start(DOIT, FCT, ARG) \
+ { struct _pthread_cleanup_buffer _buffer; \
+ int _avail = (DOIT) && _pthread_cleanup_push_defer != NULL; \
+ if (_avail) { \
+ _pthread_cleanup_push_defer (&_buffer, (FCT), (ARG)); \
+ }
+
+/* End critical region with cleanup. */
+#define __libc_cleanup_region_end(DOIT) \
+ if (_avail) { \
+ _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \
+ } \
+ }
+
+/* Sometimes we have to exit the block in the middle. */
+#define __libc_cleanup_end(DOIT) \
+ if (_avail) { \
+ _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \
+ }
+
+/* Create thread-specific key. */
+#define __libc_key_create(KEY, DESTRUCTOR) \
+ (__pthread_key_create != NULL ? __pthread_key_create (KEY, DESTRUCTOR) : 1)
+
+/* Get thread-specific data. */
+#define __libc_getspecific(KEY) \
+ (__pthread_getspecific != NULL ? __pthread_getspecific (KEY) : NULL)
+
+/* Set thread-specific data. */
+#define __libc_setspecific(KEY, VALUE) \
+ (__pthread_setspecific != NULL ? __pthread_setspecific (KEY, VALUE) : 0)
+
+
+/* Register handlers to execute before and after `fork'. Note that the
+ last parameter is NULL. The handlers registered by the libc are
+ never removed so this is OK. */
+#define __libc_atfork(PREPARE, PARENT, CHILD) \
+ __register_atfork (PREPARE, PARENT, CHILD, NULL)
+extern int __register_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void),
+ void *__dso_handle);
+
+/* Functions that are used by this file and are internal to the GNU C
+ library. */
+
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+ __const pthread_mutexattr_t *__mutex_attr);
+
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+
+extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr);
+
+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr,
+ int __kind);
+
+#ifdef __USE_UNIX98
+extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock,
+ __const pthread_rwlockattr_t *__attr);
+
+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
+
+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
+#endif
+
+extern int __pthread_key_create (pthread_key_t *__key,
+ void (*__destr_function) (void *));
+
+extern int __pthread_setspecific (pthread_key_t __key,
+ __const void *__pointer);
+
+extern void *__pthread_getspecific (pthread_key_t __key);
+
+extern int __pthread_once (pthread_once_t *__once_control,
+ void (*__init_routine) (void));
+
+extern int __pthread_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void));
+
+
+
+/* Make the pthread functions weak so that we can elide them from
+ single-threaded processes. */
+#ifndef __NO_WEAK_PTHREAD_ALIASES
+# ifdef weak_extern
+# if _LIBC
+# include <bp-sym.h>
+# else
+# define BP_SYM (sym) sym
+# endif
+weak_extern (BP_SYM (__pthread_mutex_init))
+weak_extern (BP_SYM (__pthread_mutex_destroy))
+weak_extern (BP_SYM (__pthread_mutex_lock))
+weak_extern (BP_SYM (__pthread_mutex_trylock))
+weak_extern (BP_SYM (__pthread_mutex_unlock))
+weak_extern (BP_SYM (__pthread_mutexattr_init))
+weak_extern (BP_SYM (__pthread_mutexattr_destroy))
+weak_extern (BP_SYM (__pthread_mutexattr_settype))
+weak_extern (BP_SYM (__pthread_rwlock_init))
+weak_extern (BP_SYM (__pthread_rwlock_destroy))
+weak_extern (BP_SYM (__pthread_rwlock_rdlock))
+weak_extern (BP_SYM (__pthread_rwlock_tryrdlock))
+weak_extern (BP_SYM (__pthread_rwlock_wrlock))
+weak_extern (BP_SYM (__pthread_rwlock_trywrlock))
+weak_extern (BP_SYM (__pthread_rwlock_unlock))
+weak_extern (BP_SYM (__pthread_key_create))
+weak_extern (BP_SYM (__pthread_setspecific))
+weak_extern (BP_SYM (__pthread_getspecific))
+weak_extern (BP_SYM (__pthread_once))
+weak_extern (__pthread_initialize)
+weak_extern (__pthread_atfork)
+weak_extern (BP_SYM (_pthread_cleanup_push_defer))
+weak_extern (BP_SYM (_pthread_cleanup_pop_restore))
+# else
+# pragma weak __pthread_mutex_init
+# pragma weak __pthread_mutex_destroy
+# pragma weak __pthread_mutex_lock
+# pragma weak __pthread_mutex_trylock
+# pragma weak __pthread_mutex_unlock
+# pragma weak __pthread_mutexattr_init
+# pragma weak __pthread_mutexattr_destroy
+# pragma weak __pthread_mutexattr_settype
+# pragma weak __pthread_rwlock_destroy
+# pragma weak __pthread_rwlock_rdlock
+# pragma weak __pthread_rwlock_tryrdlock
+# pragma weak __pthread_rwlock_wrlock
+# pragma weak __pthread_rwlock_trywrlock
+# pragma weak __pthread_rwlock_unlock
+# pragma weak __pthread_key_create
+# pragma weak __pthread_setspecific
+# pragma weak __pthread_getspecific
+# pragma weak __pthread_once
+# pragma weak __pthread_initialize
+# pragma weak __pthread_atfork
+# pragma weak _pthread_cleanup_push_defer
+# pragma weak _pthread_cleanup_pop_restore
+# endif
+#endif
+
+/* We need portable names for some functions. E.g., when they are
+ used as argument to __libc_cleanup_region_start. */
+#define __libc_mutex_unlock __pthread_mutex_unlock
+
+#endif /* bits/libc-lock.h */
diff --git a/nptl/sysdeps/pthread/bits/sigthread.h b/nptl/sysdeps/pthread/bits/sigthread.h
new file mode 100644
index 0000000000..df2bcac291
--- /dev/null
+++ b/nptl/sysdeps/pthread/bits/sigthread.h
@@ -0,0 +1,38 @@
+/* Signal handling function for threaded programs.
+ Copyright (C) 1998, 1999, 2000, 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _BITS_SIGTHREAD_H
+#define _BITS_SIGTHREAD_H 1
+
+#if !defined _SIGNAL_H && !defined _PTHREAD_H
+# error "Never include this file directly. Use <pthread.h> instead"
+#endif
+
+/* Functions for handling signals. */
+
+/* Modify the signal mask for the calling thread. The arguments have
+ the same meaning as for sigprocmask(2). */
+extern int pthread_sigmask (int __how,
+ __const __sigset_t *__restrict __newmask,
+ __sigset_t *__restrict __oldmask)__THROW;
+
+/* Send signal SIGNO to the given thread. */
+extern int pthread_kill (pthread_t __threadid, int __signo) __THROW;
+
+#endif /* bits/sigthread.h */
diff --git a/nptl/sysdeps/pthread/list.h b/nptl/sysdeps/pthread/list.h
new file mode 100644
index 0000000000..1d6a4cfa65
--- /dev/null
+++ b/nptl/sysdeps/pthread/list.h
@@ -0,0 +1,116 @@
+/* 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. */
+
+#ifndef _LIST_H
+#define _LIST_H 1
+
+#include <assert.h>
+
+/* The definitions of this file are adopted from those which can be
+ found in the Linux kernel headers to enable people familiar with
+ the latter find their way in these sources as well. */
+
+
+/* Basic type for the double-link list. */
+typedef struct list_head
+{
+ struct list_head *next;
+ struct list_head *prev;
+} list_t;
+
+
+/* Define a variable with the head and tail of the list. */
+#define LIST_HEAD(name) \
+ list_t name = { &(name), &(name) }
+
+/* Initialize a new list head. */
+#define INIT_LIST_HEAD(ptr) \
+ (ptr)->next = (ptr)->prev = (ptr)
+
+
+/* Add new element at the head of the list. */
+static inline void
+list_add (list_t *newp, list_t *head)
+{
+ head->next->prev = newp;
+ newp->next = head->next;
+ newp->prev = head;
+ head->next = newp;
+}
+
+
+/* Add new element at the tail of the list. */
+static inline void
+list_add_tail (list_t *newp, list_t *head)
+{
+ head->prev->next = newp;
+ newp->next = head;
+ newp->prev = head->prev;
+ head->prev = newp;
+}
+
+
+/* Remove element from list. */
+static inline void
+list_del (list_t *elem)
+{
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+}
+
+
+/* Join two lists. */
+static inline void
+list_splice (list_t *add, list_t *head)
+{
+ /* Do nothing if the list which gets added is empty. */
+ if (add != add->next)
+ {
+ add->next->prev = head;
+ add->prev->next = head->next;
+ head->next->prev = add->prev;
+ head->next = add->next;
+ }
+}
+
+
+/* Get typed element from list at a given position. */
+#define list_entry(ptr, type, member) \
+ ((type *) ((char *) (ptr) - (unsigned long) (&((type *) 0)->member)))
+
+
+
+/* Iterate forward over the elements of the list. */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+
+/* Iterate forward over the elements of the list. */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+
+/* Iterate backwards over the elements list. The list elements can be
+ removed from the list while doing this. */
+#define list_for_each_prev_safe(pos, p, head) \
+ for (pos = (head)->prev, p = pos->prev; \
+ pos != (head); \
+ pos = p, p = pos->prev)
+
+#endif /* list.h */
diff --git a/nptl/sysdeps/pthread/posix-timer.h b/nptl/sysdeps/pthread/posix-timer.h
new file mode 100644
index 0000000000..6710291b9b
--- /dev/null
+++ b/nptl/sysdeps/pthread/posix-timer.h
@@ -0,0 +1,210 @@
+/* Definitions for POSIX timer implementation on top of LinuxThreads.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <limits.h>
+#include <signal.h>
+
+/* Double linked list. */
+struct list_links
+{
+ struct list_links *next;
+ struct list_links *prev;
+};
+
+
+/* Forward declaration. */
+struct timer_node;
+
+
+/* Definitions for an internal thread of the POSIX timer implementation. */
+struct thread_node
+{
+ struct list_links links;
+ pthread_attr_t attr;
+ pthread_t id;
+ unsigned int exists;
+ struct list_links timer_queue;
+ pthread_cond_t cond;
+ struct timer_node *current_timer;
+ pthread_t captured;
+ clockid_t clock_id;
+};
+
+
+/* Internal representation of a timer. */
+struct timer_node
+{
+ struct list_links links;
+ struct sigevent event;
+ clockid_t clock;
+ struct itimerspec value;
+ struct timespec expirytime;
+ pthread_attr_t attr;
+ unsigned int abstime;
+ unsigned int armed;
+ enum {
+ TIMER_FREE, TIMER_INUSE, TIMER_DELETED
+ } inuse;
+ struct thread_node *thread;
+ pid_t creator_pid;
+ int refcount;
+ int overrun_count;
+};
+
+
+/* Static array with the structures for all the timers. */
+extern struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists. */
+extern pthread_mutex_t __timer_mutex;
+
+/* Variable to protext initialization. */
+extern pthread_once_t __timer_init_once_control;
+
+/* Nonzero if initialization of timer implementation failed. */
+extern int __timer_init_failed;
+
+/* Nodes for the threads used to deliver signals. */
+/* A distinct thread is used for each clock type. */
+
+extern struct thread_node __timer_signal_thread_rclk;
+#ifdef _POSIX_CPUTIME
+extern struct thread_node __timer_signal_thread_pclk;
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+extern struct thread_node __timer_signal_thread_tclk;
+#endif
+
+
+/* Return pointer to timer structure corresponding to ID. */
+static inline struct timer_node *
+timer_id2ptr (timer_t timerid)
+{
+ if (timerid >= 0 && timerid < TIMER_MAX)
+ return &__timer_array[timerid];
+
+ return NULL;
+}
+
+/* Return ID of TIMER. */
+static inline int
+timer_ptr2id (struct timer_node *timer)
+{
+ return timer - __timer_array;
+}
+
+/* Check whether timer is valid; global mutex must be held. */
+static inline int
+timer_valid (struct timer_node *timer)
+{
+ return timer && timer->inuse == TIMER_INUSE;
+}
+
+/* Timer refcount functions; need global mutex. */
+extern void __timer_dealloc (struct timer_node *timer);
+
+static inline void
+timer_addref (struct timer_node *timer)
+{
+ timer->refcount++;
+}
+
+static inline void
+timer_delref (struct timer_node *timer)
+{
+ if (--timer->refcount == 0)
+ __timer_dealloc (timer);
+}
+
+/* Timespec helper routines. */
+static inline int
+timespec_compare (const struct timespec *left, const struct timespec *right)
+{
+ if (left->tv_sec < right->tv_sec)
+ return -1;
+ if (left->tv_sec > right->tv_sec)
+ return 1;
+
+ if (left->tv_nsec < right->tv_nsec)
+ return -1;
+ if (left->tv_nsec > right->tv_nsec)
+ return 1;
+
+ return 0;
+}
+
+static inline void
+timespec_add (struct timespec *sum, const struct timespec *left,
+ const struct timespec *right)
+{
+ sum->tv_sec = left->tv_sec + right->tv_sec;
+ sum->tv_nsec = left->tv_nsec + right->tv_nsec;
+
+ if (sum->tv_nsec >= 1000000000)
+ {
+ ++sum->tv_sec;
+ sum->tv_nsec -= 1000000000;
+ }
+}
+
+static inline void
+timespec_sub (struct timespec *diff, const struct timespec *left,
+ const struct timespec *right)
+{
+ diff->tv_sec = left->tv_sec - right->tv_sec;
+ diff->tv_nsec = left->tv_nsec - right->tv_nsec;
+
+ if (diff->tv_nsec < 0)
+ {
+ --diff->tv_sec;
+ diff->tv_nsec += 1000000000;
+ }
+}
+
+
+/* We need one of the list functions in the other modules. */
+static inline void
+list_unlink_ip (struct list_links *list)
+{
+ struct list_links *lnext = list->next, *lprev = list->prev;
+
+ lnext->prev = lprev;
+ lprev->next = lnext;
+
+ /* The suffix ip means idempotent; list_unlink_ip can be called
+ * two or more times on the same node.
+ */
+
+ list->next = list;
+ list->prev = list;
+}
+
+
+/* Functions in the helper file. */
+extern void __timer_mutex_cancel_handler (void *arg);
+extern void __timer_init_once (void);
+extern struct timer_node *__timer_alloc (void);
+extern int __timer_thread_start (struct thread_node *thread);
+extern struct thread_node *__timer_thread_find_matching (const pthread_attr_t *desired_attr, clockid_t);
+extern struct thread_node *__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t);
+extern void __timer_thread_dealloc (struct thread_node *thread);
+extern int __timer_thread_queue_timer (struct thread_node *thread,
+ struct timer_node *insert);
+extern void __timer_thread_wakeup (struct thread_node *thread);
diff --git a/nptl/sysdeps/pthread/pt-initfini.c b/nptl/sysdeps/pthread/pt-initfini.c
new file mode 100644
index 0000000000..55d9f31562
--- /dev/null
+++ b/nptl/sysdeps/pthread/pt-initfini.c
@@ -0,0 +1,124 @@
+/* Special .init and .fini section support. Linuxthread version.
+ Copyright (C) 1995, 1996, 1997, 2000, 2001 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Library General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The Library General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ 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 Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This file is compiled into assembly code which is then munged by a sed
+ script into two files: crti.s and crtn.s.
+
+ * crti.s puts a function prologue at the beginning of the
+ .init and .fini sections and defines global symbols for
+ those addresses, so they can be called as functions.
+
+ * crtn.s puts the corresponding function epilogues
+ in the .init and .fini sections. */
+
+#include <stdlib.h>
+
+/* We use embedded asm for .section unconditionally, as this makes it
+ easier to insert the necessary directives into crtn.S. */
+#define SECTION(x) asm (".section " x )
+
+/* Embed an #include to pull in the alignment and .end directives. */
+asm ("\n#include \"defs.h\"");
+
+/* The initial common code ends here. */
+asm ("\n/*@HEADER_ENDS*/");
+
+/* To determine whether we need .end and .align: */
+asm ("\n/*@TESTS_BEGIN*/");
+extern void dummy (void (*foo) (void));
+void
+dummy (void (*foo) (void))
+{
+ if (foo)
+ (*foo) ();
+}
+asm ("\n/*@TESTS_END*/");
+
+/* The beginning of _init: */
+asm ("\n/*@_init_PROLOG_BEGINS*/");
+
+static void
+call_initialize_minimal (void)
+{
+ extern void __pthread_initialize_minimal (void);
+
+ __pthread_initialize_minimal ();
+}
+
+SECTION (".init");
+extern void _init (void);
+void
+_init (void)
+{
+ /* The very first thing we must do is to set up the registers. */
+ call_initialize_minimal ();
+
+ asm ("ALIGN");
+ asm("END_INIT");
+ /* Now the epilog. */
+ asm ("\n/*@_init_PROLOG_ENDS*/");
+ asm ("\n/*@_init_EPILOG_BEGINS*/");
+ SECTION(".init");
+}
+asm ("END_INIT");
+
+/* End of the _init epilog, beginning of the _fini prolog. */
+asm ("\n/*@_init_EPILOG_ENDS*/");
+asm ("\n/*@_fini_PROLOG_BEGINS*/");
+
+SECTION (".fini");
+extern void _fini (void);
+void
+_fini (void)
+{
+
+ /* End of the _fini prolog. */
+ asm ("ALIGN");
+ asm ("END_FINI");
+ asm ("\n/*@_fini_PROLOG_ENDS*/");
+
+ {
+ /* Let GCC know that _fini is not a leaf function by having a dummy
+ function call here. We arrange for this call to be omitted from
+ either crt file. */
+ extern void i_am_not_a_leaf (void);
+ i_am_not_a_leaf ();
+ }
+
+ /* Beginning of the _fini epilog. */
+ asm ("\n/*@_fini_EPILOG_BEGINS*/");
+ SECTION (".fini");
+}
+asm ("END_FINI");
+
+/* End of the _fini epilog. Any further generated assembly (e.g. .ident)
+ is shared between both crt files. */
+asm ("\n/*@_fini_EPILOG_ENDS*/");
+asm ("\n/*@TRAILER_BEGINS*/");
+
+/* End of file. */
diff --git a/nptl/sysdeps/pthread/pthread.h b/nptl/sysdeps/pthread/pthread.h
new file mode 100644
index 0000000000..d6b0966d40
--- /dev/null
+++ b/nptl/sysdeps/pthread/pthread.h
@@ -0,0 +1,743 @@
+/* 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. */
+
+#ifndef _PTHREAD_H
+#define _PTHREAD_H 1
+
+#include <features.h>
+#include <sched.h>
+#include <time.h>
+
+#define __need_sigset_t
+#include <signal.h>
+#include <bits/pthreadtypes.h>
+
+
+/* Detach state. */
+enum
+{
+ PTHREAD_CREATE_JOINABLE,
+#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE
+ PTHREAD_CREATE_DETACHED
+#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED
+};
+
+
+/* Mutex handling. */
+
+#define PTHREAD_MUTEX_INITIALIZER \
+ { }
+
+#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \
+ { .__data = { .__kind = PTHREAD_MUTEX_RECURSIVE_NP } }
+
+#define PTHREAD_RWLOCK_INITIALIZER \
+ { }
+
+#define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \
+ { .__data = { .__flags = PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } }
+
+enum
+{
+ PTHREAD_MUTEX_TIMED_NP,
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_ADAPTIVE_NP
+#ifdef __USE_UNIX98
+ ,
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+#endif
+#ifdef __USE_GNU
+ /* For compatibility. */
+ , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
+#endif
+};
+
+
+/* Read-write lock types. */
+#ifdef __USE_UNIX98
+enum
+{
+ PTHREAD_RWLOCK_PREFER_READER_NP,
+ PTHREAD_RWLOCK_PREFER_WRITER_NP,
+ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,
+ PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_READER_NP
+};
+#endif /* Unix98 */
+
+
+/* Scheduler inheritance. */
+enum
+{
+ PTHREAD_INHERIT_SCHED,
+#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED
+ PTHREAD_EXPLICIT_SCHED
+#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED
+};
+
+
+/* Scope handling. */
+enum
+{
+ PTHREAD_SCOPE_SYSTEM,
+#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM
+ PTHREAD_SCOPE_PROCESS
+#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS
+};
+
+
+/* Process shared or private flag. */
+enum
+{
+ PTHREAD_PROCESS_PRIVATE,
+#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE
+ PTHREAD_PROCESS_SHARED
+#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED
+};
+
+
+
+/* Conditional variable handling. */
+#define PTHREAD_COND_INITIALIZER { }
+
+
+/* Cleanup buffers */
+struct _pthread_cleanup_buffer
+{
+ void (*__routine) (void *); /* Function to call. */
+ void *__arg; /* Its argument. */
+ int __canceltype; /* Saved cancellation type. */
+ struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */
+};
+
+/* Cancellation */
+enum
+{
+ PTHREAD_CANCEL_ENABLE,
+#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE
+ PTHREAD_CANCEL_DISABLE
+#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE
+};
+enum
+{
+ PTHREAD_CANCEL_DEFERRED,
+#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED
+ PTHREAD_CANCEL_ASYNCHRONOUS
+#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS
+};
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/* Single execution handling. */
+#define PTHREAD_ONCE_INIT 0
+
+
+#ifdef __USE_XOPEN2K
+/* Value returned by 'pthread_barrier_wait' for one of the threads after
+ the required number of threads have called this function.
+ -1 is distinct from 0 and all errno constants */
+# define PTHREAD_BARRIER_SERIAL_THREAD -1
+#endif
+
+
+__BEGIN_DECLS
+
+/* Create a new thread, starting with execution of START-ROUTINE
+ getting passed ARG. Creation attributed come from ATTR. The new
+ handle is stored in *NEWTHREAD. */
+extern int pthread_create (pthread_t *__restrict __newthread,
+ __const pthread_attr_t *__restrict __attr,
+ void *(*__start_routine) (void *),
+ void *__restrict __arg) __THROW;
+
+/* Terminate calling thread. */
+extern void pthread_exit (void *__retval)
+ __THROW __attribute__ ((__noreturn__));
+
+/* Make calling thread wait for termination of the thread TH. The
+ exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN
+ is not NULL. */
+extern int pthread_join (pthread_t __th, void **__thread_return) __THROW;
+
+#ifdef __USE_GNU
+/* Check whether thread TH has terminated. If yes return the status of
+ the thread in *THREAD_RETURN, if THREAD_RETURN is not NULL. */
+extern int pthread_tryjoin_np (pthread_t __th, void **__thread_return) __THROW;
+
+/* Make calling thread wait for termination of the thread TH, but only
+ until TIMEOUT. The exit status of the thread is stored in
+ *THREAD_RETURN, if THREAD_RETURN is not NULL. */
+extern int pthread_timedjoin_np (pthread_t __th, void **__thread_return,
+ __const struct timespec *__abstime) __THROW;
+#endif
+
+/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN.
+ The resources of TH will therefore be freed immediately when it
+ terminates, instead of waiting for another thread to perform PTHREAD_JOIN
+ on it. */
+extern int pthread_detach (pthread_t __th) __THROW;
+
+
+/* Obtain the identifier of the current thread. */
+extern pthread_t pthread_self (void) __THROW __attribute__ ((__const__));
+
+/* Compare two thread identifiers. */
+extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW;
+
+
+/* Thread attribute handling. */
+
+/* Initialize thread attribute *ATTR with default attributes
+ (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER,
+ no user-provided stack). */
+extern int pthread_attr_init (pthread_attr_t *__attr) __THROW;
+
+/* Destroy thread attribute *ATTR. */
+extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW;
+
+/* Get detach state attribute. */
+extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr,
+ int *__detachstate) __THROW;
+
+/* Set detach state attribute. */
+extern int pthread_attr_setdetachstate (pthread_attr_t *__attr,
+ int __detachstate) __THROW;
+
+
+/* Get the size of the guard area created for stack overflow protection. */
+extern int pthread_attr_getguardsize (__const pthread_attr_t *__attr,
+ size_t *__guardsize) __THROW;
+
+/* Set the size of the guard area created for stack overflow protection. */
+extern int pthread_attr_setguardsize (pthread_attr_t *__attr,
+ size_t __guardsize) __THROW;
+
+
+/* Return in *PARAM the scheduling parameters of *ATTR. */
+extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict
+ __attr,
+ struct sched_param *__restrict __param)
+ __THROW;
+
+/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */
+extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr,
+ __const struct sched_param *__restrict
+ __param) __THROW;
+
+/* Return in *POLICY the scheduling policy of *ATTR. */
+extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict
+ __attr, int *__restrict __policy)
+ __THROW;
+
+/* Set scheduling policy in *ATTR according to POLICY. */
+extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy)
+ __THROW;
+
+/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */
+extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict
+ __attr, int *__restrict __inherit)
+ __THROW;
+
+/* Set scheduling inheritance mode in *ATTR according to INHERIT. */
+extern int pthread_attr_setinheritsched (pthread_attr_t *__attr,
+ int __inherit) __THROW;
+
+
+/* Return in *SCOPE the scheduling contention scope of *ATTR. */
+extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr,
+ int *__restrict __scope) __THROW;
+
+/* Set scheduling contention scope in *ATTR according to SCOPE. */
+extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope)
+ __THROW;
+
+/* Return the previously set address for the stack. */
+extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict
+ __attr, void **__restrict __stackaddr)
+ __THROW;
+
+/* Set the starting address of the stack of the thread to be created.
+ Depending on whether the stack grows up or down the value must either
+ be higher or lower than all the address in the memory block. The
+ minimal size of the block must be PTHREAD_STACK_SIZE. */
+extern int pthread_attr_setstackaddr (pthread_attr_t *__attr,
+ void *__stackaddr) __THROW;
+
+/* Return the currently used minimal stack size. */
+extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict
+ __attr, size_t *__restrict __stacksize)
+ __THROW;
+
+/* Add information about the minimum stack size needed for the thread
+ to be started. This size must never be less than PTHREAD_STACK_SIZE
+ and must also not exceed the system limits. */
+extern int pthread_attr_setstacksize (pthread_attr_t *__attr,
+ size_t __stacksize) __THROW;
+
+#ifdef __USE_XOPEN2K
+/* Return the previously set address for the stack. */
+extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr,
+ void **__restrict __stackaddr,
+ size_t *__restrict __stacksize) __THROW;
+
+/* The following two interfaces are intended to replace the last two. They
+ require setting the address as well as the size since only setting the
+ address will make the implementation on some architectures impossible. */
+extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+ size_t __stacksize) __THROW;
+#endif
+
+#ifdef __USE_GNU
+/* Get thread attributes corresponding to the already running thread TH. */
+extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW;
+#endif
+
+
+/* Functions for scheduling control. */
+
+/* Set the scheduling parameters for TARGET_THREAD according to POLICY
+ and *PARAM. */
+extern int pthread_setschedparam (pthread_t __target_thread, int __policy,
+ __const struct sched_param *__param)
+ __THROW;
+
+/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */
+extern int pthread_getschedparam (pthread_t __target_thread,
+ int *__restrict __policy,
+ struct sched_param *__restrict __param)
+ __THROW;
+
+
+#ifdef __USE_UNIX98
+/* Determine level of concurrency. */
+extern int pthread_getconcurrency (void) __THROW;
+
+/* Set new concurrency level to LEVEL. */
+extern int pthread_setconcurrency (int __level) __THROW;
+#endif
+
+#ifdef __USE_GNU
+/* Yield the processor to another thread or process.
+ This function is similar to the POSIX `sched_yield' function but
+ might be differently implemented in the case of a m-on-n thread
+ implementation. */
+extern int pthread_yield (void) __THROW;
+#endif
+
+
+/* Functions for handling initialization. */
+
+/* Guarantee that the initialization function INIT_ROUTINE will be called
+ only once, even if pthread_once is executed several times with the
+ same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or
+ extern variable initialized to PTHREAD_ONCE_INIT. */
+extern int pthread_once (pthread_once_t *__once_control,
+ void (*__init_routine) (void)) __THROW;
+
+
+/* Functions for handling cancellation. */
+
+/* Set cancelability state of current thread to STATE, returning old
+ state in *OLDSTATE if OLDSTATE is not NULL. */
+extern int pthread_setcancelstate (int __state, int *__oldstate) __THROW;
+
+/* Set cancellation state of current thread to TYPE, returning the old
+ type in *OLDTYPE if OLDTYPE is not NULL. */
+extern int pthread_setcanceltype (int __type, int *__oldtype) __THROW;
+
+/* Cancel THREAD immediately or at the next possibility. */
+extern int pthread_cancel (pthread_t __th) __THROW;
+
+/* Test for pending cancellation for the current thread and terminate
+ the thread as per pthread_exit(PTHREAD_CANCELED) if it has been
+ cancelled. */
+extern void pthread_testcancel (void) __THROW;
+
+
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+ when the thread is cancelled or calls pthread_exit. ROUTINE will also
+ be called with arguments ARG when the matching pthread_cleanup_pop
+ is executed with non-zero EXECUTE argument.
+
+ pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+ be used in matching pairs at the same nesting level of braces. */
+#define pthread_cleanup_push(routine,arg) \
+ { struct _pthread_cleanup_buffer _buffer; \
+ _pthread_cleanup_push (&_buffer, (routine), (arg));
+
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *), void *__arg)
+ __THROW;
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+ If EXECUTE is non-zero, the handler function is called. */
+#define pthread_cleanup_pop(execute) \
+ _pthread_cleanup_pop (&_buffer, (execute)); }
+
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
+ int __execute) __THROW;
+
+#ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+ saves the current cancellation type and sets it to deferred
+ cancellation. */
+# define pthread_cleanup_push_defer_np(routine,arg) \
+ { struct _pthread_cleanup_buffer _buffer; \
+ _pthread_cleanup_push_defer (&_buffer, (routine), (arg));
+
+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *),
+ void *__arg) __THROW;
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+ restores the cancellation type that was in effect when the matching
+ pthread_cleanup_push_defer was called. */
+# define pthread_cleanup_pop_restore_np(execute) \
+ _pthread_cleanup_pop_restore (&_buffer, (execute)); }
+
+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
+ int __execute) __THROW;
+#endif
+
+
+/* Mutex handling. */
+
+/* Initialize a mutex. */
+extern int pthread_mutex_init (pthread_mutex_t *__mutex,
+ __const pthread_mutexattr_t *__mutexattr)
+ __THROW;
+
+/* Destroy a mutex. */
+extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW;
+
+/* Try locking a mutex. */
+extern int pthread_mutex_trylock (pthread_mutex_t *_mutex) __THROW;
+
+/* Lock a mutex. */
+extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW;
+
+#ifdef __USE_XOPEN2K
+/* Wait until lock becomes available, or specified time passes. */
+extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
+ __const struct timespec *__restrict
+ __abstime) __THROW;
+#endif
+
+/* Unlock a mutex. */
+extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW;
+
+
+/* Functions for handling mutex attributes. */
+
+/* Initialize mutex attribute object ATTR with default attributes
+ (kind is PTHREAD_MUTEX_TIMED_NP). */
+extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW;
+
+/* Destroy mutex attribute object ATTR. */
+extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW;
+
+/* Get the process-shared flag of the mutex attribute ATTR. */
+extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t *
+ __restrict __attr,
+ int *__restrict __pshared) __THROW;
+
+/* Set the process-shared flag of the mutex attribute ATTR. */
+extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr,
+ int __pshared) __THROW;
+
+#ifdef __USE_UNIX98
+/* Return in *KIND the mutex kind attribute in *ATTR. */
+extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict
+ __attr, int *__restrict __kind) __THROW;
+
+/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL,
+ PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or
+ PTHREAD_MUTEX_DEFAULT). */
+extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)
+ __THROW;
+#endif
+
+
+#ifdef __USE_UNIX98
+/* Functions for handling read-write locks. */
+
+/* Initialize read-write lock RWLOCK using attributes ATTR, or use
+ the default values if later is NULL. */
+extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
+ __const pthread_rwlockattr_t *__restrict
+ __attr) __THROW;
+
+/* Destroy read-write lock RWLOCK. */
+extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW;
+
+/* Acquire read lock for RWLOCK. */
+extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW;
+
+/* Try to acquire read lock for RWLOCK. */
+extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW;
+
+# ifdef __USE_XOPEN2K
+/* Try to acquire read lock for RWLOCK or return after specfied time. */
+extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
+ __const struct timespec *__restrict
+ __abstime) __THROW;
+# endif
+
+/* Acquire write lock for RWLOCK. */
+extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW;
+
+/* Try to acquire write lock for RWLOCK. */
+extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW;
+
+# ifdef __USE_XOPEN2K
+/* Try to acquire write lock for RWLOCK or return after specfied time. */
+extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
+ __const struct timespec *__restrict
+ __abstime) __THROW;
+# endif
+
+/* Unlock RWLOCK. */
+extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW;
+
+
+/* Functions for handling read-write lock attributes. */
+
+/* Initialize attribute object ATTR with default values. */
+extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW;
+
+/* Destroy attribute object ATTR. */
+extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW;
+
+/* Return current setting of process-shared attribute of ATTR in PSHARED. */
+extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t *
+ __restrict __attr,
+ int *__restrict __pshared) __THROW;
+
+/* Set process-shared attribute of ATTR to PSHARED. */
+extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr,
+ int __pshared) __THROW;
+
+/* Return current setting of reader/writer preference. */
+extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t *
+ __restrict __attr,
+ int *__restrict __pref) __THROW;
+
+/* Set reader/write preference. */
+extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr,
+ int __pref) __THROW;
+#endif
+
+
+/* Functions for handling conditional variables. */
+
+/* Initialize condition variable COND using attributes ATTR, or use
+ the default values if later is NULL. */
+extern int pthread_cond_init (pthread_cond_t *__restrict __cond,
+ __const pthread_condattr_t *__restrict
+ __cond_attr) __THROW;
+
+/* Destroy condition variable COND. */
+extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW;
+
+/* Wake up one thread waiting for condition variable COND. */
+extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW;
+
+/* Wake up all threads waiting for condition variables COND. */
+extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW;
+
+/* Wait for condition variable COND to be signaled or broadcast.
+ MUTEX is assumed to be locked before. */
+extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
+ pthread_mutex_t *__restrict __mutex) __THROW;
+
+/* Wait for condition variable COND to be signaled or broadcast until
+ ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an
+ absolute time specification; zero is the beginning of the epoch
+ (00:00:00 GMT, January 1, 1970). */
+extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
+ pthread_mutex_t *__restrict __mutex,
+ __const struct timespec *__restrict
+ __abstime) __THROW;
+
+/* Functions for handling condition variable attributes. */
+
+/* Initialize condition variable attribute ATTR. */
+extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW;
+
+/* Destroy condition variable attribute ATTR. */
+extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW;
+
+/* Get the process-shared flag of the condition variable attribute ATTR. */
+extern int pthread_condattr_getpshared (__const pthread_condattr_t *
+ __restrict __attr,
+ int *__restrict __pshared) __THROW;
+
+/* Set the process-shared flag of the condition variable attribute ATTR. */
+extern int pthread_condattr_setpshared (pthread_condattr_t *__attr,
+ int __pshared) __THROW;
+
+
+
+#ifdef __USE_XOPEN2K
+/* Functions to handle spinlocks. */
+
+/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can
+ be shared between different processes. */
+extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared)
+ __THROW;
+
+/* Destroy the spinlock LOCK. */
+extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW;
+
+/* Wait until spinlock LOCK is retrieved. */
+extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW;
+
+/* Try to lock spinlock LOCK. */
+extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW;
+
+/* Release spinlock LOCK. */
+extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW;
+
+
+/* Functions to handle barriers. */
+
+/* Initialize BARRIER with the attributes in ATTR. The barrier is
+ opened when COUNT waiters arrived. */
+extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier,
+ __const pthread_barrierattr_t *__restrict
+ __attr, unsigned int __count) __THROW;
+
+/* Destroy a previously dynamically initialized barrier BARRIER. */
+extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW;
+
+/* Wait on barrier BARRIER. */
+extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW;
+
+
+/* Initialize barrier attribute ATTR. */
+extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW;
+
+/* Destroy previously dynamically initialized barrier attribute ATTR. */
+extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW;
+
+/* Get the process-shared flag of the barrier attribute ATTR. */
+extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t *
+ __restrict __attr,
+ int *__restrict __pshared) __THROW;
+
+/* Set the process-shared flag of the barrier attribute ATTR. */
+extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr,
+ int __pshared) __THROW;
+#endif
+
+
+/* Functions for handling thread-specific data. */
+
+/* Create a key value identifying a location in the thread-specific
+ data area. Each thread maintains a distinct thread-specific data
+ area. DESTR_FUNCTION, if non-NULL, is called with the value
+ associated to that key when the key is destroyed.
+ DESTR_FUNCTION is not called if the value associated is NULL when
+ the key is destroyed. */
+extern int pthread_key_create (pthread_key_t *__key,
+ void (*__destr_function) (void *)) __THROW;
+
+/* Destroy KEY. */
+extern int pthread_key_delete (pthread_key_t __key) __THROW;
+
+/* Return current value of the thread-specific data slot identified by KEY. */
+extern void *pthread_getspecific (pthread_key_t __key) __THROW;
+
+/* Store POINTER in the thread-specific data slot identified by KEY. */
+extern int pthread_setspecific (pthread_key_t __key,
+ __const void *__pointer) __THROW;
+
+
+/* Install a cleanup handler: ROUTINE will be called with arguments ARG
+ when the thread is cancelled or calls pthread_exit. ROUTINE will also
+ be called with arguments ARG when the matching pthread_cleanup_pop
+ is executed with non-zero EXECUTE argument.
+ pthread_cleanup_push and pthread_cleanup_pop are macros and must always
+ be used in matching pairs at the same nesting level of braces. */
+#define pthread_cleanup_push(routine,arg) \
+ { struct _pthread_cleanup_buffer _buffer; \
+ _pthread_cleanup_push (&_buffer, (routine), (arg));
+
+extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *),
+ void *__arg) __THROW;
+
+/* Remove a cleanup handler installed by the matching pthread_cleanup_push.
+ If EXECUTE is non-zero, the handler function is called. */
+#define pthread_cleanup_pop(execute) \
+ _pthread_cleanup_pop (&_buffer, (execute)); }
+
+extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer,
+ int __execute) __THROW;
+
+
+#ifdef __USE_GNU
+/* Install a cleanup handler as pthread_cleanup_push does, but also
+ saves the current cancellation type and set it to deferred cancellation. */
+# define pthread_cleanup_push_defer_np(routine,arg) \
+ { struct _pthread_cleanup_buffer _buffer; \
+ _pthread_cleanup_push_defer (&_buffer, (routine), (arg));
+
+extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer,
+ void (*__routine) (void *),
+ void *__arg) __THROW;
+
+/* Remove a cleanup handler as pthread_cleanup_pop does, but also
+ restores the cancellation type that was in effect when the matching
+ pthread_cleanup_push_defer was called. */
+# define pthread_cleanup_pop_restore_np(execute) \
+ _pthread_cleanup_pop_restore (&_buffer, (execute)); }
+
+extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer,
+ int __execute) __THROW;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* Get ID of CPU-time clock for thread THREAD_ID. */
+extern int pthread_getcpuclockid (pthread_t __thread_id,
+ clockid_t *__clock_id) __THROW;
+#endif
+
+
+/* Install handlers to be called when a new process is created with FORK.
+ The PREPARE handler is called in the parent process just before performing
+ FORK. The PARENT handler is called in the parent process just after FORK.
+ The CHILD handler is called in the child process. Each of the three
+ handlers can be NULL, meaning that no handler needs to be called at that
+ point.
+ PTHREAD_ATFORK can be called several times, in which case the PREPARE
+ handlers are called in LIFO order (last added with PTHREAD_ATFORK,
+ first called before FORK), and the PARENT and CHILD handlers are called
+ in FIFO (first added, first called). */
+
+extern int pthread_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void)) __THROW;
+
+__END_DECLS
+
+#endif /* pthread.h */
diff --git a/nptl/sysdeps/pthread/pthread_getcpuclockid.c b/nptl/sysdeps/pthread/pthread_getcpuclockid.c
new file mode 100644
index 0000000000..62761f9d7a
--- /dev/null
+++ b/nptl/sysdeps/pthread/pthread_getcpuclockid.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2000, 2001, 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <tls.h>
+
+
+int
+pthread_getcpuclockid (thread_id, clock_id)
+ pthread_t thread_id;
+ clockid_t *clock_id;
+{
+ /* We don't allow any process ID but our own. */
+ if ((struct pthread *) thread_id != THREAD_SELF)
+ return EPERM;
+
+#ifdef CLOCK_THREAD_CPUTIME_ID
+ /* Store the number. */
+ *clock_id = CLOCK_THREAD_CPUTIME_ID;
+
+ return 0;
+#else
+ /* We don't have a timer for that. */
+ return ENOENT;
+#endif
+}
diff --git a/nptl/sysdeps/pthread/pthread_once.c b/nptl/sysdeps/pthread/pthread_once.c
new file mode 100644
index 0000000000..9b2cef8645
--- /dev/null
+++ b/nptl/sysdeps/pthread/pthread_once.c
@@ -0,0 +1,54 @@
+/* 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. */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+
+static lll_lock_t once_lock = LLL_LOCK_INITIALIZER;
+
+
+int
+__pthread_once (once_control, init_routine)
+ pthread_once_t *once_control;
+ void (*init_routine) (void);
+{
+ /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a
+ global lock variable or one which is part of the pthread_once_t
+ object. */
+ if (*once_control == PTHREAD_ONCE_INIT)
+ {
+ lll_lock (once_lock);
+
+ /* XXX This implementation is not complete. It doesn't take
+ cancelation and fork into account. */
+ if (*once_control == PTHREAD_ONCE_INIT)
+ {
+ init_routine ();
+
+ *once_control = !PTHREAD_ONCE_INIT;
+ }
+
+ lll_unlock (once_lock);
+ }
+
+ return 0;
+}
+strong_alias (__pthread_once, pthread_once)
diff --git a/nptl/sysdeps/pthread/pthread_sigmask.c b/nptl/sysdeps/pthread/pthread_sigmask.c
new file mode 100644
index 0000000000..8ec7cf81ee
--- /dev/null
+++ b/nptl/sysdeps/pthread/pthread_sigmask.c
@@ -0,0 +1,44 @@
+/* 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. */
+
+#include <signal.h>
+#include <pthreadP.h>
+
+
+int
+pthread_sigmask (how, newmask, oldmask)
+ int how;
+ const sigset_t *newmask;
+ sigset_t *oldmask;
+{
+ sigset_t local_newmask;
+
+ /* The only thing we have to make sure here is that SIGCANCEL is not
+ blocked. */
+ if (newmask != NULL
+ && (how == SIG_SETMASK || how == SIG_BLOCK)
+ && sigismember (newmask, SIGCANCEL))
+ {
+ local_newmask = *newmask;
+ sigdelset (&local_newmask, SIGCANCEL);
+ newmask = &local_newmask;
+ }
+
+ return sigprocmask (how, newmask, oldmask);
+}
diff --git a/nptl/sysdeps/pthread/sigaction.c b/nptl/sysdeps/pthread/sigaction.c
new file mode 100644
index 0000000000..c3f6f435dd
--- /dev/null
+++ b/nptl/sysdeps/pthread/sigaction.c
@@ -0,0 +1,24 @@
+/* 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. */
+
+/* We use the libc implementation but we tell it to not allow
+ SIGCANCEL to be handled. */
+#define SIGCANCEL __SIGRTMIN
+
+#include_next <sigaction.c>
diff --git a/nptl/sysdeps/pthread/timer_create.c b/nptl/sysdeps/pthread/timer_create.c
new file mode 100644
index 0000000000..b34f70e8c1
--- /dev/null
+++ b/nptl/sysdeps/pthread/timer_create.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "posix-timer.h"
+
+
+/* Create new per-process timer using CLOCK. */
+int
+timer_create (clock_id, evp, timerid)
+ clockid_t clock_id;
+ struct sigevent *evp;
+ timer_t *timerid;
+{
+ int retval = -1;
+ struct timer_node *newtimer = NULL;
+ struct thread_node *thread = NULL;
+
+ if (clock_id != CLOCK_REALTIME
+#ifdef _POSIX_CPUTIME
+ && clock_id != CLOCK_PROCESS_CPUTIME_ID
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+ && clock_id != CLOCK_THREAD_CPUTIME_ID
+#endif
+ )
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ pthread_once (&__timer_init_once_control, __timer_init_once);
+
+ if (__timer_init_failed)
+ {
+ __set_errno (ENOMEM);
+ return -1;
+ }
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ newtimer = __timer_alloc ();
+ if (__builtin_expect (newtimer == NULL, 0))
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+
+ if (evp != NULL)
+ newtimer->event = *evp;
+ else
+ {
+ newtimer->event.sigev_notify = SIGEV_SIGNAL;
+ newtimer->event.sigev_signo = SIGALRM;
+ newtimer->event.sigev_value.sival_int = timer_ptr2id (newtimer);
+ newtimer->event.sigev_notify_function = 0;
+ }
+
+ newtimer->event.sigev_notify_attributes = &newtimer->attr;
+ newtimer->creator_pid = getpid ();
+
+ switch (__builtin_expect (newtimer->event.sigev_notify, SIGEV_SIGNAL))
+ {
+ case SIGEV_NONE:
+ /* This is a strange choice! */
+ break;
+
+ case SIGEV_SIGNAL:
+ /* We have a global thread for delivering timed signals.
+ If it is not running, try to start it up. */
+ switch (clock_id)
+ {
+ case CLOCK_REALTIME:
+ default:
+ thread = &__timer_signal_thread_rclk;
+ break;
+#ifdef _POSIX_CPUTIME
+ case CLOCK_PROCESS_CPUTIME_ID:
+ thread = &__timer_signal_thread_pclk;
+ break;
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+ case CLOCK_THREAD_CPUTIME_ID:
+ thread = &__timer_signal_thread_tclk;
+ break;
+#endif
+ }
+
+ if (! thread->exists)
+ {
+ if (__builtin_expect (__timer_thread_start (thread),
+ 1) < 0)
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+ }
+ break;
+
+ case SIGEV_THREAD:
+ /* Copy over thread attributes or set up default ones. */
+ if (evp->sigev_notify_attributes)
+ newtimer->attr = *(pthread_attr_t *) evp->sigev_notify_attributes;
+ else
+ pthread_attr_init (&newtimer->attr);
+
+ /* Ensure thread attributes call for deatched thread. */
+ pthread_attr_setdetachstate (&newtimer->attr, PTHREAD_CREATE_DETACHED);
+
+ /* Try to find existing thread having the right attributes. */
+ thread = __timer_thread_find_matching (&newtimer->attr, clock_id);
+
+ /* If no existing thread has these attributes, try to allocate one. */
+ if (thread == NULL)
+ thread = __timer_thread_alloc (&newtimer->attr, clock_id);
+
+ /* Out of luck; no threads are available. */
+ if (__builtin_expect (thread == NULL, 0))
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+
+ /* If the thread is not running already, try to start it. */
+ if (! thread->exists
+ && __builtin_expect (! __timer_thread_start (thread), 0))
+ {
+ __set_errno (EAGAIN);
+ goto unlock_bail;
+ }
+ break;
+
+ default:
+ __set_errno (EINVAL);
+ goto unlock_bail;
+ }
+
+ newtimer->clock = clock_id;
+ newtimer->abstime = 0;
+ newtimer->armed = 0;
+ newtimer->thread = thread;
+
+ *timerid = timer_ptr2id (newtimer);
+ retval = 0;
+
+ if (__builtin_expect (retval, 0) == -1)
+ {
+ unlock_bail:
+ if (thread != NULL)
+ __timer_thread_dealloc (thread);
+ if (newtimer != NULL)
+ __timer_dealloc (newtimer);
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_delete.c b/nptl/sysdeps/pthread/timer_delete.c
new file mode 100644
index 0000000000..48ba1f2726
--- /dev/null
+++ b/nptl/sysdeps/pthread/timer_delete.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Delete timer TIMERID. */
+int
+timer_delete (timerid)
+ timer_t timerid;
+{
+ struct timer_node *timer;
+ int retval = -1;
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ timer = timer_id2ptr (timerid);
+ if (! timer_valid (timer))
+ /* Invalid timer ID or the timer is not in use. */
+ __set_errno (EINVAL);
+ else
+ {
+ if (timer->armed && timer->thread != NULL)
+ {
+ struct thread_node *thread = timer->thread;
+ assert (thread != NULL);
+
+ /* If thread is cancelled while waiting for handler to terminate,
+ the mutex is unlocked and timer_delete is aborted. */
+ pthread_cleanup_push (__timer_mutex_cancel_handler, &__timer_mutex);
+
+ /* If timer is currently being serviced, wait for it to finish. */
+ while (thread->current_timer == timer)
+ pthread_cond_wait (&thread->cond, &__timer_mutex);
+
+ pthread_cleanup_pop (0);
+ }
+
+ /* Remove timer from whatever queue it may be on and deallocate it. */
+ timer->inuse = TIMER_DELETED;
+ list_unlink_ip (&timer->links);
+ timer_delref (timer);
+ retval = 0;
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_getoverr.c b/nptl/sysdeps/pthread/timer_getoverr.c
new file mode 100644
index 0000000000..f3e22215b2
--- /dev/null
+++ b/nptl/sysdeps/pthread/timer_getoverr.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get expiration overrun for timer TIMERID. */
+int
+timer_getoverrun (timerid)
+ timer_t timerid;
+{
+ struct timer_node *timer;
+ int retval = -1;
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ if (! timer_valid (timer = timer_id2ptr (timerid)))
+ __set_errno (EINVAL);
+ else
+ retval = timer->overrun_count;
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_gettime.c b/nptl/sysdeps/pthread/timer_gettime.c
new file mode 100644
index 0000000000..99a080311c
--- /dev/null
+++ b/nptl/sysdeps/pthread/timer_gettime.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Get current value of timer TIMERID and store it in VLAUE. */
+int
+timer_gettime (timerid, value)
+ timer_t timerid;
+ struct itimerspec *value;
+{
+ struct timer_node *timer;
+ struct timespec now, expiry;
+ int retval = -1, armed = 0, valid;
+ clock_t clock = 0;
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ timer = timer_id2ptr (timerid);
+ valid = timer_valid (timer);
+
+ if (valid) {
+ armed = timer->armed;
+ expiry = timer->expirytime;
+ clock = timer->clock;
+ value->it_interval = timer->value.it_interval;
+ }
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ if (valid)
+ {
+ if (armed)
+ {
+ clock_gettime (clock, &now);
+ timespec_sub (&value->it_value, &expiry, &now);
+ }
+ else
+ {
+ value->it_value.tv_sec = 0;
+ value->it_value.tv_nsec = 0;
+ }
+
+ retval = 0;
+ }
+ else
+ __set_errno (EINVAL);
+
+ return retval;
+}
diff --git a/nptl/sysdeps/pthread/timer_routines.c b/nptl/sysdeps/pthread/timer_routines.c
new file mode 100644
index 0000000000..ddd8afe988
--- /dev/null
+++ b/nptl/sysdeps/pthread/timer_routines.c
@@ -0,0 +1,592 @@
+/* Helper code for POSIX timer implementation on LinuxThreads.
+ Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include "posix-timer.h"
+#include <pthreadP.h>
+
+
+/* Number of threads used. */
+#define THREAD_MAXNODES 16
+
+/* Array containing the descriptors for the used threads. */
+static struct thread_node thread_array[THREAD_MAXNODES];
+
+/* Static array with the structures for all the timers. */
+struct timer_node __timer_array[TIMER_MAX];
+
+/* Global lock to protect operation on the lists. */
+pthread_mutex_t __timer_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Variable to protext initialization. */
+pthread_once_t __timer_init_once_control = PTHREAD_ONCE_INIT;
+
+/* Nonzero if initialization of timer implementation failed. */
+int __timer_init_failed;
+
+/* Node for the thread used to deliver signals. */
+struct thread_node __timer_signal_thread_rclk;
+#ifdef _POSIX_CPUTIME
+struct thread_node __timer_signal_thread_pclk;
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+struct thread_node __timer_signal_thread_tclk;
+#endif
+
+/* Lists to keep free and used timers and threads. */
+struct list_links timer_free_list;
+struct list_links thread_free_list;
+struct list_links thread_active_list;
+
+
+#ifdef __NR_rt_sigqueueinfo
+extern int __syscall_rt_sigqueueinfo (int, int, siginfo_t *);
+#endif
+
+
+/* List handling functions. */
+static inline void
+list_init (struct list_links *list)
+{
+ list->next = list->prev = list;
+}
+
+static inline void
+list_append (struct list_links *list, struct list_links *newp)
+{
+ newp->prev = list->prev;
+ newp->next = list;
+ list->prev->next = newp;
+ list->prev = newp;
+}
+
+static inline void
+list_insbefore (struct list_links *list, struct list_links *newp)
+{
+ list_append (list, newp);
+}
+
+/*
+ * Like list_unlink_ip, except that calling it on a node that
+ * is already unlinked is disastrous rather than a noop.
+ */
+
+static inline void
+list_unlink (struct list_links *list)
+{
+ struct list_links *lnext = list->next, *lprev = list->prev;
+
+ lnext->prev = lprev;
+ lprev->next = lnext;
+}
+
+static inline struct list_links *
+list_first (struct list_links *list)
+{
+ return list->next;
+}
+
+static inline struct list_links *
+list_null (struct list_links *list)
+{
+ return list;
+}
+
+static inline struct list_links *
+list_next (struct list_links *list)
+{
+ return list->next;
+}
+
+static inline int
+list_isempty (struct list_links *list)
+{
+ return list->next == list;
+}
+
+
+/* Functions build on top of the list functions. */
+static inline struct thread_node *
+thread_links2ptr (struct list_links *list)
+{
+ return (struct thread_node *) ((char *) list
+ - offsetof (struct thread_node, links));
+}
+
+static inline struct timer_node *
+timer_links2ptr (struct list_links *list)
+{
+ return (struct timer_node *) ((char *) list
+ - offsetof (struct timer_node, links));
+}
+
+
+/* Initialize a newly allocated thread structure. */
+static void
+thread_init (struct thread_node *thread, const pthread_attr_t *attr, clockid_t clock_id)
+{
+ if (attr != NULL)
+ thread->attr = *attr;
+ else
+ {
+ pthread_attr_init (&thread->attr);
+ pthread_attr_setdetachstate (&thread->attr, PTHREAD_CREATE_DETACHED);
+ }
+
+ thread->exists = 0;
+ list_init (&thread->timer_queue);
+ pthread_cond_init (&thread->cond, 0);
+ thread->current_timer = 0;
+ thread->captured = pthread_self ();
+ thread->clock_id = clock_id;
+}
+
+
+/* Initialize the global lists, and acquire global resources. Error
+ reporting is done by storing a non-zero value to the global variable
+ timer_init_failed. */
+static void
+init_module (void)
+{
+ int i;
+
+ list_init (&timer_free_list);
+ list_init (&thread_free_list);
+ list_init (&thread_active_list);
+
+ for (i = 0; i < TIMER_MAX; ++i)
+ {
+ list_append (&timer_free_list, &__timer_array[i].links);
+ __timer_array[i].inuse = TIMER_FREE;
+ }
+
+ for (i = 0; i < THREAD_MAXNODES; ++i)
+ list_append (&thread_free_list, &thread_array[i].links);
+
+ thread_init (&__timer_signal_thread_rclk, 0, CLOCK_REALTIME);
+#ifdef _POSIX_CPUTIME
+ thread_init (&__timer_signal_thread_pclk, 0, CLOCK_PROCESS_CPUTIME_ID);
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+ thread_init (&__timer_signal_thread_tclk, 0, CLOCK_THREAD_CPUTIME_ID);
+#endif
+}
+
+
+/* This is a handler executed in a child process after a fork()
+ occurs. It reinitializes the module, resetting all of the data
+ structures to their initial state. The mutex is initialized in
+ case it was locked in the parent process. */
+static void
+reinit_after_fork (void)
+{
+ init_module ();
+ pthread_mutex_init (&__timer_mutex, 0);
+}
+
+
+/* Called once form pthread_once in timer_init. This initializes the
+ module and ensures that reinit_after_fork will be executed in any
+ child process. */
+void
+__timer_init_once (void)
+{
+ init_module ();
+ pthread_atfork (0, 0, reinit_after_fork);
+}
+
+
+/* Deinitialize a thread that is about to be deallocated. */
+static void
+thread_deinit (struct thread_node *thread)
+{
+ assert (list_isempty (&thread->timer_queue));
+ pthread_cond_destroy (&thread->cond);
+}
+
+
+/* Allocate a thread structure from the global free list. Global
+ mutex lock must be held by caller. The thread is moved to
+ the active list. */
+struct thread_node *
+__timer_thread_alloc (const pthread_attr_t *desired_attr, clockid_t clock_id)
+{
+ struct list_links *node = list_first (&thread_free_list);
+
+ if (node != list_null (&thread_free_list))
+ {
+ struct thread_node *thread = thread_links2ptr (node);
+ list_unlink (node);
+ thread_init (thread, desired_attr, clock_id);
+ list_append (&thread_active_list, node);
+ return thread;
+ }
+
+ return 0;
+}
+
+
+/* Return a thread structure to the global free list. Global lock
+ must be held by caller. */
+void
+__timer_thread_dealloc (struct thread_node *thread)
+{
+ thread_deinit (thread);
+ list_unlink (&thread->links);
+ list_append (&thread_free_list, &thread->links);
+}
+
+
+/* Each of our threads which terminates executes this cleanup
+ handler. We never terminate threads ourselves; if a thread gets here
+ it means that the evil application has killed it. If the thread has
+ timers, these require servicing and so we must hire a replacement
+ thread right away. We must also unblock another thread that may
+ have been waiting for this thread to finish servicing a timer (see
+ timer_delete()). */
+
+static void
+thread_cleanup (void *val)
+{
+ if (val != NULL)
+ {
+ struct thread_node *thread = val;
+
+ /* How did the signal thread get killed? */
+ assert (thread != &__timer_signal_thread_rclk);
+#ifdef _POSIX_CPUTIME
+ assert (thread != &__timer_signal_thread_pclk);
+#endif
+#ifdef _POSIX_THREAD_CPUTIME
+ assert (thread != &__timer_signal_thread_tclk);
+#endif
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ thread->exists = 0;
+
+ /* We are no longer processing a timer event. */
+ thread->current_timer = 0;
+
+ if (list_isempty (&thread->timer_queue))
+ __timer_thread_dealloc (thread);
+ else
+ (void) __timer_thread_start (thread);
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ /* Unblock potentially blocked timer_delete(). */
+ pthread_cond_broadcast (&thread->cond);
+ }
+}
+
+
+/* Handle a timer which is supposed to go off now. */
+static void
+thread_expire_timer (struct thread_node *self, struct timer_node *timer)
+{
+ self->current_timer = timer; /* Lets timer_delete know timer is running. */
+
+ pthread_mutex_unlock (&__timer_mutex);
+
+ switch (__builtin_expect (timer->event.sigev_notify, SIGEV_SIGNAL))
+ {
+ case SIGEV_NONE:
+ assert (! "timer_create should never have created such a timer");
+ break;
+
+ case SIGEV_SIGNAL:
+#ifdef __NR_rt_sigqueueinfo
+ {
+ siginfo_t info;
+
+ /* First, clear the siginfo_t structure, so that we don't pass our
+ stack content to other tasks. */
+ memset (&info, 0, sizeof (siginfo_t));
+ /* We must pass the information about the data in a siginfo_t
+ value. */
+ info.si_signo = timer->event.sigev_signo;
+ info.si_code = SI_TIMER;
+ info.si_pid = timer->creator_pid;
+ info.si_uid = getuid ();
+ info.si_value = timer->event.sigev_value;
+
+ INLINE_SYSCALL (rt_sigqueueinfo, 3, info.si_pid, info.si_signo, &info);
+ }
+#else
+ if (pthread_kill (self->captured, timer->event.sigev_signo) != 0)
+ {
+ if (pthread_kill (self->id, timer->event.sigev_signo) != 0)
+ abort ();
+ }
+#endif
+ break;
+
+ case SIGEV_THREAD:
+ timer->event.sigev_notify_function (timer->event.sigev_value);
+ break;
+
+ default:
+ assert (! "unknown event");
+ break;
+ }
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ self->current_timer = 0;
+
+ pthread_cond_broadcast (&self->cond);
+}
+
+
+/* Thread function; executed by each timer thread. The job of this
+ function is to wait on the thread's timer queue and expire the
+ timers in chronological order as close to their scheduled time as
+ possible. */
+static void
+__attribute__ ((noreturn))
+thread_func (void *arg)
+{
+ struct thread_node *self = arg;
+
+ /* Register cleanup handler, in case rogue application terminates
+ this thread. (This cannot happen to __timer_signal_thread, which
+ doesn't invoke application callbacks). */
+
+ pthread_cleanup_push (thread_cleanup, self);
+
+ pthread_mutex_lock (&__timer_mutex);
+
+ while (1)
+ {
+ struct list_links *first;
+ struct timer_node *timer = NULL;
+
+ /* While the timer queue is not empty, inspect the first node. */
+ first = list_first (&self->timer_queue);
+ if (first != list_null (&self->timer_queue))
+ {
+ struct timespec now;
+
+ timer = timer_links2ptr (first);
+
+ /* This assumes that the elements of the list of one thread
+ are all for the same clock. */
+ clock_gettime (timer->clock, &now);
+
+ while (1)
+ {
+ /* If the timer is due or overdue, remove it from the queue.
+ If it's a periodic timer, re-compute its new time and
+ requeue it. Either way, perform the timer expiry. */
+ if (timespec_compare (&now, &timer->expirytime) < 0)
+ break;
+
+ list_unlink_ip (first);
+
+ if (__builtin_expect (timer->value.it_interval.tv_sec, 0) != 0
+ || timer->value.it_interval.tv_nsec != 0)
+ {
+ timer->overrun_count = 0;
+ timespec_add (&timer->expirytime, &timer->expirytime,
+ &timer->value.it_interval);
+ while (timespec_compare (&timer->expirytime, &now) < 0)
+ {
+ timespec_add (&timer->expirytime, &timer->expirytime,
+ &timer->value.it_interval);
+ if (timer->overrun_count < DELAYTIMER_MAX)
+ ++timer->overrun_count;
+ }
+ __timer_thread_queue_timer (self, timer);
+ }
+
+ thread_expire_timer (self, timer);
+
+ first = list_first (&self->timer_queue);
+ if (first == list_null (&self->timer_queue))
+ break;
+
+ timer = timer_links2ptr (first);
+ }
+ }
+
+ /* If the queue is not empty, wait until the expiry time of the
+ first node. Otherwise wait indefinitely. Insertions at the
+ head of the queue must wake up the thread by broadcasting
+ this condition variable. */
+ if (timer != NULL)
+ pthread_cond_timedwait (&self->cond, &__timer_mutex,
+ &timer->expirytime);
+ else
+ pthread_cond_wait (&self->cond, &__timer_mutex);
+ }
+ /* This macro will never be executed since the while loop loops
+ forever - but we have to add it for proper nesting. */
+ pthread_cleanup_pop (1);
+}
+
+
+/* Enqueue a timer in wakeup order in the thread's timer queue.
+ Returns 1 if the timer was inserted at the head of the queue,
+ causing the queue's next wakeup time to change. */
+
+int
+__timer_thread_queue_timer (struct thread_node *thread,
+ struct timer_node *insert)
+{
+ struct list_links *iter;
+ int athead = 1;
+
+ for (iter = list_first (&thread->timer_queue);
+ iter != list_null (&thread->timer_queue);
+ iter = list_next (iter))
+ {
+ struct timer_node *timer = timer_links2ptr (iter);
+
+ if (timespec_compare (&insert->expirytime, &timer->expirytime) < 0)
+ break;
+ athead = 0;
+ }
+
+ list_insbefore (iter, &insert->links);
+ return athead;
+}
+
+
+/* Start a thread and associate it with the given thread node. Global
+ lock must be held by caller. */
+int
+__timer_thread_start (struct thread_node *thread)
+{
+ int retval = 1;
+
+ assert (!thread->exists);
+ thread->exists = 1;
+
+ if (pthread_create (&thread->id, &thread->attr,
+ (void *(*) (void *)) thread_func, thread) != 0)
+ {
+ thread->exists = 0;
+ retval = -1;
+ }
+
+ return retval;
+}
+
+
+void
+__timer_thread_wakeup (struct thread_node *thread)
+{
+ pthread_cond_broadcast (&thread->cond);
+}
+
+
+/* Compare two pthread_attr_t thread attributes for exact equality.
+ Returns 1 if they are equal, otherwise zero if they are not equal or
+ contain illegal values. This version is LinuxThreads-specific for
+ performance reason. One could use the access functions to get the
+ values of all the fields of the attribute structure. */
+static int
+thread_attr_compare (const pthread_attr_t *left, const pthread_attr_t *right)
+{
+ struct pthread_attr *ileft = (struct pthread_attr *) left;
+ struct pthread_attr *iright = (struct pthread_attr *) right;
+
+ return (ileft->flags == iright->flags
+ && ileft->schedpolicy == iright->schedpolicy
+ && (ileft->schedparam.sched_priority
+ == iright->schedparam.sched_priority));
+}
+
+
+/* Search the list of active threads and find one which has matching
+ attributes. Global mutex lock must be held by caller. */
+struct thread_node *
+__timer_thread_find_matching (const pthread_attr_t *desired_attr,
+ clockid_t desired_clock_id)
+{
+ struct list_links *iter = list_first (&thread_active_list);
+
+ while (iter != list_null (&thread_active_list))
+ {
+ struct thread_node *candidate = thread_links2ptr (iter);
+
+ if (thread_attr_compare (desired_attr, &candidate->attr)
+ && desired_clock_id == candidate->clock_id)
+ {
+ list_unlink (iter);
+ return candidate;
+ }
+
+ iter = list_next (iter);
+ }
+
+ return NULL;
+}
+
+
+/* Grab a free timer structure from the global free list. The global
+ lock must be held by the caller. */
+struct timer_node *
+__timer_alloc (void)
+{
+ struct list_links *node = list_first (&timer_free_list);
+
+ if (node != list_null (&timer_free_list))
+ {
+ struct timer_node *timer = timer_links2ptr (node);
+ list_unlink_ip (node);
+ timer->inuse = TIMER_INUSE;
+ timer->refcount = 1;
+ return timer;
+ }
+
+ return NULL;
+}
+
+
+/* Return a timer structure to the global free list. The global lock
+ must be held by the caller. */
+void
+__timer_dealloc (struct timer_node *timer)
+{
+ assert (timer->refcount == 0);
+ timer->thread = NULL; /* Break association between timer and thread. */
+ timer->inuse = TIMER_FREE;
+ list_append (&timer_free_list, &timer->links);
+}
+
+
+/* Thread cancellation handler which unlocks a mutex. */
+void
+__timer_mutex_cancel_handler (void *arg)
+{
+ pthread_mutex_unlock (arg);
+}
diff --git a/nptl/sysdeps/pthread/timer_settime.c b/nptl/sysdeps/pthread/timer_settime.c
new file mode 100644
index 0000000000..592b5271ba
--- /dev/null
+++ b/nptl/sysdeps/pthread/timer_settime.c
@@ -0,0 +1,137 @@
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "posix-timer.h"
+
+
+/* Set timer TIMERID to VALUE, returning old value in OVLAUE. */
+int
+timer_settime (timerid, flags, value, ovalue)
+ timer_t timerid;
+ int flags;
+ const struct itimerspec *value;
+ struct itimerspec *ovalue;
+{
+ struct timer_node *timer;
+ struct thread_node *thread = NULL;
+ struct timespec now;
+ int have_now = 0, need_wakeup = 0;
+ int retval = -1;
+
+ timer = timer_id2ptr (timerid);
+ if (timer == NULL)
+ {
+ __set_errno (EINVAL);
+ goto bail;
+ }
+
+ if (value->it_interval.tv_nsec < 0
+ || value->it_interval.tv_nsec >= 1000000000
+ || value->it_value.tv_nsec < 0
+ || value->it_value.tv_nsec >= 1000000000)
+ {
+ __set_errno (EINVAL);
+ goto bail;
+ }
+
+ /* Will need to know current time since this is a relative timer;
+ might as well make the system call outside of the lock now! */
+
+ if ((flags & TIMER_ABSTIME) == 0)
+ {
+ clock_gettime (timer->clock, &now);
+ have_now = 1;
+ }
+
+ pthread_mutex_lock (&__timer_mutex);
+ timer_addref (timer);
+
+ /* One final check of timer validity; this one is possible only
+ until we have the mutex, because it accesses the inuse flag. */
+
+ if (! timer_valid(timer))
+ {
+ __set_errno (EINVAL);
+ goto unlock_bail;
+ }
+
+ if (ovalue != NULL)
+ {
+ ovalue->it_interval = timer->value.it_interval;
+
+ if (timer->armed)
+ {
+ if (! have_now)
+ {
+ pthread_mutex_unlock (&__timer_mutex);
+ clock_gettime (timer->clock, &now);
+ have_now = 1;
+ pthread_mutex_lock (&__timer_mutex);
+ timer_addref (timer);
+ }
+
+ timespec_sub (&ovalue->it_value, &timer->expirytime, &now);
+ }
+ else
+ {
+ ovalue->it_value.tv_sec = 0;
+ ovalue->it_value.tv_nsec = 0;
+ }
+ }
+
+ timer->value = *value;
+
+ list_unlink_ip (&timer->links);
+ timer->armed = 0;
+
+ thread = timer->thread;
+
+ /* A value of { 0, 0 } causes the timer to be stopped. */
+ if (value->it_value.tv_sec != 0
+ || __builtin_expect (value->it_value.tv_nsec != 0, 1))
+ {
+ if ((flags & TIMER_ABSTIME) != 0)
+ /* The user specified the expiration time. */
+ timer->expirytime = value->it_value;
+ else
+ timespec_add (&timer->expirytime, &now, &value->it_value);
+
+ /* Only need to wake up the thread if timer is inserted
+ at the head of the queue. */
+ if (thread != NULL)
+ need_wakeup = __timer_thread_queue_timer (thread, timer);
+ timer->armed = 1;
+ }
+
+ retval = 0;
+
+unlock_bail:
+ timer_delref (timer);
+ pthread_mutex_unlock (&__timer_mutex);
+
+bail:
+ if (thread != NULL && need_wakeup)
+ __timer_thread_wakeup (thread);
+
+ return retval;
+}
diff --git a/nptl/sysdeps/pthread/tst-timer.c b/nptl/sysdeps/pthread/tst-timer.c
new file mode 100644
index 0000000000..7417bcd5f0
--- /dev/null
+++ b/nptl/sysdeps/pthread/tst-timer.c
@@ -0,0 +1,114 @@
+/* Tests for POSIX timer implementation.
+ Copyright (C) 2000, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Kaz Kylheku <kaz@ashi.footprints.net>.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+
+static void
+notify_func (union sigval sigval)
+{
+ puts ("notify_func");
+}
+
+
+static void
+signal_func (int sig)
+{
+ static const char text[] = "signal_func\n";
+ signal (sig, signal_func);
+ write (STDOUT_FILENO, text, sizeof text - 1);
+}
+
+static void
+intr_sleep (int sec)
+{
+ struct timespec ts;
+
+ ts.tv_sec = sec;
+ ts.tv_nsec = 0;
+
+ while (nanosleep (&ts, &ts) == -1 && errno == EINTR)
+ ;
+}
+
+#define ZSIGALRM 14
+
+
+int
+main (void)
+{
+ struct timespec ts;
+ timer_t timer_sig, timer_thr1, timer_thr2;
+ int retval;
+ struct sigevent sigev1 =
+ {
+ .sigev_notify = SIGEV_SIGNAL,
+ .sigev_signo = ZSIGALRM
+ };
+ struct sigevent sigev2;
+ struct itimerspec itimer1 = { { 0, 200000000 }, { 0, 200000000 } };
+ struct itimerspec itimer2 = { { 0, 100000000 }, { 0, 500000000 } };
+ struct itimerspec itimer3 = { { 0, 150000000 }, { 0, 300000000 } };
+ struct itimerspec old;
+
+ retval = clock_gettime (CLOCK_REALTIME, &ts);
+
+ sigev2.sigev_notify = SIGEV_THREAD;
+ sigev2.sigev_notify_function = notify_func;
+ sigev2.sigev_notify_attributes = NULL;
+
+ setvbuf (stdout, 0, _IOLBF, 0);
+
+ printf ("clock_gettime returned %d, timespec = { %ld, %ld }\n",
+ retval, ts.tv_sec, ts.tv_nsec);
+
+ retval = clock_getres (CLOCK_REALTIME, &ts);
+
+ printf ("clock_getres returned %d, timespec = { %ld, %ld }\n",
+ retval, ts.tv_sec, ts.tv_nsec);
+
+ timer_create (CLOCK_REALTIME, &sigev1, &timer_sig);
+ timer_create (CLOCK_REALTIME, &sigev2, &timer_thr1);
+ timer_create (CLOCK_REALTIME, &sigev2, &timer_thr2);
+
+ timer_settime (timer_thr1, 0, &itimer2, &old);
+ timer_settime (timer_thr2, 0, &itimer3, &old);
+
+ signal (ZSIGALRM, signal_func);
+
+ timer_settime (timer_sig, 0, &itimer1, &old);
+
+ timer_delete (-1);
+
+ intr_sleep (3);
+
+ timer_delete (timer_sig);
+ timer_delete (timer_thr1);
+
+ intr_sleep (3);
+
+ timer_delete (timer_thr2);
+
+ return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/Implies b/nptl/sysdeps/unix/sysv/linux/Implies
new file mode 100644
index 0000000000..f1b3e8939c
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/Implies
@@ -0,0 +1 @@
+pthread
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile
new file mode 100644
index 0000000000..efe4ba4e9d
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/Makefile
@@ -0,0 +1,24 @@
+# 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. */
+
+ifeq ($(subdir),nptl)
+sysdep_routines += register-atfork unregister-atfork fork-gen lowlevellock
+
+libpthread-sysdep_routines += pt-fork
+endif
diff --git a/nptl/sysdeps/unix/sysv/linux/Versions b/nptl/sysdeps/unix/sysv/linux/Versions
new file mode 100644
index 0000000000..117598c95f
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/Versions
@@ -0,0 +1,12 @@
+libc {
+ GLIBC_PRIVATE {
+ __register_atfork; __register_pthread_fork_handler;
+ __libc_current_sigrtmin_private; __libc_current_sigrtmax_private;
+ __libc_allocate_rtsig_private;
+ }
+}
+libpthread {
+ GLIBC_2.0 {
+ fork; __fork;
+ }
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/allocrtsig.c b/nptl/sysdeps/unix/sysv/linux/allocrtsig.c
new file mode 100644
index 0000000000..5badaea9ec
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/allocrtsig.c
@@ -0,0 +1,54 @@
+/* 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. */
+
+#include <signal.h>
+
+
+static int current_rtmin = __SIGRTMIN + 1;
+static int current_rtmax = __SIGRTMAX;
+
+
+/* We reserve __SIGRTMIN for use as the cancelation signal. This
+ signal is used internally. */
+int
+__libc_current_sigrtmin (void)
+{
+ return current_rtmin;
+}
+strong_alias (__libc_current_sigrtmin, __libc_current_sigrtmin_private)
+
+
+int
+__libc_current_sigrtmax (void)
+{
+ return current_rtmax;
+}
+strong_alias (__libc_current_sigrtmax, __libc_current_sigrtmax_private)
+
+
+int
+__libc_allocate_rtsig (int high)
+{
+ if (current_rtmin == -1 || current_rtmin > current_rtmax)
+ /* We don't have anymore signal available. */
+ return -1;
+
+ return high ? current_rtmin++ : current_rtmax--;
+}
+strong_alias (__libc_allocate_rtsig, __libc_allocate_rtsig_private)
diff --git a/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h b/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h
new file mode 100644
index 0000000000..63de09a1b0
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/bits/local_lim.h
@@ -0,0 +1,80 @@
+/* Minimum guaranteed maximum values for system limits. Linux version.
+ Copyright (C) 1993,94,95,96,97,98,2000,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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* The kernel header pollutes the namespace with the NR_OPEN symbol
+ and defines LINK_MAX although filesystems have different maxima. A
+ similar thing is true for OPEN_MAX: the limit can be changed at
+ runtime and therefore the macro must not be defined. Remove this
+ after including the header if necessary. */
+#ifndef NR_OPEN
+# define __undef_NR_OPEN
+#endif
+#ifndef LINK_MAX
+# define __undef_LINK_MAX
+#endif
+#ifndef OPEN_MAX
+# define __undef_OPEN_MAX
+#endif
+
+/* The kernel sources contain a file with all the needed information. */
+#include <linux/limits.h>
+
+/* Have to remove NR_OPEN? */
+#ifdef __undef_NR_OPEN
+# undef NR_OPEN
+# undef __undef_NR_OPEN
+#endif
+/* Have to remove LINK_MAX? */
+#ifdef __undef_LINK_MAX
+# undef LINK_MAX
+# undef __undef_LINK_MAX
+#endif
+/* Have to remove OPEN_MAX? */
+#ifdef __undef_OPEN_MAX
+# undef OPEN_MAX
+# undef __undef_OPEN_MAX
+#endif
+
+/* The number of data keys per process. */
+#define _POSIX_THREAD_KEYS_MAX 128
+/* This is the value this implementation supports. */
+#define PTHREAD_KEYS_MAX 1024
+
+/* Controlling the iterations of destructors for thread-specific data. */
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
+/* Number of iterations this implementation does. */
+#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+/* The number of threads per process. */
+#define _POSIX_THREAD_THREADS_MAX 64
+/* This is the value this implementation supports. */
+#define PTHREAD_THREADS_MAX 1024
+
+/* Maximum amount by which a process can descrease its asynchronous I/O
+ priority level. */
+#define AIO_PRIO_DELTA_MAX 20
+
+/* Minimum size for a thread. We are free to choose a reasonable value. */
+#define PTHREAD_STACK_MIN 16384
+
+/* Maximum number of POSIX timers available. */
+#define TIMER_MAX 256
+
+/* Maximum number of timer expiration overruns. */
+#define DELAYTIMER_MAX 2147483647
diff --git a/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
new file mode 100644
index 0000000000..8274f516be
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
@@ -0,0 +1,144 @@
+/* Define POSIX options for Linux.
+ Copyright (C) 1996-2001, 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _POSIX_OPT_H
+#define _POSIX_OPT_H 1
+
+/* Job control is supported. */
+#define _POSIX_JOB_CONTROL 1
+
+/* Processes have a saved set-user-ID and a saved set-group-ID. */
+#define _POSIX_SAVED_IDS 1
+
+/* Priority scheduling is supported. */
+#define _POSIX_PRIORITY_SCHEDULING 200112L
+
+/* Synchronizing file data is supported. */
+#define _POSIX_SYNCHRONIZED_IO 200112L
+
+/* The fsync function is present. */
+#define _POSIX_FSYNC 200112L
+
+/* Mapping of files to memory is supported. */
+#define _POSIX_MAPPED_FILES 200112L
+
+/* Locking of all memory is supported. */
+#define _POSIX_MEMLOCK 200112L
+
+/* Locking of ranges of memory is supported. */
+#define _POSIX_MEMLOCK_RANGE 200112L
+
+/* Setting of memory protections is supported. */
+#define _POSIX_MEMORY_PROTECTION 200112L
+
+/* Implementation supports `poll' function. */
+#define _POSIX_POLL 1
+
+/* Implementation supports `select' and `pselect' functions. */
+#define _POSIX_SELECT 1
+
+/* Only root can change owner of file. */
+#define _POSIX_CHOWN_RESTRICTED 1
+
+/* `c_cc' member of 'struct termios' structure can be disabled by
+ using the value _POSIX_VDISABLE. */
+#define _POSIX_VDISABLE '\0'
+
+/* Filenames are not silently truncated. */
+#define _POSIX_NO_TRUNC 1
+
+/* X/Open realtime support is available. */
+#define _XOPEN_REALTIME 1
+
+/* X/Open realtime thread support is available. */
+#define _XOPEN_REALTIME_THREADS 1
+
+/* XPG4.2 shared memory is supported. */
+#define _XOPEN_SHM 1
+
+/* Tell we have POSIX threads. */
+#define _POSIX_THREADS 200112L
+
+/* We have the reentrant functions described in POSIX. */
+#define _POSIX_REENTRANT_FUNCTIONS 1
+#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L
+
+/* We provide priority scheduling for threads. */
+#define _POSIX_THREAD_PRIORITY_SCHEDULING 200112L
+
+/* We support user-defined stack sizes. */
+#define _POSIX_THREAD_ATTR_STACKSIZE 200112L
+
+/* We support user-defined stacks. */
+#define _POSIX_THREAD_ATTR_STACKADDR 200112L
+
+/* We support POSIX.1b semaphores, but only the non-shared form for now. */
+#define _POSIX_SEMAPHORES 1
+
+/* Real-time signals are supported. */
+#define _POSIX_REALTIME_SIGNALS 1
+
+/* We support asynchronous I/O. */
+#define _POSIX_ASYNCHRONOUS_IO 1
+#define _POSIX_ASYNC_IO 1
+/* Alternative name for Unix98. */
+#define _LFS_ASYNCHRONOUS_IO 1
+
+/* The LFS support in asynchronous I/O is also available. */
+#define _LFS64_ASYNCHRONOUS_IO 1
+
+/* The rest of the LFS is also available. */
+#define _LFS_LARGEFILE 1
+#define _LFS64_LARGEFILE 1
+#define _LFS64_STDIO 1
+
+/* POSIX shared memory objects are implemented. */
+#define _POSIX_SHARED_MEMORY_OBJECTS 200112L
+
+/* GNU libc provides regular expression handling. */
+#define _POSIX_REGEXP 1
+
+/* Reader/Writer locks are available. */
+#define _POSIX_READER_WRITER_LOCKS 200112L
+
+/* We have a POSIX shell. */
+#define _POSIX_SHELL 1
+
+/* We support the Timeouts option. */
+#define _POSIX_TIMEOUTS 200112L
+
+/* We support spinlocks. */
+#define _POSIX_SPIN_LOCKS 200112L
+
+/* The `spawn' function family is supported. */
+#define _POSIX_SPAWN 200112L
+
+/* We have POSIX timers. */
+#define _POSIX_TIMERS 1
+
+/* The barrier functions are available. */
+#define _POSIX_BARRIERS 200112L
+
+/* POSIX message queues are not yet supported. */
+#undef _POSIX_MESSAGE_PASSING
+
+/* Thread process-shared synchronization is supported. */
+#define _POSIX_THREAD_PROCESS_SHARED 200112L
+
+#endif /* posix_opt.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/configure b/nptl/sysdeps/unix/sysv/linux/configure
new file mode 100644
index 0000000000..229414dd74
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/configure
@@ -0,0 +1,3 @@
+# Local configure fragment for sysdeps/unix/sysv/linux.
+
+DEFINES="$DEFINES -D_LIBC_REENTRANT"
diff --git a/nptl/sysdeps/unix/sysv/linux/fork-gen.c b/nptl/sysdeps/unix/sysv/linux/fork-gen.c
new file mode 100644
index 0000000000..ff00261404
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/fork-gen.c
@@ -0,0 +1,37 @@
+/* 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. */
+
+#include <list.h>
+#include "fork.h"
+
+
+static struct fork_handler pthread_child_handler;
+
+
+void
+__register_pthread_fork_handler (ptr, reclaim)
+ unsigned long int *ptr;
+ void (*reclaim) (void);
+{
+ __fork_generation_pointer = ptr;
+
+ pthread_child_handler.handler = reclaim;
+
+ list_add_tail (&pthread_child_handler.list, &__fork_child_list);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/fork.c b/nptl/sysdeps/unix/sysv/linux/fork.c
new file mode 100644
index 0000000000..c1aa23c5c5
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/fork.c
@@ -0,0 +1,124 @@
+/* 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. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sysdep.h>
+#include <libio/libioP.h>
+#include <tls.h>
+#include "fork.h"
+
+
+unsigned long int *__fork_generation_pointer;
+
+
+lll_lock_t __fork_lock = LLL_LOCK_INITIALIZER;
+LIST_HEAD (__fork_prepare_list);
+LIST_HEAD (__fork_parent_list);
+LIST_HEAD (__fork_child_list);
+
+
+static void
+fresetlockfiles (void)
+{
+ _IO_ITER i;
+
+ for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
+ *((pthread_mutex_t *) _IO_iter_file(i)->_lock)
+ = (pthread_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+}
+
+
+pid_t
+__libc_fork (void)
+{
+ pid_t pid;
+ list_t *runp;
+
+ /* Get the lock so that the set of registered handlers is not
+ inconsistent or changes beneath us. */
+ lll_lock (__fork_lock);
+
+ /* Run all the registered preparation handlers. In reverse order. */
+ list_for_each_prev (runp, &__fork_prepare_list)
+ {
+ struct fork_handler *curp;
+
+ curp = list_entry (runp, struct fork_handler, list);
+
+ curp->handler ();
+ }
+
+ _IO_list_lock ();
+
+#ifdef ARCH_FORK
+ pid = ARCH_FORK ();
+#else
+# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used"
+ pid = INLINE_SYSCALL (fork, 0);
+#endif
+
+ if (pid == 0)
+ {
+ if (__fork_generation_pointer != NULL)
+ *__fork_generation_pointer += 4;
+
+ /* Reset the file list. These are recursive mutexes. */
+ fresetlockfiles ();
+
+ /* We execute this even if the 'fork' call failed. */
+ _IO_list_resetlock ();
+
+ /* Run the handlers registered for the child. */
+ list_for_each (runp, &__fork_child_list)
+ {
+ struct fork_handler *curp;
+
+ curp = list_entry (runp, struct fork_handler, list);
+
+ curp->handler ();
+ }
+
+ /* Initialize the fork lock. */
+ __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER;
+ }
+ else
+ {
+ /* We execute this even if the 'fork' call failed. */
+ _IO_list_unlock ();
+
+ /* Run the handlers registered for the parent. */
+ list_for_each (runp, &__fork_parent_list)
+ {
+ struct fork_handler *curp;
+
+ curp = list_entry (runp, struct fork_handler, list);
+
+ curp->handler ();
+ }
+
+ /* Release the for lock. */
+ lll_unlock (__fork_lock);
+ }
+
+ return pid;
+}
+weak_alias (__libc_fork, __fork)
+weak_alias (__libc_fork, fork)
diff --git a/nptl/sysdeps/unix/sysv/linux/fork.h b/nptl/sysdeps/unix/sysv/linux/fork.h
new file mode 100644
index 0000000000..85722a59eb
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/fork.h
@@ -0,0 +1,60 @@
+/* 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. */
+
+#include <list.h>
+#include <lowlevellock.h>
+
+/* The fork generation counter, defined in libpthread. */
+extern unsigned long int __fork_generation attribute_hidden;
+
+/* Pointer to the fork generation counter in the thread library. */
+extern unsigned long int *__fork_generation_pointer attribute_hidden;
+
+/* Lock to protect handling of fork handlers. */
+extern lll_lock_t __fork_lock attribute_hidden;
+
+/* Lists of registered fork handlers. */
+extern list_t __fork_prepare_list attribute_hidden;
+extern list_t __fork_parent_list attribute_hidden;
+extern list_t __fork_child_list attribute_hidden;
+
+
+/* Elements of the fork handler lists. */
+struct fork_handler
+{
+ list_t list;
+ void (*handler) (void);
+ void *dso_handle;
+};
+
+
+/* Function to call to unregister fork handlers. */
+extern void __unregister_atfork (void *dso_handle) attribute_hidden;
+#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle)
+
+
+/* C library side function to register new fork handlers. */
+extern int __register_atfork (void (*__prepare) (void),
+ void (*__parent) (void),
+ void (*__child) (void),
+ void *dso_handle);
+
+/* Register the generation counter in the libpthread with the libc. */
+extern void __register_pthread_fork_handler (unsigned long int *__ptr,
+ void (*reclaim) (void));
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
new file mode 100644
index 0000000000..2167bbb988
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
@@ -0,0 +1,150 @@
+/* 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. */
+
+#ifndef _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H 1
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_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;
+
+
+/* Data structures for mutex handling. The structure of the attribute
+ type is not exposed on purpose. */
+typedef union
+{
+ struct
+ {
+ int __lock;
+ unsigned int __count;
+ struct pthread *__owner;
+ /* KIND must stay at this position in the structure to maintain
+ binary compatibility. */
+ int __kind;
+ } __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 __nr_wakers;
+ unsigned int __nr_sleepers;
+ } __data;
+ char __size[__SIZEOF_PTHREAD_COND_T];
+ 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;
+
+
+#ifdef __USE_UNIX98
+/* 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;
+ /* FLAGS must stay at this position in the structure to maintain
+ binary compatibility. */
+ unsigned int __flags;
+ pthread_t __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/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h
new file mode 100644
index 0000000000..ab46ac099b
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/semaphore.h
@@ -0,0 +1,39 @@
+/* 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. */
+
+#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)
+
+/* Maximum value the semaphore can have. */
+#define SEM_VALUE_MAX ((int) ((~0u) >> 1))
+
+
+typedef union
+{
+ char __size[__SIZEOF_SEM_T];
+ long int __align;
+} sem_t;
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/createthread.c b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
new file mode 100644
index 0000000000..3196a8c754
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/createthread.c
@@ -0,0 +1,146 @@
+/* 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. */
+
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <atomic.h>
+#include <ldsodefs.h>
+#include <tls.h>
+
+
+#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
+
+
+static int
+create_thread (struct pthread *pd, STACK_VARIABLES_PARMS)
+{
+ union user_desc_init desc;
+
+ /* Describe the thread-local storage segment. */
+
+ /* The 'entry_number' field. The first three bits of the segment
+ register value select the GDT, ignore them. We get the index
+ from the value of the %gs register in the current thread. */
+ desc.vals[0] = TLS_GET_GS () >> 3;
+ /* The 'base_addr' field. Pointer to the TCB. */
+ desc.vals[1] = (unsigned long int) pd;
+ /* The 'limit' field. We use 4GB which is 0xfffff pages. */
+ desc.vals[2] = 0xfffff;
+ /* Collapsed value of the bitfield:
+ .seg_32bit = 1
+ .contents = 0
+ .read_exec_only = 0
+ .limit_in_pages = 1
+ .seg_not_present = 0
+ .useable = 1 */
+ desc.vals[3] = 0x51;
+
+
+ assert (pd->header.data.tcb != NULL);
+
+
+ if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+ {
+ /* The parent thread is supposed to report events. Check whether
+ the TD_CREATE event is needed, too. */
+ const int _idx = __td_eventword (TD_CREATE);
+ const uint32_t _mask = __td_eventmask (TD_CREATE);
+
+ if ((_mask & (__nptl_threads_events.event_bits[_idx]
+ | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
+ {
+ /* We have to report the new thread. Make sure the thread
+ does not run far by forcing it to get a lock. We lock it
+ here too so that the new thread cannot continue until we
+ tell it to. */
+ lll_lock (pd->lock);
+
+ /* Create the thread. */
+ if (__clone (start_thread_debug, STACK_VARIABLES_ARGS,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
+ CLONE_SETTLS | CLONE_PARENT_SETTID |
+ CLONE_CHILD_CLEARTID | CLONE_DETACHED | 0,
+ pd, &pd->tid, &desc.desc, &pd->tid) == -1)
+ /* Failed. */
+ return errno;
+
+ /* Now fill in the information about the new thread in
+ the newly created thread's data structure. We cannot let
+ the new thread do this since we don't know whether it was
+ already scheduled when we send the event. */
+ pd->eventbuf.eventnum = TD_CREATE;
+ pd->eventbuf.eventdata = pd;
+
+ /* Enqueue the descriptor. */
+ do
+ pd->nextevent = __nptl_last_event;
+ while (atomic_compare_and_exchange_acq (__nptl_last_event, pd,
+ pd->nextevent) != 0);
+
+ /* Now call the function which signals the event. */
+ __nptl_create_event ();
+
+ /* And finally restart the new thread. */
+ lll_unlock (pd->lock);
+
+ return 0;
+ }
+ }
+
+ /* We rely heavily on various flags the CLONE function understands:
+
+ CLONE_VM, CLONE_FS, CLONE_FILES
+ These flags select semantics with shared address space and
+ file descriptors according to what POSIX requires.
+
+ CLONE_SIGNAL
+ This flag selects the POSIX signal semantics.
+
+ CLONE_SETTLS
+ The sixth parameter to CLONE determines the TLS area for the
+ new thread.
+
+ CLONE_PARENT_SETTID
+ The kernels writes the thread ID of the newly created thread
+ into the location pointed to by the fifth parameters to CLONE.
+
+ Note that it would be semantically equivalent to use
+ CLONE_CHILD_SETTID but it is be more expensive in the kernel.
+
+ CLONE_CHILD_CLEARTID
+ The kernels clears the thread ID of a thread that has called
+ sys_exit() - using the same parameter as CLONE_SETTID.
+
+ CLONE_DETACHED
+ No signal is generated if the thread exists and it is
+ automatically reaped.
+
+ The termination signal is chosen to be zero which means no signal
+ is sent. */
+ if (__clone (start_thread, STACK_VARIABLES_ARGS,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL |
+ CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID |
+ CLONE_DETACHED | 0, pd, &pd->tid, &desc.desc, &pd->tid) == -1)
+ /* Failed. */
+ return errno;
+
+ return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/fork.c b/nptl/sysdeps/unix/sysv/linux/i386/fork.c
new file mode 100644
index 0000000000..813e5299a6
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/fork.c
@@ -0,0 +1,31 @@
+/* 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. */
+
+#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, 0, \
+ NULL, NULL, &THREAD_SELF->tid)
+
+#include "../fork.c"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
new file mode 100644
index 0000000000..9e2b9fec8d
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S
@@ -0,0 +1,279 @@
+/* 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. */
+
+#include <sysdep.h>
+
+ .text
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+#define EWOULDBLOCK 11
+#define EINVAL 22
+#define ETIMEDOUT 110
+
+#define cond_lock 0
+#define cond_nr_wakers 4
+#define cond_nr_sleepers 8
+
+
+ .global __lll_cond_wait
+ .type __lll_cond_wait,@function
+ .hidden __lll_cond_wait
+ .align 16
+__lll_cond_wait:
+ pushl %esi
+ pushl %ebx
+
+ xorl %esi, %esi
+
+ leal cond_nr_wakers(%eax), %ebx
+
+4: movl (%ebx), %edx
+ testl %edx, %edx
+ jne 1f
+
+ LOCK
+ decl cond_lock-cond_nr_wakers(%ebx)
+ jne 2f
+
+3: xorl %ecx, %ecx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ movl $1, %eax
+ LOCK
+ xaddl %eax, cond_lock-cond_nr_wakers(%ebx)
+ testl %eax, %eax
+ je 4b
+
+ leal cond_lock-cond_nr_wakers(%ebx), %ecx
+ /* Preserves %ebx, %edx, %edi, %esi. */
+ call __lll_mutex_lock_wait
+ jmp 4b
+
+1: decl (%ebx)
+
+ popl %ebx
+ popl %esi
+ ret
+
+2: leal cond_lock-cond_nr_wakers(%ebx), %eax
+ /* Preserves %ebx, %ecx, %edx, %edi, %esi. */
+ call __lll_mutex_unlock_wake
+ jmp 3b
+ .size __lll_cond_wait,.-__lll_cond_wait
+
+
+ .global __lll_cond_timedwait
+ .type __lll_cond_timedwait,@function
+ .hidden __lll_cond_timedwait
+ .align 16
+__lll_cond_timedwait:
+ /* Check for a valid timeout value. */
+ cmpl $1000000000, 4(%edx)
+ jae 1f
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ /* Stack frame for the timespec and timeval structs. */
+ subl $8, %esp
+
+ leal cond_nr_wakers(%eax), %ebp /* cond */
+ movl %edx, %edi /* timeout */
+
+9: movl (%ebp), %esi
+ testl %esi, %esi
+ jne 5f
+
+ LOCK
+ decl cond_lock-cond_nr_wakers(%ebp)
+ jne 6f
+
+ /* Get current time. */
+7: movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 3f
+ addl $1000000000, %edx
+ decl %ecx
+3: testl %ecx, %ecx
+ js 4f /* Time is already up. */
+
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+ movl %esi, %edx
+ movl %esp, %esi
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl %ebp, %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ movl %eax, %edx
+
+ movl $1, %eax
+ LOCK
+ xaddl %eax, cond_lock-cond_nr_wakers(%ebp)
+ testl %eax, %eax
+ jne 8f
+
+ cmpl $-ETIMEDOUT, %edx
+ jne 9b
+
+4: movl $ETIMEDOUT, %eax
+ jmp 2f
+
+5: decl (%ebp)
+ xorl %eax, %eax
+
+2: addl $8, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ ret
+
+6: leal cond_lock-cond_nr_wakers(%ebp), %eax
+ /* Preserves %ebx, %ecx, %edx, %edi, %esi. */
+ call __lll_mutex_unlock_wake
+ jmp 7b
+
+8: leal cond_lock-cond_nr_wakers(%ebp), %ecx
+ /* Preserves %ebx, %edx, %edi, %esi. */
+ call __lll_mutex_lock_wait
+ jmp 5b
+
+1: movl $EINVAL, %eax
+ ret
+ .size __lll_cond_timedwait,.-__lll_cond_timedwait
+
+
+ .global __lll_cond_wake
+ .type __lll_cond_wake,@function
+ .hidden __lll_cond_wake
+ .align 16
+__lll_cond_wake:
+ pushl %esi
+ pushl %ebx
+
+ movl %eax, %ebx
+
+ movl $1, %eax
+ LOCK
+ xaddl %eax, (%ebx)
+ testl %eax, %eax
+ jne 1f
+
+2: leal cond_nr_wakers(%ebx), %ebx
+ cmpl $0, cond_nr_sleepers-cond_nr_wakers(%ebx)
+ je 3f
+
+ incl (%ebx)
+ jz 5f
+
+6: movl $FUTEX_WAKE, %ecx
+ xorl %esi, %esi
+ movl %ecx, %edx /* movl $1, %edx */
+ movl $SYS_futex, %eax
+ int $0x80
+
+3: LOCK
+ decl cond_lock-cond_nr_wakers(%ebx)
+ je,pt 4f
+
+ leal cond_lock-cond_nr_wakers(%ebx), %eax
+ call __lll_mutex_unlock_wake
+
+4: popl %ebx
+ popl %esi
+ ret
+
+1: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+
+5: movl $0x80000000, (%ebx)
+ jmp 6b
+ .size __lll_cond_wake,.-__lll_cond_wake
+
+
+ .global __lll_cond_broadcast
+ .type __lll_cond_broadcast,@function
+ .hidden __lll_cond_broadcast
+ .align 16
+__lll_cond_broadcast:
+ pushl %esi
+ pushl %ebx
+
+ movl %eax, %ebx
+ movl $0x8000000, %edx
+
+ movl $1, %eax
+ LOCK
+ xaddl %eax, (%ebx)
+ testl %eax, %eax
+ jne 1f
+
+2: leal cond_nr_wakers(%ebx), %ebx
+ cmpl $0, cond_nr_sleepers-cond_nr_wakers(%ebx)
+ je 3f
+
+ orl %edx, (%ebx)
+
+6: movl $FUTEX_WAKE, %ecx
+ xorl %esi, %esi
+ movl $SYS_futex, %eax
+ int $0x80
+
+3: LOCK
+ decl cond_lock-cond_nr_wakers(%ebx)
+ je,pt 4f
+
+ leal cond_lock-cond_nr_wakers(%ebx), %eax
+ call __lll_mutex_unlock_wake
+
+4: popl %ebx
+ popl %esi
+ ret
+
+1: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+ .size __lll_cond_broadcast,.-__lll_cond_broadcast
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
new file mode 100644
index 0000000000..400413d7c2
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevellock.S
@@ -0,0 +1,180 @@
+/* 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. */
+
+#include <sysdep.h>
+
+ .text
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+#define ETIMEDOUT 110
+
+
+ .globl __lll_lock_wait
+ .type __lll_lock_wait,@function
+ .hidden __lll_lock_wait
+ .align 16
+__lll_lock_wait:
+ pushl %esi
+ pushl %ebx
+ pushl %edx
+
+ movl %ecx, %ebx
+ xorl %esi, %esi /* No timeout. */
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+1:
+ leal -1(%eax), %edx /* account for the preceeded xadd. */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ orl $-1, %eax /* Load -1. */
+ LOCK
+ xaddl %eax, (%ebx)
+ jne 1b
+
+ movl $-1, (%ebx)
+
+ popl %edx
+ popl %ebx
+ popl %esi
+ ret
+ .size __lll_lock_wait,.-__lll_lock_wait
+
+
+ .globl lll_unlock_wake_cb
+ .type lll_unlock_wake_cb,@function
+ .hidden lll_unlock_wake_cb
+ .align 16
+lll_unlock_wake_cb:
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+
+ movl 20(%esp), %ebx
+ LOCK
+ incl (%ebx)
+ jng 1f
+
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ ret
+ .size lll_unlock_wake_cb,.-lll_unlock_wake_cb
+
+
+ .globl __lll_unlock_wake
+ .type __lll_unlock_wake,@function
+ .hidden __lll_unlock_wake
+__lll_unlock_wake:
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+
+ movl %eax, %ebx
+1: movl $FUTEX_WAKE, %ecx
+ movl $1, %edx /* Wake one thread. */
+ xorl %esi, %esi
+ movl %edx, (%ebx) /* Stores '$1'. */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ ret
+ .size __lll_unlock_wake,.-__lll_unlock_wake
+
+
+ .globl __lll_timedwait_tid
+ .type __lll_timedwait_tid,@function
+ .hidden __lll_timedwait_tid
+__lll_timedwait_tid:
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ movl %eax, %ebp
+ movl %edx, %edi
+ subl $8, %esp
+
+ /* Get current time. */
+2: movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 5f
+ addl $1000000000, %edx
+ decl %ecx
+5: testl %ecx, %ecx
+ js 6f /* Time is already up. */
+
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+
+ movl (%ebp), %edx
+ testl %edx, %edx
+ jz 4f
+
+ movl %esp, %esi
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl %ebp, %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ movl %eax, %edx
+
+ cmpl $0, (%ebx)
+ jne 1f
+4: xorl %eax, %eax
+
+3: addl $8, %esp
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
+
+1: cmpl $-ETIMEDOUT, %edx
+ jne 2b
+6: movl $ETIMEDOUT, %eax
+ jmp 3b
+ .size __lll_timedwait_tid,.-__lll_timedwait_tid
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S
new file mode 100644
index 0000000000..a48cd88fa8
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelmutex.S
@@ -0,0 +1,176 @@
+/* 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. */
+
+#include <sysdep.h>
+
+ .text
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK lock
+#endif
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+#define EWOULDBLOCK 11
+#define EINVAL 22
+#define ETIMEDOUT 110
+
+
+ .globl __lll_mutex_lock_wait
+ .type __lll_mutex_lock_wait,@function
+ .hidden __lll_mutex_lock_wait
+ .align 16
+__lll_mutex_lock_wait:
+ pushl %esi
+ pushl %ebx
+ pushl %edx
+
+ movl %ecx, %ebx
+ xorl %esi, %esi /* No timeout. */
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+1:
+ leal 1(%eax), %edx /* account for the preceeded xadd. */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ movl $1, %eax
+ LOCK
+ xaddl %eax, (%ebx)
+ testl %eax, %eax
+ jne 1b
+
+ movl $2, (%ebx)
+
+ popl %edx
+ popl %ebx
+ popl %esi
+ ret
+ .size __lll_mutex_lock_wait,.-__lll_mutex_lock_wait
+
+
+ .globl __lll_mutex_timedlock_wait
+ .type __lll_mutex_timedlock_wait,@function
+ .hidden __lll_mutex_timedlock_wait
+ .align 16
+__lll_mutex_timedlock_wait:
+ /* Check for a valid timeout value. */
+ cmpl $1000000000, 4(%edx)
+ jae 3f
+
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ebp
+
+ /* Stack frame for the timespec and timeval structs. */
+ subl $8, %esp
+
+ movl %ecx, %ebp
+ movl %edx, %edi
+ leal 1(%eax), %esi
+
+ /* Get current time. */
+1:
+ movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 4f
+ addl $1000000000, %edx
+ decl %ecx
+4: testl %ecx, %ecx
+ js 5f /* Time is already up. */
+
+ /* Futex call. */
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+ movl %esi, %edx
+ movl %esp, %esi
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl %ebp, %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ movl $1, %esi
+ LOCK
+ xaddl %esi, (%ebx)
+ testl %esi, %esi
+ jne 7f
+
+ movl $2, (%ebx)
+ xorl %eax, %eax
+
+6: addl $8, %esp
+ popl %ebp
+ popl %ebx
+ popl %esi
+ popl %edi
+ ret
+
+ /* Check whether the time expired. */
+7: cmpl $-ETIMEDOUT, %eax
+ je 5f
+ jmp 1b
+
+3: movl $EINVAL, %eax
+ ret
+
+5: movl $ETIMEDOUT, %eax
+ jmp 6b
+ .size __lll_mutex_timedlock_wait,.-__lll_mutex_timedlock_wait
+
+
+ .globl __lll_mutex_unlock_wake
+ .type __lll_mutex_unlock_wake,@function
+ .hidden __lll_mutex_unlock_wake
+ .align 16
+__lll_mutex_unlock_wake:
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+
+ movl $FUTEX_WAKE, %ecx
+ movl %eax, %ebx
+ xorl %esi, %esi
+ movl $0, (%ebx)
+ movl $1, %edx /* Wake one thread. */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ ret
+ .size __lll_mutex_unlock_wake,.-__lll_mutex_unlock_wake
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S
new file mode 100644
index 0000000000..2dde246d1f
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S
@@ -0,0 +1,566 @@
+/* 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. */
+
+#include <sysdep.h>
+
+ .text
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+#define EAGAIN 11
+#define EDEADLK 35
+#define ETIMEDOUT 110
+
+/* Offsets in the pthread_rwlock_t structure. */
+#define MUTEX 0
+#define NR_READERS 4
+#define READERS_WAKEUP 8
+#define WRITERS_WAKEUP 12
+#define READERS_QUEUED 16
+#define WRITERS_QUEUED 20
+#define FLAGS 24
+#define WRITER 28
+
+#ifndef UP
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+
+ .globl __pthread_rwlock_rdlock
+ .type __pthread_rwlock_rdlock,@function
+ .align 16
+__pthread_rwlock_rdlock:
+ pushl %esi
+ pushl %ebx
+
+ xorl %esi, %esi
+ xorl %edx, %edx
+ movl 12(%esp), %ebx
+
+ /* Get the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebx)
+ testl %eax, %eax
+ jne 1f
+
+2: movl WRITER(%ebx), %eax
+ testl %eax, %eax
+ jne 14f
+ cmp $0, WRITERS_QUEUED(%ebx)
+ je 5f
+ cmpl $0, FLAGS(%ebx)
+ je 5f
+
+3: incl READERS_QUEUED(%ebx)
+ je 4f
+
+ LOCK
+ decl MUTEX(%ebx)
+ jne 10f
+
+11: addl $READERS_WAKEUP-MUTEX, %ebx
+ movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ subl $READERS_WAKEUP-MUTEX, %ebx
+
+ /* Reget the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebx)
+ testl %eax, %eax
+ jne 12f
+
+13: decl READERS_QUEUED(%ebx)
+ jne 2b
+ movl $0, READERS_WAKEUP(%ebx)
+ jmp 2b
+
+5: xorl %ecx, %ecx
+ incl NR_READERS(%ebx)
+ je 8f
+9: LOCK
+ decl MUTEX(%ebx)
+ jne 6f
+7:
+
+ movl %ecx, %eax
+ popl %ebx
+ popl %esi
+ ret
+
+1: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+
+14: cmpl %gs:8, %eax
+ jne 3b
+ /* Deadlock detected. */
+ movl $EDEADLK, %ecx
+ jmp 9b
+
+6: movl %ebx, %eax
+ call __lll_mutex_unlock_wake
+ jmp 7b
+
+ /* Overflow. */
+8: decl NR_READERS(%ebx)
+ movl $EAGAIN, %ecx
+ jmp 9b
+
+ /* Overflow. */
+4: decl READERS_QUEUED(%ebx)
+ movl $EAGAIN, %ecx
+ jmp 9b
+
+10: movl %ebx, %eax
+ call __lll_mutex_unlock_wake
+ jmp 11b
+
+12: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 13b
+ .size __pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock
+
+ .globl pthread_rwlock_rdlock
+pthread_rwlock_rdlock = __pthread_rwlock_rdlock
+
+
+ .globl pthread_rwlock_timedrdlock
+ .type pthread_rwlock_timedrdlock,@function
+ .align 16
+pthread_rwlock_timedrdlock:
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ pushl %ebp
+ subl $8, %esp
+
+ movl 28(%esp), %ebp
+ movl 32(%esp), %edi
+
+ /* Get the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebp)
+ testl %eax, %eax
+ jne 1f
+
+2: movl WRITER(%ebp), %eax
+ testl %eax, %eax
+ jne 14f
+ cmp $0, WRITERS_QUEUED(%ebp)
+ je 5f
+ cmpl $0, FLAGS(%ebp)
+ je 5f
+
+3: incl READERS_QUEUED(%ebp)
+ je 4f
+
+ LOCK
+ decl MUTEX(%ebp)
+ jne 10f
+
+ /* Get current time. */
+ movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 15f
+ addl $1000000000, %edx
+ decl %ecx
+15: testl %ecx, %ecx
+ js 16f /* Time is already up. */
+
+ /* Futex call. */
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl %esp, %esi
+ movl %ecx, %edx
+ leal READERS_WAKEUP(%ebp), %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+ movl %eax, %edx
+17:
+
+ /* Reget the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebp)
+ testl %eax, %eax
+ jne 12f
+
+13: cmpl $-ETIMEDOUT, %ecx
+ je 18f
+ decl READERS_QUEUED(%ebp)
+ jne 2b
+ movl $0, READERS_WAKEUP(%ebp)
+ jmp 2b
+
+
+5: xorl %ecx, %ecx
+ incl NR_READERS(%ebp)
+ je 8f
+9: LOCK
+ decl MUTEX(%ebp)
+ jne 6f
+
+7: movl %ecx, %eax
+
+ addl $8, %esp
+ popl %ebp
+ popl %ebx
+ popl %edi
+ popl %esi
+ ret
+
+1: movl %ebp, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+
+14: cmpl %gs:8, %eax
+ jne 3b
+ movl $EDEADLK, %ecx
+ jmp 9b
+
+6: movl %ebp, %eax
+ call __lll_mutex_unlock_wake
+ jmp 7b
+
+ /* Overflow. */
+8: decl NR_READERS(%ebp)
+ movl $EAGAIN, %ecx
+ jmp 9b
+
+ /* Overflow. */
+4: decl READERS_QUEUED(%ebp)
+ movl $EAGAIN, %ecx
+ jmp 9b
+
+10: movl %ebp, %eax
+ call __lll_mutex_unlock_wake
+ jmp 11b
+
+12: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 13b
+
+16: movl $-ETIMEDOUT, %ecx
+ jmp 17b
+
+18: movl $ETIMEDOUT, %ecx
+ jmp 9b
+ .size pthread_rwlock_timedrdlock,.-pthread_rwlock_timedrdlock
+
+
+ .globl __pthread_rwlock_wrlock
+ .type __pthread_rwlock_wrlock,@function
+ .align 16
+__pthread_rwlock_wrlock:
+ pushl %esi
+ pushl %ebx
+
+ xorl %esi, %esi
+ xorl %edx, %edx
+ movl 12(%esp), %ebx
+
+ /* Get the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebx)
+ testl %eax, %eax
+ jne 1f
+
+2: movl WRITER(%ebx), %eax
+ testl %eax, %eax
+ jne 14f
+ cmp $0, NR_READERS(%ebx)
+ je 5f
+
+3: incl WRITERS_QUEUED(%ebx)
+ je 4f
+
+ LOCK
+ decl MUTEX(%ebx)
+ jne 10f
+
+11: addl $WRITERS_WAKEUP-MUTEX, %ebx
+ movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl $SYS_futex, %eax
+ int $0x80
+
+ subl $WRITERS_WAKEUP-MUTEX, %ebx
+
+ /* Reget the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebx)
+ testl %eax, %eax
+ jne 12f
+
+13: decl WRITERS_QUEUED(%ebx)
+ movl $0, WRITERS_WAKEUP(%ebx)
+ jmp 2b
+
+5: xorl %ecx, %ecx
+ movl %gs:8, %eax
+ movl %eax, WRITER(%ebx)
+9: LOCK
+ decl MUTEX(%ebx)
+ jne 6f
+7:
+
+ movl %ecx, %eax
+ popl %ebx
+ popl %esi
+ ret
+
+1: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+
+14: cmpl %gs:8, %eax
+ jne 3b
+ movl $EDEADLK, %ecx
+ jmp 9b
+
+6: movl %ebx, %eax
+ call __lll_mutex_unlock_wake
+ jmp 7b
+
+4: decl WRITERS_QUEUED(%ebx)
+ movl $EAGAIN, %ecx
+ jmp 9b
+
+10: movl %ebx, %eax
+ call __lll_mutex_unlock_wake
+ jmp 11b
+
+12: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 13b
+ .size __pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock
+
+ .globl pthread_rwlock_wrlock
+pthread_rwlock_wrlock = __pthread_rwlock_wrlock
+
+
+ .globl pthread_rwlock_timedwrlock
+ .type pthread_rwlock_timedwrlock,@function
+ .align 16
+pthread_rwlock_timedwrlock:
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ pushl %ebp
+ subl $8, %esp
+
+ movl 28(%esp), %ebp
+ movl 32(%esp), %edi
+
+ /* Get the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebp)
+ testl %eax, %eax
+ jne 1f
+
+2: movl WRITER(%ebp), %eax
+ testl %eax, %eax
+ jne 14f
+ cmp $0, NR_READERS(%ebp)
+ je 5f
+
+3: incl WRITERS_QUEUED(%ebp)
+ je 4f
+
+ LOCK
+ decl MUTEX(%ebp)
+ jne 10f
+
+ /* Get current time. */
+ movl %esp, %ebx
+ xorl %ecx, %ecx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 15f
+ addl $1000000000, %edx
+ decl %ecx
+15: testl %ecx, %ecx
+ js 16f /* Time is already up. */
+
+ /* Futex call. */
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+ xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl %esp, %esi
+ movl %ecx, %edx
+ leal WRITERS_WAKEUP(%ebp), %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+ movl %eax, %edx
+17:
+
+ /* Reget the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebp)
+ testl %eax, %eax
+ jne 12f
+
+13: cmpl $-ETIMEDOUT, %ecx
+ je 18f
+ decl WRITERS_QUEUED(%ebp)
+ movl $0, WRITERS_WAKEUP(%ebp)
+ jmp 2b
+
+
+5: xorl %ecx, %ecx
+ movl %gs:8, %eax
+ movl %eax, WRITER(%ebp)
+9: LOCK
+ decl MUTEX(%ebp)
+ jne 6f
+
+7: movl %ecx, %eax
+
+ addl $8, %esp
+ popl %ebp
+ popl %ebx
+ popl %edi
+ popl %esi
+ ret
+
+1: movl %ebp, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+
+14: cmpl %gs:8, %eax
+ jne 3b
+ movl $EDEADLK, %ecx
+ jmp 9b
+
+6: movl %ebp, %eax
+ call __lll_mutex_unlock_wake
+ jmp 7b
+
+ /* Overflow. */
+4: decl WRITERS_QUEUED(%ebp)
+ movl $EAGAIN, %ecx
+ jmp 9b
+
+10: movl %ebp, %eax
+ call __lll_mutex_unlock_wake
+ jmp 11b
+
+12: movl %ebx, %ecx
+ call __lll_mutex_lock_wait
+ jmp 13b
+
+16: movl $-ETIMEDOUT, %ecx
+ jmp 17b
+
+18: movl $ETIMEDOUT, %ecx
+ jmp 9b
+ .size pthread_rwlock_timedwrlock,.-pthread_rwlock_timedwrlock
+
+ .globl __pthread_rwlock_unlock
+ .type __pthread_rwlock_unlock,@function
+ .align 16
+__pthread_rwlock_unlock:
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+
+ xorl %esi, %esi
+ xorl %edx, %edx
+ movl 16(%esp), %edi
+
+ /* Get the lock. */
+ movl $1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%edi)
+ testl %eax, %eax
+ jne 1f
+
+2: cmpl $0, WRITER(%edi)
+ jne 5f
+ decl NR_READERS(%edi)
+ jnz 6f
+
+5: movl $0, WRITER(%edi)
+
+ movl $0x7fffffff, %edx
+ leal READERS_WAKEUP(%edi), %ebx
+ movl $1, %ecx
+ leal WRITERS_WAKEUP(%edi), %eax
+ cmpl $0, WRITERS_QUEUED(%edi)
+ cmovne %ecx, %edx
+ cmovne %eax, %ebx
+ movl $SYS_futex, %eax
+ int $0x80
+
+6: LOCK
+ decl MUTEX(%edi)
+ jne 3f
+
+4: xorl %eax, %eax
+ popl %edi
+ popl %esi
+ popl %ebx
+ ret
+
+1: movl %edi, %ecx
+ call __lll_mutex_lock_wait
+ jmp 2b
+
+3: movl %edi, %eax
+ call __lll_mutex_unlock_wake
+ jmp 4b
+
+ .size __pthread_rwlock_unlock,.-__pthread_rwlock_unlock
+
+ .globl pthread_rwlock_unlock
+pthread_rwlock_unlock = __pthread_rwlock_unlock
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S
new file mode 100644
index 0000000000..18fb16f6f6
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S
@@ -0,0 +1,311 @@
+/* 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. */
+
+#include <sysdep.h>
+#include <shlib-compat.h>
+
+ .text
+
+#ifndef UP
+# define LOCK lock
+#else
+# define
+#endif
+
+#define SYS_gettimeofday __NR_gettimeofday
+#define SYS_futex 240
+#define FUTEX_WAKE 1
+
+#define EINTR 4
+#define EAGAIN 11
+#define EWOULDBLOCK EAGAIN
+#define EINVAL 22
+#define ETIMEDOUT 110
+
+
+ .globl __new_sem_wait
+ .type __new_sem_wait,@function
+ .align 16
+__new_sem_wait:
+ pushl %ebx
+ pushl %esi
+
+ movl 12(%esp), %ebx
+
+3: movl (%ebx), %eax
+2: testl %eax, %eax
+ je,pn 1f
+
+ leal -1(%eax), %edx
+ LOCK
+ cmpxchgl %edx, (%ebx)
+ jne,pn 2b
+ xorl %eax, %eax
+
+ popl %esi
+ popl %ebx
+ ret
+
+1: xorl %esi, %esi
+ movl $SYS_futex, %eax
+ movl %esi, %ecx
+ movl %esi, %edx
+ int $0x80
+
+ testl %eax, %eax
+ je 3b
+ cmpl $-EWOULDBLOCK, %eax
+ je 3b
+ negl %eax
+#ifdef PIC
+ call __i686.get_pc_thunk.bx
+#else
+ movl $4f, %ebx
+4:
+#endif
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl %gs:0, %edx
+ subl errno@gottpoff(%ebx), %edx
+ movl %eax, (%edx)
+ orl $-1, %eax
+ popl %esi
+ popl %ebx
+ ret
+ .size __new_sem_wait,.-__new_sem_wait
+ .symver __new_sem_wait, sem_wait@@GLIBC_2.1
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+ .global __old_sem_wait
+__old_sem_wait = __new_sem_wait
+ .symver __old_sem_wait, sem_wait@GLIBC_2.0
+#endif
+
+
+ .globl __new_sem_trywait
+ .type __new_sem_trywait,@function
+ .align 16
+__new_sem_trywait:
+ movl 4(%esp), %ecx
+
+ movl (%ecx), %eax
+2: testl %eax, %eax
+ jz 1f
+
+ leal -1(%eax), %edx
+ LOCK
+ cmpxchgl %edx, (%ecx)
+ jne,pn 2b
+ xorl %eax, %eax
+ ret
+
+1:
+#ifdef PIC
+ call __i686.get_pc_thunk.cx
+#else
+ movl $3f, %ecx
+3:
+#endif
+ addl $_GLOBAL_OFFSET_TABLE_, %ecx
+ movl %gs:0, %edx
+ subl errno@gottpoff(%ecx), %edx
+ movl $EAGAIN, (%edx)
+ orl $-1, %eax
+ ret
+ .size __new_sem_trywait,.-__new_sem_trywait
+ .symver __new_sem_trywait, sem_trywait@@GLIBC_2.1
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+ .global __old_sem_trywait
+__old_sem_trywait = __new_sem_trywait
+ .symver __old_sem_trywait, sem_trywait@GLIBC_2.0
+#endif
+
+
+ .globl sem_timedwait
+ .type sem_timedwait,@function
+ .align 16
+sem_timedwait:
+ movl 4(%esp), %ecx
+
+ movl (%ecx), %eax
+2: testl %eax, %eax
+ je,pn 1f
+
+ leal -1(%eax), %edx
+ LOCK
+ cmpxchgl %edx, (%ecx)
+ jne,pn 2b
+
+ xorl %eax, %eax
+ ret
+
+ /* Check whether the timeout value is valid. */
+1: pushl %esi
+ pushl %edi
+ pushl %ebx
+ subl $8, %esp
+
+ movl %esp, %esi
+ movl 28(%esp), %edi
+
+ /* Check for invalid nanosecond field. */
+ cmpl $1000000000, 4(%edi)
+ movl $EINVAL, %eax
+ jae 6f
+
+7: xorl %ecx, %ecx
+ movl %esp, %ebx
+ movl %ecx, %edx
+ movl $SYS_gettimeofday, %eax
+ int $0x80
+
+ /* Compute relative timeout. */
+ movl 4(%esp), %eax
+ movl $1000, %edx
+ mul %edx /* Milli seconds to nano seconds. */
+ movl (%edi), %ecx
+ movl 4(%edi), %edx
+ subl (%esp), %ecx
+ subl %eax, %edx
+ jns 5f
+ addl $1000000000, %edx
+ decl %ecx
+5: testl %ecx, %ecx
+ movl $ETIMEDOUT, %eax
+ js 6f /* Time is already up. */
+
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
+ movl 24(%esp), %ebx
+ xorl %ecx, %ecx
+ movl $SYS_futex, %eax
+ xorl %edx, %edx
+ int $0x80
+
+ testl %eax, %eax
+ je,pt 9f
+ cmpl $-EWOULDBLOCK, %eax
+ jne 3f
+
+9: movl (%ebx), %eax
+8: testl %eax, %eax
+ je 7b
+
+ leal -1(%eax), %ecx
+ LOCK
+ cmpxchgl %ecx, (%ebx)
+ jne,pn 8b
+
+ addl $8, %esp
+ xorl %eax, %eax
+ popl %ebx
+ popl %edi
+ popl %esi
+ ret
+
+3: negl %eax
+6:
+#ifdef PIC
+ call __i686.get_pc_thunk.bx
+#else
+ movl $4f, %ebx
+4:
+#endif
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl %gs:0, %edx
+ subl errno@gottpoff(%ebx), %edx
+ movl %eax, (%edx)
+
+ addl $8, %esp
+ orl $-1, %eax
+ popl %ebx
+ popl %edi
+ popl %esi
+ ret
+ .size sem_timedwait,.-sem_timedwait
+
+
+ .globl __new_sem_post
+ .type __new_sem_post,@function
+ .align 16
+__new_sem_post:
+ pushl %esi
+ pushl %ebx
+
+ movl 12(%esp), %ebx
+ movl $1, %edx
+ LOCK
+ xaddl %edx, (%ebx)
+
+ xorl %esi, %esi
+ movl $SYS_futex, %eax
+ movl $FUTEX_WAKE, %ecx
+ incl %edx
+ int $0x80
+
+ testl %eax, %eax
+ js 1f
+
+ popl %ebx
+ popl %esi
+ ret
+
+1:
+#ifdef PIC
+ call __i686.get_pc_thunk.bx
+#else
+ movl $4f, %ebx
+4:
+#endif
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl %gs:0, %edx
+ subl errno@gottpoff(%ebx), %edx
+ movl $EINVAL, (%edx)
+
+ orl $-1, %eax
+ popl %ebx
+ popl %esi
+ ret
+ .size __new_sem_post,.-__new_sem_post
+ .symver __new_sem_post, sem_post@@GLIBC_2.1
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+ .global __old_sem_post
+__old_sem_post = __new_sem_post
+ .symver __old_sem_post, sem_post@GLIBC_2.0
+#endif
+
+
+#ifdef PIC
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+ .globl __i686.get_pc_thunk.bx
+ .hidden __i686.get_pc_thunk.bx
+ .type __i686.get_pc_thunk.bx,@function
+__i686.get_pc_thunk.bx:
+ movl (%esp), %ebx;
+ ret
+ .size __i686.get_pc_thunk.bx,.-__i686.get_pc_thunk.bx
+
+
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
+ .globl __i686.get_pc_thunk.cx
+ .hidden __i686.get_pc_thunk.cx
+ .type __i686.get_pc_thunk.cx,@function
+__i686.get_pc_thunk.cx:
+ movl (%esp), %ecx;
+ ret
+ .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S
new file mode 100644
index 0000000000..a385adc5f9
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_barrier_wait.S
@@ -0,0 +1,122 @@
+/* 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. */
+
+#include <sysdep.h>
+
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+#ifndef UP
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+#define CURR_EVENT 0
+#define MUTEX 4
+#define LEFT 8
+#define INIT_COUNT 12
+
+
+ .text
+
+ .globl pthread_barrier_wait
+ .type pthread_barrier_wait,@function
+ .align 16
+pthread_barrier_wait:
+ pushl %esi
+ pushl %ebx
+
+ movl 12(%esp), %ebx
+ xorl %esi, %esi
+
+ /* Get the mutex. */
+ orl $-1, %eax
+ LOCK
+ xaddl %eax, MUTEX(%ebx)
+ jne 1f
+
+ /* One less waiter. If this was the last one needed wake
+ everybody. */
+2: decl LEFT(%ebx)
+ je 3f
+
+ /* There are more threads to come. */
+ movl CURR_EVENT(%ebx), %edx
+
+ /* Release the mutex. */
+ LOCK
+ incl MUTEX(%ebx)
+ jng 6f
+
+ /* Wait for the remaining threads. The call will return immediately
+ if the CURR_EVENT memory has meanwhile been changed. */
+7: movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
+8: movl $SYS_futex, %eax
+ int $0x80
+
+ /* Don't return on spurious wakeups. The syscall does not change
+ any register except %eax so there is no need to reload any of
+ them. */
+ cmpl %edx, CURR_EVENT(%ebx)
+ je,pn 8b
+
+ /* Note: %esi is still zero. */
+ movl %esi, %eax /* != PTHREAD_BARRIER_SERIAL_THREAD */
+
+ popl %ebx
+ popl %esi
+ ret
+
+ /* The necessary number of threads arrived. */
+3: movl INIT_COUNT(%ebx), %eax
+ movl %eax, LEFT(%ebx)
+ incl CURR_EVENT(%ebx)
+
+ /* Wake up all waiters. The count is a signed number in the kernel
+ so 0x7fffffff is the highest value. */
+ movl $0x7fffffff, %edx
+ movl $FUTEX_WAKE, %ecx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ /* Release the mutex. */
+ LOCK
+ incl MUTEX(%ebx)
+ jng 4f
+
+5: orl $-1, %eax /* == PTHREAD_BARRIER_SERIAL_THREAD */
+
+ popl %ebx
+ popl %esi
+ ret
+
+1: leal MUTEX(%ebx), %ecx
+ call __lll_lock_wait
+ jmp 2b
+
+4: leal MUTEX(%ebx), %eax
+ call __lll_unlock_wake
+ jmp 5b
+
+6: leal MUTEX(%ebx), %eax
+ call __lll_unlock_wake
+ jmp 7b
+ .size pthread_barrier_wait,.-pthread_barrier_wait
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S
new file mode 100644
index 0000000000..3dc8403a29
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelcond.S
@@ -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. */
+
+#include "../i486/lowlevelcond.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S
new file mode 100644
index 0000000000..e60dea89ef
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevellock.S
@@ -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. */
+
+#include "../i486/lowlevellock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S
new file mode 100644
index 0000000000..50481991ff
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelmutex.S
@@ -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. */
+
+#include "../i486/lowlevelmutex.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S
new file mode 100644
index 0000000000..6f4a8305ee
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelrwlock.S
@@ -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. */
+
+#include "../i486/lowlevelrwlock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S
new file mode 100644
index 0000000000..cfaa36ac74
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/lowlevelsem.S
@@ -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. */
+
+#include "../i486/lowlevelsem.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S
new file mode 100644
index 0000000000..6d20b9a95c
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i586/pthread_barrier_wait.S
@@ -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. */
+
+#include "../i486/pthread_barrier_wait.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S
new file mode 100644
index 0000000000..3dc8403a29
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelcond.S
@@ -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. */
+
+#include "../i486/lowlevelcond.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S
new file mode 100644
index 0000000000..e60dea89ef
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevellock.S
@@ -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. */
+
+#include "../i486/lowlevellock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S
new file mode 100644
index 0000000000..50481991ff
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelmutex.S
@@ -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. */
+
+#include "../i486/lowlevelmutex.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S
new file mode 100644
index 0000000000..6f4a8305ee
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelrwlock.S
@@ -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. */
+
+#include "../i486/lowlevelrwlock.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S
new file mode 100644
index 0000000000..cfaa36ac74
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/lowlevelsem.S
@@ -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. */
+
+#include "../i486/lowlevelsem.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S
new file mode 100644
index 0000000000..6d20b9a95c
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/pthread_barrier_wait.S
@@ -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. */
+
+#include "../i486/pthread_barrier_wait.S"
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
new file mode 100644
index 0000000000..71babd5c93
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h
@@ -0,0 +1,257 @@
+/* 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. */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H 1
+
+#include <time.h>
+#include <bits/pthreadtypes.h>
+
+#ifndef LOCK_INSTR
+# ifdef UP
+# define LOCK_INSTR /* nothing */
+# else
+# define LOCK_INSTR "lock;"
+# endif
+#endif
+
+#define SYS_futex 240
+#define FUTEX_WAIT 0
+#define FUTEX_WAKE 1
+
+
+/* Initializer for compatibility lock. */
+#define LLL_MUTEX_LOCK_INITIALIZER (0)
+
+
+/* Does not preserve %eax and %ecx. */
+extern int __lll_mutex_lock_wait (int val, int *__futex)
+ __attribute ((regparm (2))) attribute_hidden;
+/* Does not preserver %eax, %ecx, and %edx. */
+extern int __lll_mutex_timedlock_wait (int val, int *__futex,
+ const struct timespec *abstime)
+ __attribute ((regparm (3))) attribute_hidden;
+/* Preserves all registers but %eax. */
+extern int __lll_mutex_unlock_wait (int *__futex)
+ __attribute ((regparm (1))) attribute_hidden;
+
+
+#define lll_mutex_trylock(futex) \
+ ({ unsigned char ret; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0" \
+ : "=a" (ret), "=m" (futex) \
+ : "r" (1), "1" (futex), "0" (0)); \
+ ret; })
+
+
+#define lll_mutex_lock(futex) \
+ (void) ({ int ignore1, ignore2; \
+ __asm (LOCK_INSTR "xaddl %0, %2\n\t" \
+ "testl %0, %0\n\t" \
+ "jne 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %2, %%ecx\n\t" \
+ "call __lll_mutex_lock_wait\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=a" (ignore1), "=&c" (ignore2), "=m" (futex) \
+ : "0" (1), "2" (futex)); })
+
+
+#define lll_mutex_timedlock(futex, timeout) \
+ ({ int result, ignore1, ignore2; \
+ __asm (LOCK_INSTR "xaddl %0, %3\n\t" \
+ "testl %0, %0\n\t" \
+ "jne 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %3, %%ecx\n\t" \
+ "movl %6, %%edx\n\t" \
+ "call __lll_mutex_timedlock_wait\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=a" (result), "=&c" (ignore1), "=&d" (ignore2), "=m" (futex) \
+ : "0" (1), "3" (futex), "m" (timeout)); \
+ result; })
+
+
+#define lll_mutex_unlock(futex) \
+ (void) ({ int ignore; \
+ __asm (LOCK_INSTR "decl %0\n\t" \
+ "jne 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %0, %%eax\n\t" \
+ "call __lll_mutex_unlock_wake\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=m" (futex), "=&a" (ignore) \
+ : "0" (futex)); })
+
+
+#define lll_mutex_islocked(futex) \
+ (futex != 0)
+
+
+/* We have a separate internal lock implementation which is not tied
+ to binary compatibility. */
+
+/* Type for lock object. */
+typedef int lll_lock_t;
+
+/* Initializers for lock. */
+#define LLL_LOCK_INITIALIZER (1)
+#define LLL_LOCK_INITIALIZER_LOCKED (0)
+
+
+extern int __lll_lock_wait (int val, int *__futex)
+ __attribute ((regparm (2))) attribute_hidden;
+extern int __lll_unlock_wake (int *__futex)
+ __attribute ((regparm (1))) attribute_hidden;
+extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
+
+
+/* The states of a lock are:
+ 1 - untaken
+ 0 - taken by one user
+ <0 - taken by more users */
+
+
+#define lll_trylock(futex) \
+ ({ unsigned char ret; \
+ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1; setne %0" \
+ : "=a" (ret), "=m" (futex) \
+ : "r" (0), "1" (futex), "0" (1)); \
+ ret; })
+
+
+#define lll_lock(futex) \
+ (void) ({ int ignore1, ignore2; \
+ __asm (LOCK_INSTR "xaddl %0, %2\n\t" \
+ "jne 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %2, %%ecx\n\t" \
+ "call __lll_lock_wait\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=a" (ignore1), "=&c" (ignore2), "=m" (futex) \
+ : "0" (-1), "2" (futex)); })
+
+
+#define lll_unlock(futex) \
+ (void) ({ int ignore; \
+ __asm (LOCK_INSTR "incl %0\n\t" \
+ "jng 1f\n\t" \
+ ".subsection 1\n" \
+ "1:\tleal %0, %%eax\n\t" \
+ "call __lll_unlock_wake\n\t" \
+ "jmp 2f\n\t" \
+ ".previous\n" \
+ "2:" \
+ : "=m" (futex), "=&a" (ignore) \
+ : "0" (futex)); })
+
+
+#define lll_islocked(futex) \
+ (futex != 0)
+
+
+/* The kernel notifies a process with 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.
+
+ The macro parameter must not have any side effect. */
+#ifdef PIC
+# define LLL_TID_EBX_LOAD "xchgl %2, %%ebx\n"
+# define LLL_TID_EBX_REG "D"
+#else
+# define LLL_TID_EBX_LOAD
+# define LLL_TID_EBX_REG "b"
+#endif
+#define lll_wait_tid(tid) \
+ do { \
+ int __ignore; \
+ register __typeof (tid) _tid asm ("edx") = (tid); \
+ if (_tid != 0) \
+ __asm __volatile (LLL_TID_EBX_LOAD \
+ "1:\tmovl %1, %%eax\n\t" \
+ "int $0x80\n\t" \
+ "cmpl $0, (%%ebx)\n\t" \
+ "jne,pn 1b\n\t" \
+ LLL_TID_EBX_LOAD \
+ : "=&a" (__ignore) \
+ : "i" (SYS_futex), LLL_TID_EBX_REG (&tid), "S" (0), \
+ "c" (FUTEX_WAIT), "d" (_tid)); \
+ } while (0)
+
+extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
+ __attribute__ ((regparm (2))) attribute_hidden;
+#define lll_timedwait_tid(tid, abstime) \
+ ({ \
+ int __result = 0; \
+ if (tid != 0) \
+ { \
+ if (abstime == NULL || abstime->tv_nsec >= 1000000000) \
+ __result = EINVAL; \
+ else \
+ __result = __lll_timedwait_tid (&tid, abstime); \
+ } \
+ __result; })
+
+
+#define lll_wake_tid(tid) \
+ do { \
+ int __ignore; \
+ (tid) = 0; \
+ __asm __volatile (LLL_TID_EBX_LOAD \
+ "\tint $0x80\n\t" \
+ LLL_TID_EBX_LOAD \
+ : "=a" (__ignore) \
+ : "0" (SYS_futex), LLL_TID_EBX_REG (&(tid)), "S" (0), \
+ "c" (FUTEX_WAKE), "d" (0x7fffffff)); \
+ } while (0)
+
+
+/* Conditional variable handling. */
+
+extern void __lll_cond_wait (pthread_cond_t *cond)
+ __attribute ((regparm (1))) attribute_hidden;
+extern int __lll_cond_timedwait (pthread_cond_t *cond,
+ const struct timespec *abstime)
+ __attribute ((regparm (2))) attribute_hidden;
+extern void __lll_cond_wake (pthread_cond_t *cond)
+ __attribute ((regparm (1))) attribute_hidden;
+extern void __lll_cond_broadcast (pthread_cond_t *cond)
+ __attribute ((regparm (1))) attribute_hidden;
+
+
+#define lll_cond_wait(cond) \
+ __lll_cond_wait (cond)
+#define lll_cond_timedwait(cond, abstime) \
+ __lll_cond_timedwait (cond, abstime)
+#define lll_cond_wake(cond) \
+ __lll_cond_wake (cond)
+#define lll_cond_broadcast(cond) \
+ __lll_cond_broadcast (cond)
+
+
+#endif /* lowlevellock.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h b/nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h
new file mode 100644
index 0000000000..bd5f96402b
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/lowlevelsem.h
@@ -0,0 +1,101 @@
+/* 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. */
+
+#ifndef _LOWLEVELSEM_H
+#define _LOWLEVELSEM_H 1
+
+#ifndef LOCK
+# ifdef UP
+# define LOCK /* nothing */
+# else
+# define LOCK "lock;"
+# endif
+#endif
+
+#define SYS_futex 240
+
+
+#define lll_sem_wait(sem) \
+ ({ int result, ignore1, ignore2; \
+ __asm __volatile ("1:\tincl 8(%4)\n\t" \
+ LOCK "incl (%4)\n\t" \
+ "jng 2f\n" \
+ ".subsection 1\n" \
+ "2:\tmovl %4, %%eax\n\t" \
+ "call __lll_unlock_wake\n\t" \
+ "jmp 3f\n\t" \
+ ".previous\n" \
+ "3:\tpushl %%ebx\n\t" \
+ "movl %%esi, %%ecx\n\t" \
+ "movl %%esi, %%edx\n\t" \
+ "leal 4(%4), %%ebx\n\t" \
+ "movl %5, %%eax\n\t" \
+ "int $0x80\n\t" \
+ "movl %%eax, %%edx\n\t" \
+ "popl %%ebx\n\t" \
+ "orl $-1, %%eax\n\t" \
+ LOCK "xaddl %%eax, (%4)\n\t" \
+ "jne 4f\n\t" \
+ ".subsection 1\n" \
+ "4:\tmovl %4, %%ecx\n\t" \
+ "call __lll_lock_wait\n\t" \
+ "jmp 5f\n\t" \
+ ".previous\n" \
+ "5:\tdecl 8(%4)\n\t" \
+ "xorl %0, %0\n\t" \
+ "cmpl $0, 4(%4)\n\t" \
+ "jne,pt 6f\n\t" \
+ "cmpl %7, %%edx\n\t" \
+ "jne,pn 1b\n\t" \
+ "addl %8, %0\n\t" /* Shorter than movl %7, %0 */ \
+ "6:" \
+ : "=a" (result), "=c" (ignore1), "=d" (ignore2), \
+ "=m" (*sem) \
+ : "D" (sem), "i" (SYS_futex), "S" (0), \
+ "i" (-EINTR), "i" (EINTR)); \
+ result; })
+
+
+extern int __lll_sem_timedwait (struct sem *sem, const struct timespec *ts)
+ __attribute__ ((regparm (2))) attribute_hidden;
+#define lll_sem_timedwait(sem, timeout) \
+ __lll_sem_timedwait (sem, timeout)
+
+
+#define lll_sem_post(sem) \
+ (void) ({ int ignore1, ignore2, ignore3; \
+ __asm __volatile ("movl $1, %%eax\n\t" \
+ LOCK \
+ "xaddl %%eax, (%4)\n\t" \
+ "pushl %%esi\n\t" \
+ "pushl %%ebx\n\t" \
+ "movl %4, %%ebx\n\t" \
+ "leal 1(%%eax), %%edx\n\t" \
+ "xorl %%esi, %%esi\n\t" \
+ "movl %5, %%eax\n\t" \
+ /* movl $FUTEX_WAKE, %ecx */ \
+ "movl $1, %%ecx\n\t" \
+ "int $0x80\n\t" \
+ "popl %%ebx\n\t" \
+ "popl %%esi" \
+ : "=&a" (ignore1), "=c" (ignore2), \
+ "=m" (*sem), "=d" (ignore3) \
+ : "r" (sem), "i" (SYS_futex)); })
+
+#endif /* lowlevelsem.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S b/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S
new file mode 100644
index 0000000000..6994c0d7fa
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/pt-vfork.S
@@ -0,0 +1,49 @@
+/* Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Andreas Schwab <schwab@gnu.org>.
+
+ 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>
+#define _ERRNO_H 1
+#include <bits/errno.h>
+#include <kernel-features.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. */
+
+ENTRY (__vfork)
+ /* Pop the return PC value into ECX. */
+ popl %ecx
+
+ /* Stuff the syscall number in EAX and enter into the kernel. */
+ movl $SYS_ify (vfork), %eax
+ int $0x80
+
+ /* Jump to the return PC. Don't jump directly since this
+ disturbs the branch target cache. Instead push the return
+ address back on the stack. */
+ pushl %ecx
+
+ cmpl $-4095, %eax
+ jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */
+.Lpseudo_end:
+ ret
+PSEUDO_END (__vfork)
+
+weak_alias (__vfork, vfork)
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S b/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S
new file mode 100644
index 0000000000..747c8ec2d2
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S
@@ -0,0 +1,171 @@
+/* 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. */
+
+#include <sysdep.h>
+
+#ifndef UP
+# define LOCK lock
+#else
+# define LOCK
+#endif
+
+#define SYS_futex 240
+#define FUTEX_WAKE 1
+
+ .comm __fork_generation, 4, 4
+
+ .text
+
+
+ .globl __pthread_once
+ .type __pthread_once,@function
+ .align 16
+__pthread_once:
+ movl 4(%esp), %ecx
+ testl $2, (%ecx)
+ jz 1f
+ xorl %eax, %eax
+ ret
+
+1: pushl %ebx
+ pushl %esi
+ movl %ecx, %ebx
+ xorl %esi, %esi
+
+ /* Not yet initialized or initialization in progress.
+ Get the fork generation counter now. */
+6: movl (%ebx), %eax
+#ifdef PIC
+ call __i686.get_pc_thunk.cx
+ addl $_GLOBAL_OFFSET_TABLE_, %ecx
+#endif
+
+5: movl %eax, %edx
+
+ testl $2, %eax
+ jnz 4f
+
+ andl $3, %edx
+#ifdef PIC
+ orl __fork_generation@GOTOFF(%ecx), %edx
+#else
+ orl __fork_generation, %edx
+#endif
+ orl $1, %edx
+
+ LOCK
+ cmpxchgl %edx, (%ebx)
+ jnz 5b
+
+ /* Check whether another thread already runs the initializer. */
+ testl $1, %eax
+ jz 3f /* No -> do it. */
+
+ /* Check whether the initializer execution was interrupted
+ by a fork. */
+ xorl %edx, %eax
+ testl $0xfffffffc, %eax
+ jnz 3f /* Different for generation -> run initializer. */
+
+ /* Somebody else got here first. Wait. */
+ movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
+ movl $SYS_futex, %eax
+ int $0x80
+ jmp 6b
+
+3: /* Call the initializer function after setting up the
+ cancellation handler. */
+ subl $16, %esp
+
+ /* Push the cleanup handler. */
+#ifdef PIC
+ leal clear_once_control@GOTOFF(%ecx), %eax
+#else
+ leal clear_once_control, %eax
+#endif
+ movl %esp, %edx
+ pushl %ebx
+ pushl %eax
+ pushl %edx
+ call _GI_pthread_cleanup_push /* Note: no @PLT. */
+
+ movl 44(%esp), %eax
+ call *%eax
+
+ /* Pop the cleanup handler. This code depends on the once
+ handler and _pthread_cleanup_push not touch the content
+ of the stack. Otherwise the first parameter would have
+ to be reloaded. */
+ movl $0, 4(%esp)
+ call _GI_pthread_cleanup_pop /* Note: no @PLT. */
+
+ addl $28, %esp
+
+ /* Sucessful run of the initializer. Signal that we are done. */
+ LOCK
+ incl (%ebx)
+
+ /* Wake up all other threads. */
+ movl $0x7fffffff, %edx
+ movl $FUTEX_WAKE, %ecx
+ movl $SYS_futex, %eax
+ int $0x80
+
+4: popl %esi
+ popl %ebx
+ xorl %eax, %eax
+ ret
+
+ .size __pthread_once,.-__pthread_once
+
+ .globl pthread_once
+pthread_once = __pthread_once
+
+
+ .type clear_once_control,@function
+ .align 16
+clear_once_control:
+ pushl %esi
+ pushl %ebx
+
+ movl 4(%esp), %eax
+ movl $0, (%eax)
+
+ xorl %esi, %esi
+ movl $0x7fffffff, %edx
+ movl $FUTEX_WAKE, %ecx
+ movl $SYS_futex, %eax
+ int $0x80
+
+ popl %ebx
+ popl %esi
+ ret
+ .size clear_once_control,.-clear_once_control
+
+
+#ifdef PIC
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
+ .globl __i686.get_pc_thunk.cx
+ .hidden __i686.get_pc_thunk.cx
+ .type __i686.get_pc_thunk.cx,@function
+__i686.get_pc_thunk.cx:
+ movl (%esp), %ecx;
+ ret
+ .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
+#endif
diff --git a/nptl/sysdeps/unix/sysv/linux/internaltypes.h b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
new file mode 100644
index 0000000000..24ead1b5ce
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/internaltypes.h
@@ -0,0 +1,130 @@
+/* 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. */
+
+#ifndef _INTERNALTYPES_H
+#define _INTERNALTYPES_H 1
+
+
+struct pthread_attr
+{
+ /* Scheduler parameters and priority. */
+ struct sched_param schedparam;
+ int schedpolicy;
+ /* Various flags like detachstate, scope, etc. */
+ int flags;
+ /* Size of guard area. */
+ size_t guardsize;
+ /* Stack handling. */
+ void *stackaddr;
+ size_t stacksize;
+
+ /* Chain of all initialized attributes. Keep this last since it is
+ not always used. */
+ struct pthread_attr *next;
+};
+
+#define ATTR_FLAG_DETACHSTATE 0x0001
+#define ATTR_FLAG_NOTINHERITSCHED 0x0002
+#define ATTR_FLAG_SCOPEPROCESS 0x0004
+#define ATTR_FLAG_STACKADDR 0x0008
+
+
+/* Mutex attribute data structure. */
+struct pthread_mutexattr
+{
+ /* Identifier for the kind of mutex.
+
+ Bit 31 is set if the mutex is to be shared between processes.
+
+ Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify
+ the type of the mutex. */
+ int mutexkind;
+};
+
+
+/* Conditional variable attribute data structure. */
+struct pthread_condattr
+{
+ /* Flag whether coditional variable will be shareable between processes. */
+ int pshared;
+};
+
+
+/* Read-write lock variable attribute data structure. */
+struct pthread_rwlockattr
+{
+ int lockkind;
+ int pshared;
+};
+
+
+/* Barrier data structure. */
+struct pthread_barrier
+{
+ unsigned int curr_event;
+ int lock;
+ unsigned int left;
+ unsigned int init_count;
+};
+
+
+/* Barrier variable attribute data structure. */
+struct pthread_barrierattr
+{
+ int pshared;
+};
+
+
+/* Thread-local data handling. */
+struct pthread_key_struct
+{
+ /* Sequence numbers. Even numbers indicated vacant entries. Note
+ that zero is even. We use uintptr_t to not require padding on
+ 32- and 64-bit machines. On 64-bit machines it helps to avoid
+ wrapping, too. */
+ uintptr_t seq;
+
+ /* Destructor for the data. */
+ void (*destr) (void *);
+};
+
+/* Check whether an entry is unused. */
+#define KEY_UNUSED(p) (((p) & 1) == 0)
+/* Check whether a key is usable. We cannot reuse an allocated key if
+ the sequence counter would overflow after the next destroy call.
+ This would mean that we potentially free memory for a key with the
+ same sequence. This is *very* unlikely to happen, A program would
+ have to create and destroy a key 2^31 times (on 32-bit platforms,
+ on 64-bit platforms that would be 2^63). If it should happen we
+ simply don't use this specific key anymore. */
+#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2)))
+
+
+/* Handling of read-write lock data. */
+// XXX For now there is only one flag. Maybe more in future.
+#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0)
+
+
+/* Semaphore variable structure. */
+struct sem
+{
+ unsigned int count;
+};
+
+#endif /* internaltypes.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c b/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c
new file mode 100644
index 0000000000..0fd3c9aa58
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/jmp-unwind.c
@@ -0,0 +1,33 @@
+/* _longjmp_unwind -- Clean up stack frames unwound by longjmp. Linux version.
+ Copyright (C) 1995, 1997, 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. */
+
+#include <setjmp.h>
+#include <stddef.h>
+
+
+extern void __pthread_cleanup_upto (jmp_buf env, char *targetframe);
+#pragma weak __pthread_cleanup_upto
+
+
+void
+_longjmp_unwind (jmp_buf env, int val)
+{
+ if (__pthread_cleanup_upto != NULL)
+ __pthread_cleanup_upto (env, __builtin_frame_address (0));
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pt-fork.c b/nptl/sysdeps/unix/sysv/linux/pt-fork.c
new file mode 100644
index 0000000000..a1e228ee29
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pt-fork.c
@@ -0,0 +1,28 @@
+/* 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. */
+
+#include <unistd.h>
+
+
+pid_t
+__fork (void)
+{
+ return __libc_fork ();
+}
+strong_alias (__fork, fork)
diff --git a/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/nptl/sysdeps/unix/sysv/linux/pt-raise.c
new file mode 100644
index 0000000000..0c68960e5d
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pt-raise.c
@@ -0,0 +1,31 @@
+/* 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. */
+
+#include <errno.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+
+int
+raise (sig)
+ int sig;
+{
+ return INLINE_SYSCALL (tkill, 2, THREAD_SELF->tid, sig);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/nptl/sysdeps/unix/sysv/linux/pthread_kill.c
new file mode 100644
index 0000000000..f5c2377e7e
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_kill.c
@@ -0,0 +1,36 @@
+/* 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. */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthreadP.h>
+#include <tls.h>
+#include <sysdep.h>
+
+
+int
+pthread_kill (threadid, signo)
+ pthread_t threadid;
+ int signo;
+{
+ struct pthread *pd = (struct pthread *) threadid;
+
+ /* We have a special syscall to do the work. */
+ return INLINE_SYSCALL (tkill, 2, pd->tid, signo);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_yield.c b/nptl/sysdeps/unix/sysv/linux/pthread_yield.c
new file mode 100644
index 0000000000..5aecffcf0d
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/pthread_yield.c
@@ -0,0 +1,30 @@
+/* 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. */
+
+#include <pthread.h>
+#include <sched.h>
+
+
+/* With the 1-on-1 model we implement this function is equivalent to
+ the 'sched_yield' function. */
+int
+pthread_yield (void)
+{
+ return sched_yield ();
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/raise.c b/nptl/sysdeps/unix/sysv/linux/raise.c
new file mode 100644
index 0000000000..009f32ad30
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/raise.c
@@ -0,0 +1,39 @@
+/* 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. */
+
+#include <errno.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <nptl/pthreadP.h>
+
+
+int
+raise (sig)
+ int sig;
+{
+ struct pthread *pd = THREAD_SELF;
+ pid_t selftid = pd->tid;
+ if (selftid == 0)
+ {
+ selftid = INLINE_SYSCALL (gettid, 0);
+ THREAD_SETMEM (pd, tid, selftid);
+ }
+
+ return INLINE_SYSCALL (tkill, 2, selftid, sig);
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/nptl/sysdeps/unix/sysv/linux/register-atfork.c
new file mode 100644
index 0000000000..ef70dde8a2
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/register-atfork.c
@@ -0,0 +1,87 @@
+/* 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. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "fork.h"
+
+
+int
+__register_atfork (prepare, parent, child, dso_handle)
+ void (*prepare) (void);
+ void (*parent) (void);
+ void (*child) (void);
+ void *dso_handle;
+{
+ struct fork_handler *new_prepare = NULL;
+ struct fork_handler *new_parent = NULL;
+ struct fork_handler *new_child = NULL;
+
+ if (prepare != NULL)
+ {
+ new_prepare = (struct fork_handler *) malloc (sizeof (*new_prepare));
+ if (new_prepare == NULL)
+ goto out1;
+
+ new_prepare->handler = prepare;
+ new_prepare->dso_handle = dso_handle;
+ }
+
+ if (parent != NULL)
+ {
+ new_parent = (struct fork_handler *) malloc (sizeof (*new_parent));
+ if (new_parent == NULL)
+ goto out2;
+
+ new_parent->handler = parent;
+ new_parent->dso_handle = dso_handle;
+ }
+
+ if (child != NULL)
+ {
+ new_child = (struct fork_handler *) malloc (sizeof (*new_child));
+ if (new_child == NULL)
+ {
+ free (new_parent);
+ out2:
+ free (new_prepare);
+ out1:
+ return errno;
+ }
+
+ new_child->handler = child;
+ new_child->dso_handle = dso_handle;
+ }
+
+ /* Get the lock to not conflict with running forks. */
+ lll_lock (__fork_lock);
+
+ /* Now that we have all the handlers allocate enqueue them. */
+ if (new_prepare != NULL)
+ list_add_tail (&new_prepare->list, &__fork_prepare_list);
+ if (new_parent != NULL)
+ list_add_tail (&new_parent->list, &__fork_parent_list);
+ if (new_child != NULL)
+ list_add_tail (&new_child->list, &__fork_child_list);
+
+ /* Release the lock. */
+ lll_unlock (__fork_lock);
+
+ return 0;
+}
diff --git a/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
new file mode 100644
index 0000000000..470f80d05c
--- /dev/null
+++ b/nptl/sysdeps/unix/sysv/linux/unregister-atfork.c
@@ -0,0 +1,49 @@
+/* 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. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "fork.h"
+
+
+void
+__unregister_atfork (dso_handle)
+ void *dso_handle;
+{
+ /* Get the lock to not conflict with running forks. */
+ lll_lock (__fork_lock);
+
+ list_t *runp;
+ list_t *prevp;
+
+ list_for_each_prev_safe (runp, prevp, &__fork_prepare_list)
+ if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle)
+ list_del (runp);
+
+ list_for_each_prev_safe (runp, prevp, &__fork_parent_list)
+ if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle)
+ list_del (runp);
+
+ list_for_each_prev_safe (runp, prevp, &__fork_child_list)
+ if (list_entry (runp, struct fork_handler, list)->dso_handle == dso_handle)
+ list_del (runp);
+
+ /* Release the lock. */
+ lll_unlock (__fork_lock);
+}