Browse Source

initial import of latest linuxthreads

Mike Frysinger 18 years ago
parent
commit
cccc549ced
100 changed files with 11256 additions and 0 deletions
  1. 3 0
      libpthread/linuxthreads/.cvsignore
  2. 105 0
      libpthread/linuxthreads/CVS/Entries
  3. 1 0
      libpthread/linuxthreads/CVS/Repository
  4. 1 0
      libpthread/linuxthreads/CVS/Root
  5. 15 0
      libpthread/linuxthreads/Makefile
  6. 124 0
      libpthread/linuxthreads/Makefile.in
  7. 36 0
      libpthread/linuxthreads/alloca_cutoff.c
  8. 467 0
      libpthread/linuxthreads/attr.c
  9. 128 0
      libpthread/linuxthreads/barrier.c
  10. 238 0
      libpthread/linuxthreads/cancel.c
  11. 304 0
      libpthread/linuxthreads/condvar.c
  12. 270 0
      libpthread/linuxthreads/descr.h
  13. 46 0
      libpthread/linuxthreads/errno.c
  14. 37 0
      libpthread/linuxthreads/events.c
  15. 141 0
      libpthread/linuxthreads/forward.c
  16. 551 0
      libpthread/linuxthreads/internals.h
  17. 220 0
      libpthread/linuxthreads/join.c
  18. 64 0
      libpthread/linuxthreads/libc-cancellation.c
  19. 47 0
      libpthread/linuxthreads/libc_pthread_init.c
  20. 52 0
      libpthread/linuxthreads/lockfile.c
  21. 1123 0
      libpthread/linuxthreads/manager.c
  22. 362 0
      libpthread/linuxthreads/mutex.c
  23. 25 0
      libpthread/linuxthreads/pt-machine.c
  24. 75 0
      libpthread/linuxthreads/ptcleanup.c
  25. 69 0
      libpthread/linuxthreads/ptclock_gettime.c
  26. 55 0
      libpthread/linuxthreads/ptclock_settime.c
  27. 93 0
      libpthread/linuxthreads/ptfork.c
  28. 5 0
      libpthread/linuxthreads/pthandles.c
  29. 1379 0
      libpthread/linuxthreads/pthread.c
  30. 57 0
      libpthread/linuxthreads/pthread_atfork.c
  31. 27 0
      libpthread/linuxthreads/pthread_setegid.c
  32. 27 0
      libpthread/linuxthreads/pthread_seteuid.c
  33. 27 0
      libpthread/linuxthreads/pthread_setgid.c
  34. 27 0
      libpthread/linuxthreads/pthread_setregid.c
  35. 27 0
      libpthread/linuxthreads/pthread_setresgid.c
  36. 27 0
      libpthread/linuxthreads/pthread_setresuid.c
  37. 27 0
      libpthread/linuxthreads/pthread_setreuid.c
  38. 27 0
      libpthread/linuxthreads/pthread_setuid.c
  39. 61 0
      libpthread/linuxthreads/queue.h
  40. 49 0
      libpthread/linuxthreads/restart.h
  41. 658 0
      libpthread/linuxthreads/rwlock.c
  42. 298 0
      libpthread/linuxthreads/semaphore.c
  43. 87 0
      libpthread/linuxthreads/semaphore.h
  44. 71 0
      libpthread/linuxthreads/sighandler.c
  45. 215 0
      libpthread/linuxthreads/signals.c
  46. 241 0
      libpthread/linuxthreads/specific.c
  47. 720 0
      libpthread/linuxthreads/spinlock.c
  48. 218 0
      libpthread/linuxthreads/spinlock.h
  49. 14 0
      libpthread/linuxthreads/sysdeps/CVS/Entries
  50. 1 0
      libpthread/linuxthreads/sysdeps/CVS/Repository
  51. 1 0
      libpthread/linuxthreads/sysdeps/CVS/Root
  52. 4 0
      libpthread/linuxthreads/sysdeps/alpha/CVS/Entries
  53. 2 0
      libpthread/linuxthreads/sysdeps/alpha/CVS/Entries.Log
  54. 1 0
      libpthread/linuxthreads/sysdeps/alpha/CVS/Repository
  55. 1 0
      libpthread/linuxthreads/sysdeps/alpha/CVS/Root
  56. 2 0
      libpthread/linuxthreads/sysdeps/alpha/elf/CVS/Entries
  57. 1 0
      libpthread/linuxthreads/sysdeps/alpha/elf/CVS/Repository
  58. 1 0
      libpthread/linuxthreads/sysdeps/alpha/elf/CVS/Root
  59. 90 0
      libpthread/linuxthreads/sysdeps/alpha/elf/pt-initfini.c
  60. 110 0
      libpthread/linuxthreads/sysdeps/alpha/pspinlock.c
  61. 128 0
      libpthread/linuxthreads/sysdeps/alpha/pt-machine.h
  62. 134 0
      libpthread/linuxthreads/sysdeps/alpha/tls.h
  63. 4 0
      libpthread/linuxthreads/sysdeps/arm/CVS/Entries
  64. 1 0
      libpthread/linuxthreads/sysdeps/arm/CVS/Repository
  65. 1 0
      libpthread/linuxthreads/sysdeps/arm/CVS/Root
  66. 82 0
      libpthread/linuxthreads/sysdeps/arm/pspinlock.c
  67. 55 0
      libpthread/linuxthreads/sysdeps/arm/pt-machine.h
  68. 172 0
      libpthread/linuxthreads/sysdeps/arm/tls.h
  69. 3 0
      libpthread/linuxthreads/sysdeps/cris/CVS/Entries
  70. 1 0
      libpthread/linuxthreads/sysdeps/cris/CVS/Repository
  71. 1 0
      libpthread/linuxthreads/sysdeps/cris/CVS/Root
  72. 72 0
      libpthread/linuxthreads/sysdeps/cris/pspinlock.c
  73. 58 0
      libpthread/linuxthreads/sysdeps/cris/pt-machine.h
  74. 3 0
      libpthread/linuxthreads/sysdeps/hppa/CVS/Entries
  75. 1 0
      libpthread/linuxthreads/sysdeps/hppa/CVS/Repository
  76. 1 0
      libpthread/linuxthreads/sysdeps/hppa/CVS/Root
  77. 81 0
      libpthread/linuxthreads/sysdeps/hppa/pspinlock.c
  78. 62 0
      libpthread/linuxthreads/sysdeps/hppa/pt-machine.h
  79. 8 0
      libpthread/linuxthreads/sysdeps/i386/CVS/Entries
  80. 1 0
      libpthread/linuxthreads/sysdeps/i386/CVS/Repository
  81. 1 0
      libpthread/linuxthreads/sysdeps/i386/CVS/Root
  82. 2 0
      libpthread/linuxthreads/sysdeps/i386/i586/CVS/Entries
  83. 1 0
      libpthread/linuxthreads/sysdeps/i386/i586/CVS/Repository
  84. 1 0
      libpthread/linuxthreads/sysdeps/i386/i586/CVS/Root
  85. 3 0
      libpthread/linuxthreads/sysdeps/i386/i686/CVS/Entries
  86. 1 0
      libpthread/linuxthreads/sysdeps/i386/i686/CVS/Repository
  87. 1 0
      libpthread/linuxthreads/sysdeps/i386/i686/CVS/Root
  88. 79 0
      libpthread/linuxthreads/sysdeps/i386/i686/pt-machine.h
  89. 103 0
      libpthread/linuxthreads/sysdeps/i386/pspinlock.c
  90. 115 0
      libpthread/linuxthreads/sysdeps/i386/pt-machine.h
  91. 7 0
      libpthread/linuxthreads/sysdeps/i386/tcb-offsets.sym
  92. 229 0
      libpthread/linuxthreads/sysdeps/i386/tls.h
  93. 314 0
      libpthread/linuxthreads/sysdeps/i386/useldt.h
  94. 7 0
      libpthread/linuxthreads/sysdeps/ia64/CVS/Entries
  95. 1 0
      libpthread/linuxthreads/sysdeps/ia64/CVS/Repository
  96. 1 0
      libpthread/linuxthreads/sysdeps/ia64/CVS/Root
  97. 79 0
      libpthread/linuxthreads/sysdeps/ia64/pspinlock.c
  98. 133 0
      libpthread/linuxthreads/sysdeps/ia64/pt-machine.h
  99. 9 0
      libpthread/linuxthreads/sysdeps/ia64/tcb-offsets.sym
  100. 145 0
      libpthread/linuxthreads/sysdeps/ia64/tls.h

+ 3 - 0
libpthread/linuxthreads/.cvsignore

@@ -0,0 +1,3 @@
+.cvsignore
+*.os
+Makefile.in

+ 105 - 0
libpthread/linuxthreads/CVS/Entries

@@ -0,0 +1,105 @@
+/internals.h/1.94/Sun Dec 12 21:05:54 2004//
+/lockfile.c/1.10/Wed Dec 18 01:16:46 2002//
+/pthread.c/1.136/Sun Jan  9 20:02:37 2005//
+D/Examples////
+D/man////
+D/sysdeps////
+/Makefile/1.99/Mon Nov  7 16:58:12 2005//
+/descr.h/1.16/Mon Nov 14 19:51:28 2005//
+/Banner/1.4/Tue Nov 15 14:20:47 2005//
+/Changes/1.2/Tue Nov 15 14:20:47 2005//
+/FAQ.html/1.3/Tue Nov 15 14:20:48 2005//
+/LICENSE/1.1/Tue Nov 15 14:20:47 2005//
+/README/1.2/Tue Nov 15 14:20:48 2005//
+/README.Xfree3.2/1.1/Tue Nov 15 14:20:48 2005//
+/Versions/1.49/Tue Nov 15 14:20:47 2005//
+/attr.c/1.36/Tue Nov 15 14:20:47 2005//
+/barrier.c/1.4/Tue Nov 15 14:20:48 2005//
+/bug-sleep.c/-1.1/Tue Nov 15 14:20:47 2005//
+/cancel.c/1.23/Tue Nov 15 14:20:47 2005//
+/condvar.c/1.32/Tue Nov 15 14:20:47 2005//
+/configure/1.3/Tue Nov 15 14:20:47 2005//
+/configure.in/1.1/Tue Nov 15 14:20:48 2005//
+/ecmutex.c/-1.3/Tue Nov 15 16:18:58 2005//
+/errno.c/1.7/Tue Nov 15 14:20:48 2005//
+/events.c/1.3/Tue Nov 15 14:20:48 2005//
+/join.c/1.20/Tue Nov 15 14:20:47 2005//
+/joinrace.c/-1.2/Tue Nov 15 14:20:48 2005//
+/libc-tls-loc.c/-1.2/Tue Nov 15 14:20:48 2005//
+/libc-tsd.c/-1.2/Tue Nov 15 14:20:47 2005//
+/libc_pthread_init.c/1.3/Tue Nov 15 16:03:12 2005//
+/linuxthreads.texi/1.15/Tue Nov 15 14:20:48 2005//
+/manager.c/1.98/Tue Nov 15 16:02:59 2005//
+/mutex.c/1.27/Tue Nov 15 14:20:48 2005//
+/old_pthread_atfork.c/-1.1/Tue Nov 15 14:20:47 2005//
+/oldsemaphore.c/-1.12/Tue Nov 15 14:20:48 2005//
+/pt-machine.c/1.3/Tue Nov 15 14:20:47 2005//
+/pt-system.c/-1.3/Tue Nov 15 16:18:58 2005//
+/ptclock_gettime.c/1.3/Tue Nov 15 14:20:48 2005//
+/ptclock_settime.c/1.3/Tue Nov 15 14:20:47 2005//
+/pthandles.c/1.1/Tue Nov 15 14:20:47 2005//
+/pthread_atfork.c/1.2/Tue Nov 15 14:20:47 2005//
+/pthread_setegid.c/1.1/Tue Nov 15 14:20:47 2005//
+/pthread_seteuid.c/1.1/Tue Nov 15 14:20:47 2005//
+/pthread_setgid.c/1.1/Tue Nov 15 14:20:48 2005//
+/pthread_setregid.c/1.1/Tue Nov 15 14:20:47 2005//
+/pthread_setresgid.c/1.1/Tue Nov 15 14:20:48 2005//
+/pthread_setresuid.c/1.1/Tue Nov 15 14:20:48 2005//
+/pthread_setreuid.c/1.1/Tue Nov 15 14:20:47 2005//
+/pthread_setuid.c/1.1/Tue Nov 15 14:20:48 2005//
+/queue.h/1.4/Tue Nov 15 14:20:47 2005//
+/restart.h/1.6/Tue Nov 15 14:20:47 2005//
+/rwlock.c/1.20/Tue Nov 15 14:20:48 2005//
+/semaphore.c/1.20/Tue Nov 15 14:20:47 2005//
+/semaphore.h/1.13/Tue Nov 15 14:20:48 2005//
+/shlib-versions/1.10/Tue Nov 15 14:20:47 2005//
+/sighandler.c/1.2/Tue Nov 15 14:20:47 2005//
+/signals.c/1.29/Tue Nov 15 14:20:47 2005//
+/spinlock.c/1.38/Tue Nov 15 14:20:47 2005//
+/spinlock.h/1.24/Tue Nov 15 14:20:48 2005//
+/tst-_res1.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-_res1mod1.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-_res1mod2.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-align.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-attr1.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel-static.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel-wrappers.sh/-1.8/Tue Nov 15 16:18:58 2005//
+/tst-cancel.c/-1.9/Tue Nov 15 16:18:58 2005//
+/tst-cancel1.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel2.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel3.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel4.c/-1.3/Tue Nov 15 16:18:58 2005//
+/tst-cancel5.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel6.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel7.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-cancel8.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-clock1.c/-1.2/Tue Nov 15 16:18:58 2005//
+/tst-context.c/-1.6/Tue Nov 15 16:18:58 2005//
+/tst-popen.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-popen2.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-signal.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-signal.sh/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-stack1.c/-1.2/Tue Nov 15 16:18:58 2005//
+/tst-static-locale.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1.h/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1mod.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1moda.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1modb.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1modc.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1modd.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1mode.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls1modf.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tls2.sh/-1.1/Tue Nov 15 16:18:58 2005//
+/tst-tsd1.c/-1.1/Tue Nov 15 16:18:58 2005//
+/tststack.c/-1.4/Tue Nov 15 16:18:58 2005//
+/unload.c/-1.3/dummy timestamp//
+/pt-allocrtsig.c/-1.1/Tue Nov 15 19:09:25 2005//
+/ptfork.c/1.11/Tue Nov 15 18:19:48 2005//
+/forward.c/1.6/Tue Sep 23 04:31:36 2003//
+/specific.c/1.21/Thu Dec 29 06:16:36 2005//
+/ChangeLog/1.861/Fri Jan 20 14:26:17 2006//
+/ptcleanup.c/1.3/Fri Jan 20 14:54:46 2006//
+/libc-cancellation.c/1.6/Fri Jan 20 15:05:11 2006//
+/alloca_cutoff.c/1.2/Tue Apr  1 00:52:40 2003//
+/Makeconfig/1.3/Tue Jan 31 04:59:21 2006//

+ 1 - 0
libpthread/linuxthreads/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads

+ 1 - 0
libpthread/linuxthreads/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 15 - 0
libpthread/linuxthreads/Makefile

@@ -0,0 +1,15 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+TOPDIR=../../
+
+top_srcdir=$(TOPDIR)
+top_builddir=../../
+include $(top_builddir)Rules.mak
+all: libs
+include Makefile.in
+include $(top_srcdir)Makerules

+ 124 - 0
libpthread/linuxthreads/Makefile.in

@@ -0,0 +1,124 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
+# Copyright (C) 2000-2005 Erik Andersen <andersen@uclibc.org>
+#
+# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+#
+
+CFLAGS-linuxthreads := -DNOT_IN_libc $(SSP_ALL_CFLAGS)
+CFLAGS-linuxthreads += -DIS_IN_linuxthreads=1 -D_GNU_SOURCE
+
+CFLAGS-libpthread/linuxthreads/sysdeps/$(TARGET_ARCH)/ := $(CFLAGS-linuxthreads)
+CFLAGS-libpthread/linuxthreads/sysdeps/unix/sysv/linux/ := $(CFLAGS-linuxthreads)
+CFLAGS-libpthread/linuxthreads/sysdeps/pthread/         := $(CFLAGS-linuxthreads)
+
+# This stuff will not compile without at least -O1
+# psm: can't handle this here, could maybe search for -O0 in CFLAGS
+# and append -O1 if found
+#CFLAGS:=$(CFLAGS:-O0=-O1)
+
+ifeq ($(PTHREADS_DEBUG_SUPPORT),y)
+LDFLAGS-libpthread.so := $(LDFLAGS_NOSTRIP) -z defs
+else
+LDFLAGS-libpthread.so := $(LDFLAGS)
+endif
+
+LIBS-libpthread.so := $(LIBS) $(ldso)
+
+START_FILE-libpthread.so := $(SHARED_START_FILES)
+END_FILE-libpthread.so := $(SHARED_END_FILES)
+
+libpthread_FULL_NAME := libpthread-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so
+
+libpthread_DIR := $(top_srcdir)libpthread/linuxthreads
+libpthread_OUT := $(top_builddir)libpthread/linuxthreads
+
+-include $(libpthread_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch
+
+pthread_arch_SRC   := pspinlock
+pthread_arch_SRC   := $(patsubst %,$(libpthread_DIR)/sysdeps/$(TARGET_ARCH)/%.c,$(pthread_arch_SRC))
+pthread_linux_SRC  := fork pt-sigsuspend register-atfork unregister-atfork
+pthread_linux_SRC  := $(patsubst %,$(libpthread_DIR)/sysdeps/unix/sysv/linux/%.c,$(pthread_linux_SRC))
+pthread_sysdep_SRC := errno-loc herrno-loc ptlongjmp
+pthread_sysdep_SRC := $(patsubst %,$(libpthread_DIR)/sysdeps/pthread/%.c,$(pthread_sysdep_SRC))
+pthread_SRC := \
+	attr barrier cancel condvar errno events join pthread \
+	lockfile manager mutex pt-machine ptcleanup \
+	ptclock_gettime ptclock_settime ptfork pthandles pthread_atfork \
+	pthread_setegid pthread_seteuid pthread_setgid pthread_setregid \
+	pthread_setresgid pthread_setresuid pthread_setreuid pthread_setuid \
+	rwlock semaphore sighandler signals specific spinlock
+pthread_SRC := $(patsubst %,$(libpthread_DIR)/%.c,$(pthread_SRC))
+
+libpthread_static_SRC := pt-allocrtsig
+libpthread_shared_SRC := pthread_atfork
+libpthread_SRC := $(pthread_arch_SRC) $(pthread_linux_SRC) $(pthread_sysdep_SRC) $(pthread_SRC)
+libpthread_OBJ := $(patsubst $(libpthread_DIR)/%.c,$(libpthread_OUT)/%.o,$(libpthread_SRC))
+
+#
+# Stuff that goes into libc.so, not libpthread.so
+#
+#CFLAGS-alloca_cutoff.c := -DIS_IN_libc
+CFLAGS-forward.c := -DIS_IN_libc
+CFLAGS-libc-cancellation.c := -DIS_IN_libc
+CFLAGS-libc_pthread_init.c := -DIS_IN_libc
+libpthread_libc_CSRC := \
+	forward.c libc-cancellation.c libc_pthread_init.c # alloca_cutoff.c
+libpthread_libc_OBJ  := $(patsubst %.c, $(libpthread_OUT)/%.o,$(libpthread_libc_CSRC))
+libc-static-y += $(libpthread_OUT)/libc_pthread_init.o
+libc-shared-y += $(libpthread_libc_OBJ:.o=.oS)
+
+libpthread-static-y += $(patsubst %.c,$(libpthread_OUT)/%.o,$(libpthread_SPEC_SRC))
+libpthread-shared-y += $(patsubst %.c,$(libpthread_OUT)/%.oS,$(libpthread_SPEC_SRC))
+
+ifeq ($(DOPIC),y)
+libpthread-a-y  += $(libpthread_OBJ:.o=.os) $(libpthread-static-y:.o=.os)
+else
+libpthread-a-y  += $(libpthread_OBJ) $(libpthread-static-y)
+endif
+libpthread-so-y += $(libpthread_OBJ:.o=.os) $(libpthread-shared-y)
+
+libpthread-multi-y += $(libpthread_SRC)
+libpthread-nomulti-y += $(patsubst %.c,$(libpthread_OUT)/%.o,$(libpthread_NO_MULTI))
+
+lib-a-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.a
+lib-so-$(UCLIBC_HAS_THREADS) += $(top_builddir)lib/libpthread.so
+objclean-y += libpthread_clean
+headers-$(UCLIBC_HAS_THREADS) += linuxthreads_headers
+headers_clean-y += linuxthreads_headers_clean
+
+$(top_builddir)lib/libpthread.so: $(libpthread_OUT)/libpthread_so.a $(libc)
+	$(call link.so,$(libpthread_FULL_NAME),$(MAJOR_VERSION))
+
+$(libpthread_OUT)/libpthread_so.a: $(libpthread-so-y)
+	$(Q)$(RM) $@
+ifeq ($(PTHREADS_DEBUG_SUPPORT),y)
+	$(do_strip:-x=-X --strip-debug)
+else
+	$(do_strip)
+endif
+	$(do_ar)
+
+$(top_builddir)lib/libpthread.a: $(libpthread-a-y)
+	$(Q)$(INSTALL) -d $(dir $@)
+	$(Q)$(RM) $@
+ifeq ($(PTHREADS_DEBUG_SUPPORT),y)
+	$(do_strip:-x=-X --strip-debug)
+else
+	$(do_strip)
+endif
+	$(do_ar)
+
+linuxthreads_headers:
+	$(LN) -sf ../$(PTDIR)/sysdeps/pthread/pthread.h $(top_builddir)include/
+	$(LN) -sf ../$(PTDIR)/semaphore.h $(top_builddir)include/
+	$(INSTALL) -d $(top_builddir)include/bits
+	$(LN) -sf ../../$(PTDIR)/sysdeps/pthread/bits/pthreadtypes.h $(top_builddir)include/bits/
+
+linuxthreads_headers_clean:
+	$(RM) $(top_builddir)include/pthread.h $(top_builddir)include/semaphore.h \
+		$(top_builddir)include/bits/pthreadtypes.h
+
+libpthread_clean:
+	$(RM) $(libpthread_OUT)/{,*/,*/*/,*/*/*/,*/*/*/*/}*.{o,os,a}

+ 36 - 0
libpthread/linuxthreads/alloca_cutoff.c

@@ -0,0 +1,36 @@
+/* Determine whether block of given size can be allocated on the stack or not.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; 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 <stdlib.h>
+#include <sys/param.h>
+#include "internals.h"
+#include <sysdep-cancel.h>
+
+int
+__libc_alloca_cutoff (size_t size)
+{
+  if (! SINGLE_THREAD_P)
+    {
+      pthread_descr self = thread_self ();
+      return size <= LIBC_THREAD_GETMEM (self, p_alloca_cutoff);
+    }
+
+  return size <= __MAX_ALLOCA_CUTOFF;
+}

+ 467 - 0
libpthread/linuxthreads/attr.c

@@ -0,0 +1,467 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Handling of thread attributes */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include "pthread.h"
+#include "internals.h"
+
+
+int __pthread_attr_init(pthread_attr_t *attr)
+{
+  size_t ps = __getpagesize ();
+
+  attr->__detachstate = PTHREAD_CREATE_JOINABLE;
+  attr->__schedpolicy = SCHED_OTHER;
+  attr->__schedparam.sched_priority = 0;
+  attr->__inheritsched = PTHREAD_EXPLICIT_SCHED;
+  attr->__scope = PTHREAD_SCOPE_SYSTEM;
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  attr->__guardsize = ps + ps;
+#else
+  attr->__guardsize = ps;
+#endif
+  attr->__stackaddr = NULL;
+  attr->__stackaddr_set = 0;
+  attr->__stacksize = STACK_SIZE - ps;
+  return 0;
+}
+strong_alias (__pthread_attr_init, pthread_attr_init)
+
+int __pthread_attr_destroy(pthread_attr_t *attr)
+{
+  return 0;
+}
+strong_alias (__pthread_attr_destroy, pthread_attr_destroy);
+
+int __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+  if (detachstate < PTHREAD_CREATE_JOINABLE ||
+      detachstate > PTHREAD_CREATE_DETACHED)
+    return EINVAL;
+  attr->__detachstate = detachstate;
+  return 0;
+}
+strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate);
+
+int __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+  *detachstate = attr->__detachstate;
+  return 0;
+}
+strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate);
+
+int __pthread_attr_setschedparam(pthread_attr_t *attr,
+                                 const struct sched_param *param)
+{
+  int max_prio = __sched_get_priority_max(attr->__schedpolicy);
+  int min_prio = __sched_get_priority_min(attr->__schedpolicy);
+
+  if (param->sched_priority < min_prio || param->sched_priority > max_prio)
+    return EINVAL;
+  memcpy (&attr->__schedparam, param, sizeof (struct sched_param));
+  return 0;
+}
+strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam);
+
+int __pthread_attr_getschedparam(const pthread_attr_t *attr,
+                                 struct sched_param *param)
+{
+  memcpy (param, &attr->__schedparam, sizeof (struct sched_param));
+  return 0;
+}
+strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam);
+
+int __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+  if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
+    return EINVAL;
+  attr->__schedpolicy = policy;
+  return 0;
+}
+strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy);
+
+int __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+  *policy = attr->__schedpolicy;
+  return 0;
+}
+strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy);
+
+int __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit)
+{
+  if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
+    return EINVAL;
+  attr->__inheritsched = inherit;
+  return 0;
+}
+strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched);
+
+int __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit)
+{
+  *inherit = attr->__inheritsched;
+  return 0;
+}
+strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched);
+
+int __pthread_attr_setscope(pthread_attr_t *attr, int scope)
+{
+  switch (scope) {
+  case PTHREAD_SCOPE_SYSTEM:
+    attr->__scope = scope;
+    return 0;
+  case PTHREAD_SCOPE_PROCESS:
+    return ENOTSUP;
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_attr_setscope, pthread_attr_setscope);
+
+int __pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
+{
+  *scope = attr->__scope;
+  return 0;
+}
+strong_alias (__pthread_attr_getscope, pthread_attr_getscope);
+
+int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+  /* The guard size must not be larger than the stack itself */
+  if (guardsize >= attr->__stacksize) return EINVAL;
+
+  attr->__guardsize = guardsize;
+
+  return 0;
+}
+weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize)
+
+int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+  *guardsize = attr->__guardsize;
+  return 0;
+}
+weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize)
+
+int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+  attr->__stackaddr = stackaddr;
+  attr->__stackaddr_set = 1;
+  return 0;
+}
+weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
+
+link_warning (pthread_attr_setstackaddr,
+	      "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
+
+int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+  /* XXX This function has a stupid definition.  The standard specifies
+     no error value but what is if no stack address was set?  We simply
+     return the value we have in the member.  */
+  *stackaddr = attr->__stackaddr;
+  return 0;
+}
+weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
+
+link_warning (pthread_attr_getstackaddr,
+	      "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
+
+
+int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+#ifdef FLOATING_STACKS
+  /* We have to check against the maximum allowed stack size.  This is no
+     problem if the manager is already started and we determined it.  If
+     this hasn't happened, we have to find the limit outself.  */
+  if (__pthread_max_stacksize == 0)
+    __pthread_init_max_stacksize ();
+
+  if (stacksize > __pthread_max_stacksize)
+    return EINVAL;
+#else
+  /* We have a fixed size limit.  */
+  if (stacksize > STACK_SIZE)
+    return EINVAL;
+#endif
+
+  /* We don't accept value smaller than PTHREAD_STACK_MIN.  */
+  if (stacksize < PTHREAD_STACK_MIN)
+    return EINVAL;
+
+  attr->__stacksize = stacksize;
+  return 0;
+}
+
+#if PTHREAD_STACK_MIN == 16384
+weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
+#else
+versioned_symbol (libpthread, __pthread_attr_setstacksize,
+                  pthread_attr_setstacksize, GLIBC_2_3_3);
+
+# if SHLIB_COMPAT(libpthread, GLIBC_2_1, GLIBC_2_3_3)
+
+int __old_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+#  ifdef FLOATING_STACKS
+  /* We have to check against the maximum allowed stack size.  This is no
+     problem if the manager is already started and we determined it.  If
+     this hasn't happened, we have to find the limit outself.  */
+  if (__pthread_max_stacksize == 0)
+    __pthread_init_max_stacksize ();
+
+  if (stacksize > __pthread_max_stacksize)
+    return EINVAL;
+#  else
+  /* We have a fixed size limit.  */
+  if (stacksize > STACK_SIZE)
+    return EINVAL;
+#  endif
+
+  /* We don't accept value smaller than old PTHREAD_STACK_MIN.  */
+  if (stacksize < 16384)
+    return EINVAL;
+
+  attr->__stacksize = stacksize;
+  return 0;
+}
+compat_symbol (libpthread, __old_pthread_attr_setstacksize,
+	       pthread_attr_setstacksize, GLIBC_2_1);
+# endif
+#endif
+
+
+int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+  *stacksize = attr->__stacksize;
+  return 0;
+}
+weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
+
+int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
+			     size_t stacksize)
+{
+  int err;
+
+  if ((((uintptr_t) stackaddr)
+       & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
+    err = EINVAL;
+  else
+    err = __pthread_attr_setstacksize (attr, stacksize);
+  if (err == 0)
+    {
+#ifndef _STACK_GROWS_UP
+      attr->__stackaddr = (char *) stackaddr + stacksize;
+#else
+      attr->__stackaddr = stackaddr;
+#endif
+      attr->__stackaddr_set = 1;
+    }
+
+  return err;
+}
+
+#if PTHREAD_STACK_MIN == 16384
+weak_alias (__pthread_attr_setstack, pthread_attr_setstack)
+#else
+versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack,
+                  GLIBC_2_3_3);
+# if SHLIB_COMPAT(libpthread, GLIBC_2_2, GLIBC_2_3_3)
+int __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
+				 size_t stacksize)
+{
+  int err;
+
+  if ((((uintptr_t) stackaddr)
+       & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0)
+    err = EINVAL;
+  else
+    err = __old_pthread_attr_setstacksize (attr, stacksize);
+  if (err == 0)
+    {
+#  ifndef _STACK_GROWS_UP
+      attr->__stackaddr = (char *) stackaddr + stacksize;
+#  else
+      attr->__stackaddr = stackaddr;
+#  endif
+      attr->__stackaddr_set = 1;
+    }
+
+  return err;
+}
+
+compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack,
+               GLIBC_2_2);
+
+# endif
+#endif
+
+int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr,
+			     size_t *stacksize)
+{
+  /* XXX This function has a stupid definition.  The standard specifies
+     no error value but what is if no stack address was set?  We simply
+     return the value we have in the member.  */
+#ifndef _STACK_GROWS_UP
+  *stackaddr = (char *) attr->__stackaddr - attr->__stacksize;
+#else
+  *stackaddr = attr->__stackaddr;
+#endif
+  *stacksize = attr->__stacksize;
+  return 0;
+}
+weak_alias (__pthread_attr_getstack, pthread_attr_getstack)
+
+int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
+{
+  pthread_handle handle = thread_handle (thread);
+  pthread_descr descr;
+  int ret = 0;
+
+  if (handle == NULL)
+    return ENOENT;
+
+  descr = handle->h_descr;
+
+  attr->__detachstate = (descr->p_detached
+			 ? PTHREAD_CREATE_DETACHED
+			 : PTHREAD_CREATE_JOINABLE);
+
+  attr->__schedpolicy = __sched_getscheduler (descr->p_pid);
+  if (attr->__schedpolicy == -1)
+    return errno;
+
+  if (__sched_getparam (descr->p_pid,
+			(struct sched_param *) &attr->__schedparam) != 0)
+    return errno;
+
+  attr->__inheritsched = descr->p_inheritsched;
+  attr->__scope = PTHREAD_SCOPE_SYSTEM;
+
+#ifdef _STACK_GROWS_DOWN
+# ifdef USE_TLS
+  attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr
+		      - descr->p_guardsize;
+# else
+  attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr
+		      - descr->p_guardsize;
+# endif
+#else
+# ifdef USE_TLS
+  attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr;
+# else
+  attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr;
+# endif
+#endif
+  attr->__guardsize = descr->p_guardsize;
+  attr->__stackaddr_set = descr->p_userstack;
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  if (descr->p_userstack == 0)
+    attr->__stacksize *= 2;
+  /* XXX This is awkward.  The guard pages are in the middle of the
+     two stacks.  We must count the guard size in the stack size since
+     otherwise the range of the stack area cannot be computed.  */
+  attr->__stacksize += attr->__guardsize;
+#endif
+#ifdef USE_TLS
+  attr->__stackaddr = descr->p_stackaddr;
+#else
+# ifndef _STACK_GROWS_UP
+  attr->__stackaddr = (char *)(descr + 1);
+# else
+  attr->__stackaddr = (char *)descr;
+# endif
+#endif
+
+#ifdef USE_TLS
+  if (attr->__stackaddr == NULL)
+#else
+  if (descr == &__pthread_initial_thread)
+#endif
+    {
+      /* Stack size limit.  */
+      struct rlimit rl;
+
+      /* The safest way to get the top of the stack is to read
+	 /proc/self/maps and locate the line into which
+	 __libc_stack_end falls.  */
+      FILE *fp = fopen ("/proc/self/maps", "rc");
+      if (fp == NULL)
+	ret = errno;
+      /* We need the limit of the stack in any case.  */
+      else if (getrlimit (RLIMIT_STACK, &rl) != 0)
+	ret = errno;
+      else
+	{
+	  /* We need no locking.  */
+	  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+	  /* Until we found an entry (which should always be the case)
+	     mark the result as a failure.  */
+	  ret = ENOENT;
+
+	  char *line = NULL;
+	  size_t linelen = 0;
+	  uintptr_t last_to = 0;
+
+	  while (! feof_unlocked (fp))
+	    {
+	      if (getdelim (&line, &linelen, '\n', fp) <= 0)
+		break;
+
+	      uintptr_t from;
+	      uintptr_t to;
+	      if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
+		continue;
+	      if (from <= (uintptr_t) __libc_stack_end
+		  && (uintptr_t) __libc_stack_end < to)
+		{
+		  /* Found the entry.  Now we have the info we need.  */
+		  attr->__stacksize = rl.rlim_cur;
+#ifdef _STACK_GROWS_UP
+		  /* Don't check to enforce a limit on the __stacksize */
+		  attr->__stackaddr = (void *) from;
+#else
+		  attr->__stackaddr = (void *) to;
+
+		  /* The limit might be too high.  */
+		  if ((size_t) attr->__stacksize
+		      > (size_t) attr->__stackaddr - last_to)
+		    attr->__stacksize = (size_t) attr->__stackaddr - last_to;
+#endif
+
+		  /* We succeed and no need to look further.  */
+		  ret = 0;
+		  break;
+		}
+	      last_to = to;
+	    }
+
+	  fclose (fp);
+	  free (line);
+	}
+    }
+
+  return 0;
+
+}

+ 128 - 0
libpthread/linuxthreads/barrier.c

@@ -0,0 +1,128 @@
+/* POSIX barrier implementation for LinuxThreads.
+   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Kaz Kylheku <kaz@ashi.footprints.net>, 2000.
+
+   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 "internals.h"
+#include "spinlock.h"
+#include "queue.h"
+#include "restart.h"
+
+int
+pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+  pthread_descr self = thread_self();
+  pthread_descr temp_wake_queue, th;
+  int result = 0;
+
+  __pthread_lock(&barrier->__ba_lock, self);
+
+  /* If the required number of threads have achieved rendezvous... */
+  if (barrier->__ba_present >= barrier->__ba_required - 1)
+    {
+      /* ... then this last caller shall be the serial thread */
+      result = PTHREAD_BARRIER_SERIAL_THREAD;
+      /* Copy and clear wait queue and reset barrier. */
+      temp_wake_queue = barrier->__ba_waiting;
+      barrier->__ba_waiting = NULL;
+      barrier->__ba_present = 0;
+    }
+  else
+    {
+      result = 0;
+      barrier->__ba_present++;
+      enqueue(&barrier->__ba_waiting, self);
+    }
+
+  __pthread_unlock(&barrier->__ba_lock);
+
+  if (result == 0)
+    {
+      /* Non-serial threads have to suspend */
+      suspend(self);
+      /* We don't bother dealing with cancellation because the POSIX
+         spec for barriers doesn't mention that pthread_barrier_wait
+         is a cancellation point. */
+    }
+  else
+    {
+      /* Serial thread wakes up all others. */
+      while ((th = dequeue(&temp_wake_queue)) != NULL)
+	restart(th);
+    }
+
+  return result;
+}
+
+int
+pthread_barrier_init(pthread_barrier_t *barrier,
+				const pthread_barrierattr_t *attr,
+				unsigned int count)
+{
+  if (count == 0)
+     return EINVAL;
+
+  __pthread_init_lock(&barrier->__ba_lock);
+  barrier->__ba_required = count;
+  barrier->__ba_present = 0;
+  barrier->__ba_waiting = NULL;
+  return 0;
+}
+
+int
+pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+  if (barrier->__ba_waiting != NULL) return EBUSY;
+  return 0;
+}
+
+int
+pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+  attr->__pshared = PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int
+pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+  return 0;
+}
+
+int
+__pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+				 int *pshared)
+{
+  *pshared = PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int
+pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+  if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
+    return EINVAL;
+
+  /* For now it is not possible to shared a conditional variable.  */
+  if (pshared != PTHREAD_PROCESS_PRIVATE)
+    return ENOSYS;
+
+  return 0;
+}

+ 238 - 0
libpthread/linuxthreads/cancel.c

@@ -0,0 +1,238 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Thread cancellation */
+
+#include <errno.h>
+#include <libc-internal.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+
+#ifdef _STACK_GROWS_DOWN
+# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
+#elif _STACK_GROWS_UP
+# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
+
+int __pthread_setcancelstate(int state, int * oldstate)
+{
+  pthread_descr self = thread_self();
+  if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
+    return EINVAL;
+  if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate);
+  THREAD_SETMEM(self, p_cancelstate, state);
+  if (THREAD_GETMEM(self, p_canceled) &&
+      THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
+      THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  return 0;
+}
+strong_alias (__pthread_setcancelstate, pthread_setcancelstate);
+
+int __pthread_setcanceltype(int type, int * oldtype)
+{
+  pthread_descr self = thread_self();
+  if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
+    return EINVAL;
+  if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype);
+  THREAD_SETMEM(self, p_canceltype, type);
+  if (THREAD_GETMEM(self, p_canceled) &&
+      THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
+      THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  return 0;
+}
+strong_alias (__pthread_setcanceltype, pthread_setcanceltype);
+
+
+/* The next two functions are similar to pthread_setcanceltype() but
+   more specialized for the use in the cancelable functions like write().
+   They do not need to check parameters etc.  */
+int
+attribute_hidden
+__pthread_enable_asynccancel (void)
+{
+  pthread_descr self = thread_self();
+  int oldtype = THREAD_GETMEM(self, p_canceltype);
+  THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
+  if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) &&
+      THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  return oldtype;
+}
+
+void
+internal_function attribute_hidden
+__pthread_disable_asynccancel (int oldtype)
+{
+  pthread_descr self = thread_self();
+  THREAD_SETMEM(self, p_canceltype, oldtype);
+}
+
+
+int pthread_cancel(pthread_t thread)
+{
+  pthread_handle handle = thread_handle(thread);
+  int pid;
+  int dorestart = 0;
+  pthread_descr th;
+  pthread_extricate_if *pextricate;
+  int already_canceled;
+
+  __pthread_lock(&handle->h_lock, NULL);
+  if (invalid_handle(handle, thread)) {
+    __pthread_unlock(&handle->h_lock);
+    return ESRCH;
+  }
+
+  th = handle->h_descr;
+
+  already_canceled = th->p_canceled;
+  th->p_canceled = 1;
+
+  if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
+    __pthread_unlock(&handle->h_lock);
+    return 0;
+  }
+
+  pextricate = th->p_extricate;
+  pid = th->p_pid;
+
+  /* If the thread has registered an extrication interface, then
+     invoke the interface. If it returns 1, then we succeeded in
+     dequeuing the thread from whatever waiting object it was enqueued
+     with. In that case, it is our responsibility to wake it up.
+     And also to set the p_woken_by_cancel flag so the woken thread
+     can tell that it was woken by cancellation. */
+
+  if (pextricate != NULL) {
+    dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th);
+    th->p_woken_by_cancel = dorestart;
+  }
+
+  __pthread_unlock(&handle->h_lock);
+
+  /* If the thread has suspended or is about to, then we unblock it by
+     issuing a restart, instead of a cancel signal. Otherwise we send
+     the cancel signal to unblock the thread from a cancellation point,
+     or to initiate asynchronous cancellation. The restart is needed so
+     we have proper accounting of restarts; suspend decrements the thread's
+     resume count, and restart() increments it.  This also means that suspend's
+     handling of the cancel signal is obsolete. */
+
+  if (dorestart)
+    restart(th);
+  else
+    kill(pid, __pthread_sig_cancel);
+
+  return 0;
+}
+
+void pthread_testcancel(void)
+{
+  pthread_descr self = thread_self();
+  if (THREAD_GETMEM(self, p_canceled)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+}
+
+void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer,
+			   void (*routine)(void *), void * arg)
+{
+  pthread_descr self = thread_self();
+  buffer->__routine = routine;
+  buffer->__arg = arg;
+  buffer->__prev = THREAD_GETMEM(self, p_cleanup);
+  if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+    buffer->__prev = NULL;
+  THREAD_SETMEM(self, p_cleanup, buffer);
+}
+
+void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer,
+			  int execute)
+{
+  pthread_descr self = thread_self();
+  if (execute) buffer->__routine(buffer->__arg);
+  THREAD_SETMEM(self, p_cleanup, buffer->__prev);
+}
+
+void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer,
+				 void (*routine)(void *), void * arg)
+{
+  pthread_descr self = thread_self();
+  buffer->__routine = routine;
+  buffer->__arg = arg;
+  buffer->__canceltype = THREAD_GETMEM(self, p_canceltype);
+  buffer->__prev = THREAD_GETMEM(self, p_cleanup);
+  if (buffer->__prev != NULL && FRAME_LEFT (buffer, buffer->__prev))
+    buffer->__prev = NULL;
+  THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED);
+  THREAD_SETMEM(self, p_cleanup, buffer);
+}
+
+void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer,
+				  int execute)
+{
+  pthread_descr self = thread_self();
+  if (execute) buffer->__routine(buffer->__arg);
+  THREAD_SETMEM(self, p_cleanup, buffer->__prev);
+  THREAD_SETMEM(self, p_canceltype, buffer->__canceltype);
+  if (THREAD_GETMEM(self, p_canceled) &&
+      THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE &&
+      THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+}
+
+extern void __rpc_thread_destroy(void);
+void __pthread_perform_cleanup(char *currentframe)
+{
+  pthread_descr self = thread_self();
+  struct _pthread_cleanup_buffer *c = THREAD_GETMEM(self, p_cleanup);
+  struct _pthread_cleanup_buffer *last;
+
+  if (c != NULL)
+    while (FRAME_LEFT (currentframe, c))
+      {
+	last = c;
+	c = c->__prev;
+
+	if (c == NULL || FRAME_LEFT (last, c))
+	  {
+	    c = NULL;
+	    break;
+	  }
+      }
+
+  while (c != NULL)
+    {
+      c->__routine(c->__arg);
+
+      last = c;
+      c = c->__prev;
+
+      if (FRAME_LEFT (last, c))
+	break;
+    }
+
+#ifdef __UCLIBC_HAS_RPC__
+  /* And the TSD which needs special help.  */
+  if (THREAD_GETMEM(self, p_libc_specific[_LIBC_TSD_KEY_RPC_VARS]) != NULL)
+      __rpc_thread_destroy ();
+#endif
+}

+ 304 - 0
libpthread/linuxthreads/condvar.c

@@ -0,0 +1,304 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/* and Pavel Krauz (krauz@fsid.cvut.cz).                                */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Condition variables */
+
+#include <errno.h>
+#include <sched.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "queue.h"
+#include "restart.h"
+
+int __pthread_cond_init(pthread_cond_t *cond,
+                        const pthread_condattr_t *cond_attr)
+{
+  __pthread_init_lock(&cond->__c_lock);
+  cond->__c_waiting = NULL;
+  return 0;
+}
+strong_alias (__pthread_cond_init, pthread_cond_init)
+
+int __pthread_cond_destroy(pthread_cond_t *cond)
+{
+  if (cond->__c_waiting != NULL) return EBUSY;
+  return 0;
+}
+strong_alias (__pthread_cond_destroy, pthread_cond_destroy)
+
+/* Function called by pthread_cancel to remove the thread from
+   waiting on a condition variable queue. */
+
+static int cond_extricate_func(void *obj, pthread_descr th)
+{
+  volatile pthread_descr self = thread_self();
+  pthread_cond_t *cond = obj;
+  int did_remove = 0;
+
+  __pthread_lock(&cond->__c_lock, self);
+  did_remove = remove_from_queue(&cond->__c_waiting, th);
+  __pthread_unlock(&cond->__c_lock);
+
+  return did_remove;
+}
+
+int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+  volatile pthread_descr self = thread_self();
+  pthread_extricate_if extr;
+  int already_canceled = 0;
+  int spurious_wakeup_count;
+
+  /* Check whether the mutex is locked and owned by this thread.  */
+  if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
+      && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
+      && mutex->__m_owner != self)
+    return EINVAL;
+
+  /* Set up extrication interface */
+  extr.pu_object = cond;
+  extr.pu_extricate_func = cond_extricate_func;
+
+  /* Register extrication interface */
+  THREAD_SETMEM(self, p_condvar_avail, 0);
+  __pthread_set_own_extricate_if(self, &extr);
+
+  /* Atomically enqueue thread for waiting, but only if it is not
+     canceled. If the thread is canceled, then it will fall through the
+     suspend call below, and then call pthread_exit without
+     having to worry about whether it is still on the condition variable queue.
+     This depends on pthread_cancel setting p_canceled before calling the
+     extricate function. */
+
+  __pthread_lock(&cond->__c_lock, self);
+  if (!(THREAD_GETMEM(self, p_canceled)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
+    enqueue(&cond->__c_waiting, self);
+  else
+    already_canceled = 1;
+  __pthread_unlock(&cond->__c_lock);
+
+  if (already_canceled) {
+    __pthread_set_own_extricate_if(self, 0);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+
+  pthread_mutex_unlock(mutex);
+
+  spurious_wakeup_count = 0;
+  while (1)
+    {
+      suspend(self);
+      if (THREAD_GETMEM(self, p_condvar_avail) == 0
+	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+	{
+	  /* Count resumes that don't belong to us. */
+	  spurious_wakeup_count++;
+	  continue;
+	}
+      break;
+    }
+
+  __pthread_set_own_extricate_if(self, 0);
+
+  /* Check for cancellation again, to provide correct cancellation
+     point behavior */
+
+  if (THREAD_GETMEM(self, p_woken_by_cancel)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+    THREAD_SETMEM(self, p_woken_by_cancel, 0);
+    pthread_mutex_lock(mutex);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+
+  /* Put back any resumes we caught that don't belong to us. */
+  while (spurious_wakeup_count--)
+    restart(self);
+
+  pthread_mutex_lock(mutex);
+  return 0;
+}
+strong_alias (__pthread_cond_wait, pthread_cond_wait)
+
+static int
+pthread_cond_timedwait_relative(pthread_cond_t *cond,
+				pthread_mutex_t *mutex,
+				const struct timespec * abstime)
+{
+  volatile pthread_descr self = thread_self();
+  int already_canceled = 0;
+  pthread_extricate_if extr;
+  int spurious_wakeup_count;
+
+  /* Check whether the mutex is locked and owned by this thread.  */
+  if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
+      && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
+      && mutex->__m_owner != self)
+    return EINVAL;
+
+  /* Set up extrication interface */
+  extr.pu_object = cond;
+  extr.pu_extricate_func = cond_extricate_func;
+
+  /* Register extrication interface */
+  THREAD_SETMEM(self, p_condvar_avail, 0);
+  __pthread_set_own_extricate_if(self, &extr);
+
+  /* Enqueue to wait on the condition and check for cancellation. */
+  __pthread_lock(&cond->__c_lock, self);
+  if (!(THREAD_GETMEM(self, p_canceled)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
+    enqueue(&cond->__c_waiting, self);
+  else
+    already_canceled = 1;
+  __pthread_unlock(&cond->__c_lock);
+
+  if (already_canceled) {
+    __pthread_set_own_extricate_if(self, 0);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+
+  pthread_mutex_unlock(mutex);
+
+  spurious_wakeup_count = 0;
+  while (1)
+    {
+      if (!timedsuspend(self, abstime)) {
+	int was_on_queue;
+
+	/* __pthread_lock will queue back any spurious restarts that
+	   may happen to it. */
+
+	__pthread_lock(&cond->__c_lock, self);
+	was_on_queue = remove_from_queue(&cond->__c_waiting, self);
+	__pthread_unlock(&cond->__c_lock);
+
+	if (was_on_queue) {
+	  __pthread_set_own_extricate_if(self, 0);
+	  pthread_mutex_lock(mutex);
+	  return ETIMEDOUT;
+	}
+
+	/* Eat the outstanding restart() from the signaller */
+	suspend(self);
+      }
+
+      if (THREAD_GETMEM(self, p_condvar_avail) == 0
+	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+	{
+	  /* Count resumes that don't belong to us. */
+	  spurious_wakeup_count++;
+	  continue;
+	}
+      break;
+    }
+
+  __pthread_set_own_extricate_if(self, 0);
+
+  /* The remaining logic is the same as in other cancellable waits,
+     such as pthread_join sem_wait or pthread_cond wait. */
+
+  if (THREAD_GETMEM(self, p_woken_by_cancel)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+    THREAD_SETMEM(self, p_woken_by_cancel, 0);
+    pthread_mutex_lock(mutex);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+
+  /* Put back any resumes we caught that don't belong to us. */
+  while (spurious_wakeup_count--)
+    restart(self);
+
+  pthread_mutex_lock(mutex);
+  return 0;
+}
+
+int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+			     const struct timespec * abstime)
+{
+  /* Indirect call through pointer! */
+  return pthread_cond_timedwait_relative(cond, mutex, abstime);
+}
+strong_alias (__pthread_cond_timedwait, pthread_cond_timedwait)
+
+int __pthread_cond_signal(pthread_cond_t *cond)
+{
+  pthread_descr th;
+
+  __pthread_lock(&cond->__c_lock, NULL);
+  th = dequeue(&cond->__c_waiting);
+  __pthread_unlock(&cond->__c_lock);
+  if (th != NULL) {
+    th->p_condvar_avail = 1;
+    WRITE_MEMORY_BARRIER();
+    restart(th);
+  }
+  return 0;
+}
+strong_alias (__pthread_cond_signal, pthread_cond_signal)
+
+int __pthread_cond_broadcast(pthread_cond_t *cond)
+{
+  pthread_descr tosignal, th;
+
+  __pthread_lock(&cond->__c_lock, NULL);
+  /* Copy the current state of the waiting queue and empty it */
+  tosignal = cond->__c_waiting;
+  cond->__c_waiting = NULL;
+  __pthread_unlock(&cond->__c_lock);
+  /* Now signal each process in the queue */
+  while ((th = dequeue(&tosignal)) != NULL) {
+    th->p_condvar_avail = 1;
+    WRITE_MEMORY_BARRIER();
+    restart(th);
+  }
+  return 0;
+}
+strong_alias (__pthread_cond_broadcast, pthread_cond_broadcast)
+
+int __pthread_condattr_init(pthread_condattr_t *attr)
+{
+  return 0;
+}
+strong_alias (__pthread_condattr_init, pthread_condattr_init)
+
+int __pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+  return 0;
+}
+strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy)
+
+int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
+{
+  *pshared = PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
+{
+  if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
+    return EINVAL;
+
+  /* For now it is not possible to shared a conditional variable.  */
+  if (pshared != PTHREAD_PROCESS_PRIVATE)
+    return ENOSYS;
+
+  return 0;
+}

+ 270 - 0
libpthread/linuxthreads/descr.h

@@ -0,0 +1,270 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+#ifndef _DESCR_H
+#define _DESCR_H	1
+
+#define __need_res_state
+#include <resolv.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <hp-timing.h>
+#ifdef USE_TLS
+#include <tls.h>
+#endif
+#include "uClibc-glue.h"
+
+/* Fast thread-specific data internal to libc.  */
+enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
+			_LIBC_TSD_KEY_DL_ERROR,
+			_LIBC_TSD_KEY_RPC_VARS,
+			_LIBC_TSD_KEY_LOCALE,
+			_LIBC_TSD_KEY_CTYPE_B,
+			_LIBC_TSD_KEY_CTYPE_TOLOWER,
+			_LIBC_TSD_KEY_CTYPE_TOUPPER,
+			_LIBC_TSD_KEY_N };
+
+/* The type of thread descriptors */
+typedef struct _pthread_descr_struct *pthread_descr;
+
+
+/* Some more includes.  */
+#include <pt-machine.h>
+#include <linuxthreads_db/thread_dbP.h>
+
+
+/* Arguments passed to thread creation routine */
+struct pthread_start_args {
+  void *(*start_routine)(void *); /* function to run */
+  void *arg;                      /* its argument */
+  sigset_t mask;                  /* initial signal mask for thread */
+  int schedpolicy;                /* initial scheduling policy (if any) */
+  struct sched_param schedparam;  /* initial scheduling parameters (if any) */
+};
+
+
+/* Callback interface for removing the thread from waiting on an
+   object if it is cancelled while waiting or about to wait.
+   This hold a pointer to the object, and a pointer to a function
+   which ``extricates'' the thread from its enqueued state.
+   The function takes two arguments: pointer to the wait object,
+   and a pointer to the thread. It returns 1 if an extrication
+   actually occured, and hence the thread must also be signalled.
+   It returns 0 if the thread had already been extricated. */
+typedef struct _pthread_extricate_struct {
+    void *pu_object;
+    int (*pu_extricate_func)(void *, pthread_descr);
+} pthread_extricate_if;
+
+
+/* Atomic counter made possible by compare_and_swap */
+struct pthread_atomic {
+  long p_count;
+  int p_spinlock;
+};
+
+
+/* Context info for read write locks. The pthread_rwlock_info structure
+   is information about a lock that has been read-locked by the thread
+   in whose list this structure appears. The pthread_rwlock_context
+   is embedded in the thread context and contains a pointer to the
+   head of the list of lock info structures, as well as a count of
+   read locks that are untracked, because no info structure could be
+   allocated for them. */
+struct _pthread_rwlock_t;
+typedef struct _pthread_rwlock_info {
+  struct _pthread_rwlock_info *pr_next;
+  struct _pthread_rwlock_t *pr_lock;
+  int pr_lock_count;
+} pthread_readlock_info;
+
+
+/* We keep thread specific data in a special data structure, a two-level
+   array.  The top-level array contains pointers to dynamically allocated
+   arrays of a certain number of data pointers.  So we can implement a
+   sparse array.  Each dynamic second-level array has
+	PTHREAD_KEY_2NDLEVEL_SIZE
+   entries.  This value shouldn't be too large.  */
+#define PTHREAD_KEY_2NDLEVEL_SIZE	32
+
+/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
+   keys in each subarray.  */
+#define PTHREAD_KEY_1STLEVEL_SIZE \
+  ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
+   / PTHREAD_KEY_2NDLEVEL_SIZE)
+
+
+union dtv;
+
+struct _pthread_descr_struct
+{
+#if !defined USE_TLS || !TLS_DTV_AT_TP || INCLUDE_TLS_PADDING
+  /* This overlaps tcbhead_t (see tls.h), as used for TLS without threads.  */
+  union
+  {
+    struct
+    {
+      void *tcb;		/* Pointer to the TCB.  This is not always
+				   the address of this thread descriptor.  */
+      union dtv *dtvp;
+      pthread_descr self;	/* Pointer to this structure */
+      int multiple_threads;
+# ifdef NEED_DL_SYSINFO
+      uintptr_t sysinfo;
+# endif
+    } data;
+    void *__padding[16];
+  } p_header;
+# define p_multiple_threads p_header.data.multiple_threads
+#elif TLS_MULTIPLE_THREADS_IN_TCB
+  int p_multiple_threads;
+#endif
+
+  pthread_descr p_nextlive, p_prevlive;
+                                /* Double chaining of active threads */
+  pthread_descr p_nextwaiting;  /* Next element in the queue holding the thr */
+  pthread_descr p_nextlock;	/* can be on a queue and waiting on a lock */
+  pthread_t p_tid;              /* Thread identifier */
+  int p_pid;                    /* PID of Unix process */
+  int p_priority;               /* Thread priority (== 0 if not realtime) */
+  struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */
+  int p_signal;                 /* last signal received */
+  sigjmp_buf * p_signal_jmp;    /* where to siglongjmp on a signal or NULL */
+  sigjmp_buf * p_cancel_jmp;    /* where to siglongjmp on a cancel or NULL */
+  char p_terminated;            /* true if terminated e.g. by pthread_exit */
+  char p_detached;              /* true if detached */
+  char p_exited;                /* true if the assoc. process terminated */
+  void * p_retval;              /* placeholder for return value */
+  int p_retcode;                /* placeholder for return code */
+  pthread_descr p_joining;      /* thread joining on that thread or NULL */
+  struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */
+  char p_cancelstate;           /* cancellation state */
+  char p_canceltype;            /* cancellation type (deferred/async) */
+  char p_canceled;              /* cancellation request pending */
+  char * p_in_sighandler;       /* stack address of sighandler, or NULL */
+  char p_sigwaiting;            /* true if a sigwait() is in progress */
+  struct pthread_start_args p_start_args; /* arguments for thread creation */
+  void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
+#if !(USE_TLS && HAVE___THREAD)
+  void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */
+  int * p_errnop;               /* pointer to used errno variable */
+  int p_errno;                  /* error returned by last system call */
+  int * p_h_errnop;             /* pointer to used h_errno variable */
+  int p_h_errno;                /* error returned by last netdb function */
+  struct __res_state *p_resp;	/* Pointer to resolver state */
+#endif
+  struct __res_state p_res;	/* per-thread resolver state */
+  int p_userstack;		/* nonzero if the user provided the stack */
+  void *p_guardaddr;		/* address of guard area or NULL */
+  size_t p_guardsize;		/* size of guard area */
+  int p_nr;                     /* Index of descriptor in __pthread_handles */
+  int p_report_events;		/* Nonzero if events must be reported.  */
+  td_eventbuf_t p_eventbuf;     /* Data for event.  */
+  struct pthread_atomic p_resume_count; /* number of times restart() was
+					   called on thread */
+  char p_woken_by_cancel;       /* cancellation performed wakeup */
+  char p_condvar_avail;		/* flag if conditional variable became avail */
+  char p_sem_avail;             /* flag if semaphore became available */
+  pthread_extricate_if *p_extricate; /* See above */
+  pthread_readlock_info *p_readlock_list;  /* List of readlock info structs */
+  pthread_readlock_info *p_readlock_free;  /* Free list of structs */
+  int p_untracked_readlock_count;	/* Readlocks not tracked by list */
+  int p_inheritsched;           /* copied from the thread attribute */
+#if HP_TIMING_AVAIL
+  hp_timing_t p_cpuclock_offset; /* Initial CPU clock for thread.  */
+#endif
+#ifdef USE_TLS
+  char *p_stackaddr;		/* Stack address.  */
+#endif
+  size_t p_alloca_cutoff;	/* Maximum size which should be allocated
+				   using alloca() instead of malloc().  */
+  /* New elements must be added at the end.  */
+} __attribute__ ((aligned(32))); /* We need to align the structure so that
+				    doubles are aligned properly.  This is 8
+				    bytes on MIPS and 16 bytes on MIPS64.
+				    32 bytes might give better cache
+				    utilization.  */
+
+
+
+/* Limit between the stack of the initial thread (above) and the
+   stacks of other threads (below). Aligned on a STACK_SIZE boundary.
+   Initially 0, meaning that the current thread is (by definition)
+   the initial thread. */
+
+extern char *__pthread_initial_thread_bos;
+
+/* Descriptor of the initial thread */
+
+extern struct _pthread_descr_struct __pthread_initial_thread;
+
+/* Limits of the thread manager stack. */
+
+extern char *__pthread_manager_thread_bos;
+extern char *__pthread_manager_thread_tos;
+
+/* Descriptor of the manager thread */
+
+extern struct _pthread_descr_struct __pthread_manager_thread;
+extern pthread_descr __pthread_manager_threadp attribute_hidden;
+
+/* Indicate whether at least one thread has a user-defined stack (if 1),
+   or all threads have stacks supplied by LinuxThreads (if 0). */
+
+extern int __pthread_nonstandard_stacks;
+
+/* The max size of the thread stack segments.  If the default
+   THREAD_SELF implementation is used, this must be a power of two and
+   a multiple of PAGE_SIZE.  */
+#ifndef STACK_SIZE
+#define STACK_SIZE  (2 * 1024 * 1024)
+#endif
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.  */
+#ifndef CURRENT_STACK_FRAME
+#define CURRENT_STACK_FRAME  ({ char __csf; &__csf; })
+#endif
+
+/* Recover thread descriptor for the current thread */
+
+extern pthread_descr __pthread_find_self (void) __attribute__ ((pure));
+
+static inline pthread_descr thread_self (void) __attribute__ ((pure));
+static inline pthread_descr thread_self (void)
+{
+#ifdef THREAD_SELF
+  return THREAD_SELF;
+#else
+  char *sp = CURRENT_STACK_FRAME;
+  if (sp >= __pthread_initial_thread_bos)
+    return &__pthread_initial_thread;
+  else if (sp >= __pthread_manager_thread_bos
+	   && sp < __pthread_manager_thread_tos)
+    return &__pthread_manager_thread;
+  else if (__pthread_nonstandard_stacks)
+    return __pthread_find_self();
+  else
+#ifdef _STACK_GROWS_DOWN
+    return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1;
+#else
+    return (pthread_descr)((unsigned long)sp &~ (STACK_SIZE-1));
+#endif
+#endif
+}
+
+#endif	/* descr.h */

+ 46 - 0
libpthread/linuxthreads/errno.c

@@ -0,0 +1,46 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Define the location of errno for the remainder of the C library */
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include "pthread.h"
+#include "internals.h"
+
+#if !USE_TLS || !HAVE___THREAD
+/* The definition in libc is sufficient if we use TLS.  */
+int *
+__errno_location (void)
+{
+  pthread_descr self = thread_self();
+  return THREAD_GETMEM (self, p_errnop);
+}
+
+int *
+__h_errno_location (void)
+{
+  pthread_descr self = thread_self();
+  return THREAD_GETMEM (self, p_h_errnop);
+}
+
+/* Return thread specific resolver state.  */
+struct __res_state *
+__res_state (void)
+{
+  pthread_descr self = thread_self();
+  return THREAD_GETMEM (self, p_resp);
+}
+#endif

+ 37 - 0
libpthread/linuxthreads/events.c

@@ -0,0 +1,37 @@
+/* Event functions used while debugging.
+   Copyright (C) 1999, 2000 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.  */
+
+/* The functions contained here do nothing, they just return.  */
+
+#include "internals.h"
+
+void
+__linuxthreads_create_event (void)
+{
+}
+
+void
+__linuxthreads_death_event (void)
+{
+}
+
+void
+__linuxthreads_reap_event (void)
+{
+}

+ 141 - 0
libpthread/linuxthreads/forward.c

@@ -0,0 +1,141 @@
+/* Copyright (C) 2002, 2003 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 <dlfcn.h>
+#include "internals.h"
+#include <stdlib.h>
+
+
+/* Pointers to the libc functions.  */
+struct pthread_functions __libc_pthread_functions attribute_hidden;
+
+
+# define FORWARD2(name, rettype, decl, params, defaction) \
+rettype									      \
+name decl								      \
+{									      \
+  if (__libc_pthread_functions.ptr_##name == NULL)			      \
+    defaction;								      \
+									      \
+  return __libc_pthread_functions.ptr_##name params;			      \
+}
+
+# define FORWARD(name, decl, params, defretval) \
+  FORWARD2 (name, int, decl, params, return defretval)
+
+FORWARD (pthread_attr_destroy, (pthread_attr_t *attr), (attr), 0)
+
+FORWARD (__pthread_attr_init, (pthread_attr_t *attr), (attr), 0)
+
+FORWARD (pthread_attr_getdetachstate,
+	 (const pthread_attr_t *attr, int *detachstate), (attr, detachstate),
+	 0)
+FORWARD (pthread_attr_setdetachstate, (pthread_attr_t *attr, int detachstate),
+	 (attr, detachstate), 0)
+
+FORWARD (pthread_attr_getinheritsched,
+	 (const pthread_attr_t *attr, int *inherit), (attr, inherit), 0)
+FORWARD (pthread_attr_setinheritsched, (pthread_attr_t *attr, int inherit),
+	 (attr, inherit), 0)
+
+FORWARD (pthread_attr_getschedparam,
+	 (const pthread_attr_t *attr, struct sched_param *param),
+	 (attr, param), 0)
+FORWARD (pthread_attr_setschedparam,
+	 (pthread_attr_t *attr, const struct sched_param *param),
+	 (attr, param), 0)
+
+FORWARD (pthread_attr_getschedpolicy,
+	 (const pthread_attr_t *attr, int *policy), (attr, policy), 0)
+FORWARD (pthread_attr_setschedpolicy, (pthread_attr_t *attr, int policy),
+	 (attr, policy), 0)
+
+FORWARD (pthread_attr_getscope,
+	 (const pthread_attr_t *attr, int *scope), (attr, scope), 0)
+FORWARD (pthread_attr_setscope, (pthread_attr_t *attr, int scope),
+	 (attr, scope), 0)
+
+
+FORWARD (pthread_condattr_destroy, (pthread_condattr_t *attr), (attr), 0)
+FORWARD (pthread_condattr_init, (pthread_condattr_t *attr), (attr), 0)
+
+
+FORWARD (pthread_cond_broadcast, (pthread_cond_t *cond), (cond), 0)
+
+FORWARD (pthread_cond_destroy, (pthread_cond_t *cond), (cond), 0)
+
+FORWARD (pthread_cond_init,
+	 (pthread_cond_t *cond, const pthread_condattr_t *cond_attr),
+	 (cond, cond_attr), 0)
+
+FORWARD (pthread_cond_signal, (pthread_cond_t *cond), (cond), 0)
+
+FORWARD (pthread_cond_wait, (pthread_cond_t *cond, pthread_mutex_t *mutex),
+	 (cond, mutex), 0)
+
+FORWARD (pthread_cond_timedwait,
+	 (pthread_cond_t *cond, pthread_mutex_t *mutex,
+	  const struct timespec *abstime), (cond, mutex, abstime), 0)
+
+
+FORWARD (pthread_equal, (pthread_t thread1, pthread_t thread2),
+	 (thread1, thread2), 1)
+
+
+/* Use an alias to avoid warning, as pthread_exit is declared noreturn.  */
+FORWARD2 (__pthread_exit, void, (void *retval), (retval), exit (EXIT_SUCCESS))
+strong_alias (__pthread_exit, pthread_exit);
+
+
+FORWARD (pthread_getschedparam,
+	 (pthread_t target_thread, int *policy, struct sched_param *param),
+	 (target_thread, policy, param), 0)
+FORWARD (pthread_setschedparam,
+	 (pthread_t target_thread, int policy,
+	  const struct sched_param *param), (target_thread, policy, param), 0)
+
+
+FORWARD (pthread_mutex_destroy, (pthread_mutex_t *mutex), (mutex), 0)
+
+FORWARD (pthread_mutex_init,
+	 (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr),
+	 (mutex, mutexattr), 0)
+hidden_strong_alias(pthread_mutex_init, __pthread_mutex_init)
+
+FORWARD (pthread_mutex_lock, (pthread_mutex_t *mutex), (mutex), 0)
+hidden_strong_alias(pthread_mutex_lock, __pthread_mutex_lock)
+
+FORWARD (pthread_mutex_trylock, (pthread_mutex_t *mutex), (mutex), 0)
+hidden_strong_alias(pthread_mutex_trylock, __pthread_mutex_trylock)
+
+FORWARD (pthread_mutex_unlock, (pthread_mutex_t *mutex), (mutex), 0)
+hidden_strong_alias(pthread_mutex_unlock, __pthread_mutex_unlock)
+
+
+FORWARD2 (pthread_self, pthread_t, (void), (), return 0)
+
+
+FORWARD (pthread_setcancelstate, (int state, int *oldstate), (state, oldstate),
+	 0)
+
+FORWARD (pthread_setcanceltype, (int type, int *oldtype), (type, oldtype), 0)
+
+FORWARD2 (_pthread_cleanup_push, void, (struct _pthread_cleanup_buffer * buffer, void (*routine)(void *), void * arg), (buffer, routine, arg), return)
+
+FORWARD2 (_pthread_cleanup_pop, void, (struct _pthread_cleanup_buffer * buffer, int execute), (buffer, execute), return)

+ 551 - 0
libpthread/linuxthreads/internals.h

@@ -0,0 +1,551 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+#ifndef _INTERNALS_H
+#define _INTERNALS_H	1
+
+#include "uClibc-glue.h"
+
+/* Internal data structures */
+
+/* Includes */
+
+#include <limits.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/ucontext.h>
+#include <bits/stackinfo.h>
+#include <bits/sigcontextinfo.h>
+#include <bits/pthreadtypes.h>
+
+#ifdef USE_TLS
+#include <tls.h>
+#endif
+#include "descr.h"
+
+#include "semaphore.h"
+#include <pthread-functions.h>
+
+#ifndef THREAD_GETMEM
+# define THREAD_GETMEM(descr, member) descr->member
+#endif
+#ifndef THREAD_GETMEM_NC
+# define THREAD_GETMEM_NC(descr, member) descr->member
+#endif
+#ifndef THREAD_SETMEM
+# define THREAD_SETMEM(descr, member, value) descr->member = (value)
+#endif
+#ifndef THREAD_SETMEM_NC
+# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value)
+#endif
+
+#if !defined NOT_IN_libc && defined FLOATING_STACKS
+# define LIBC_THREAD_GETMEM(descr, member) THREAD_GETMEM (descr, member)
+# define LIBC_THREAD_SETMEM(descr, member, value) \
+  THREAD_SETMEM (descr, member, value)
+#else
+# define LIBC_THREAD_GETMEM(descr, member) descr->member
+# define LIBC_THREAD_SETMEM(descr, member, value) descr->member = (value)
+#endif
+
+typedef void (*destr_function)(void *);
+
+struct pthread_key_struct {
+  int in_use;                   /* already allocated? */
+  destr_function destr;         /* destruction routine */
+};
+
+
+#define PTHREAD_START_ARGS_INITIALIZER(fct) \
+  { (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } }
+
+
+/* The type of thread handles. */
+
+typedef struct pthread_handle_struct * pthread_handle;
+
+struct pthread_handle_struct {
+  struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */
+  pthread_descr h_descr;        /* Thread descriptor or NULL if invalid */
+  char * h_bottom;              /* Lowest address in the stack thread */
+};
+
+/* The type of messages sent to the thread manager thread */
+
+struct pthread_request {
+  pthread_descr req_thread;     /* Thread doing the request */
+  enum {                        /* Request kind */
+    REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT,
+    REQ_POST, REQ_DEBUG, REQ_KICK, REQ_FOR_EACH_THREAD
+  } req_kind;
+  union {                       /* Arguments for request */
+    struct {                    /* For REQ_CREATE: */
+      const pthread_attr_t * attr; /* thread attributes */
+      void * (*fn)(void *);     /*   start function */
+      void * arg;               /*   argument to start function */
+      sigset_t mask;            /*   signal mask */
+    } create;
+    struct {                    /* For REQ_FREE: */
+      pthread_t thread_id;      /*   identifier of thread to free */
+    } free;
+    struct {                    /* For REQ_PROCESS_EXIT: */
+      int code;                 /*   exit status */
+    } exit;
+    void * post;                /* For REQ_POST: the semaphore */
+    struct {			/* For REQ_FOR_EACH_THREAD: callback */
+      void (*fn)(void *, pthread_descr);
+      void *arg;
+    } for_each;
+  } req_args;
+};
+
+
+
+typedef void (*arch_sighandler_t) (int, SIGCONTEXT);
+union sighandler
+{
+  arch_sighandler_t old;
+  void (*rt) (int, struct siginfo *, struct ucontext *);
+};
+extern union sighandler __sighandler[NSIG];
+
+
+/* Signals used for suspend/restart and for cancellation notification.  */
+
+extern int __pthread_sig_restart;
+extern int __pthread_sig_cancel;
+
+/* Signal used for interfacing with gdb */
+
+extern int __pthread_sig_debug;
+
+/* Global array of thread handles, used for validating a thread id
+   and retrieving the corresponding thread descriptor. Also used for
+   mapping the available stack segments. */
+
+extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX];
+
+/* Descriptor of the main thread */
+
+extern pthread_descr __pthread_main_thread;
+
+/* File descriptor for sending requests to the thread manager.
+   Initially -1, meaning that __pthread_initialize_manager must be called. */
+
+extern int __pthread_manager_request;
+
+/* Other end of the pipe for sending requests to the thread manager. */
+
+extern int __pthread_manager_reader;
+
+#ifdef FLOATING_STACKS
+/* Maximum stack size.  */
+extern size_t __pthread_max_stacksize;
+#endif
+
+/* Pending request for a process-wide exit */
+
+extern int __pthread_exit_requested, __pthread_exit_code;
+
+/* Set to 1 by gdb if we're debugging */
+
+extern volatile int __pthread_threads_debug;
+
+/* Globally enabled events.  */
+extern volatile td_thr_events_t __pthread_threads_events;
+
+/* Pointer to descriptor of thread with last event.  */
+extern volatile pthread_descr __pthread_last_event;
+
+/* Flag which tells whether we are executing on SMP kernel. */
+extern int __pthread_smp_kernel;
+
+/* Return the handle corresponding to a thread id */
+
+static inline pthread_handle thread_handle(pthread_t id)
+{
+  return &__pthread_handles[id % PTHREAD_THREADS_MAX];
+}
+
+/* Validate a thread handle. Must have acquired h->h_spinlock before. */
+
+static inline int invalid_handle(pthread_handle h, pthread_t id)
+{
+  return h->h_descr == NULL || h->h_descr->p_tid != id || h->h_descr->p_terminated;
+}
+
+static inline int nonexisting_handle(pthread_handle h, pthread_t id)
+{
+  return h->h_descr == NULL || h->h_descr->p_tid != id;
+}
+
+/* Fill in defaults left unspecified by pt-machine.h.  */
+
+/* We round up a value with page size. */
+#ifndef page_roundup
+#define page_roundup(v,p) ((((size_t) (v)) + (p) - 1) & ~((p) - 1))
+#endif
+
+/* The page size we can get from the system.  This should likely not be
+   changed by the machine file but, you never know.  */
+#ifndef PAGE_SIZE
+#define PAGE_SIZE  (sysconf (_SC_PAGE_SIZE))
+#endif
+
+/* The initial size of the thread stack.  Must be a multiple of PAGE_SIZE.  */
+#ifndef INITIAL_STACK_SIZE
+#define INITIAL_STACK_SIZE  (4 * PAGE_SIZE)
+#endif
+
+/* Size of the thread manager stack. The "- 32" avoids wasting space
+   with some malloc() implementations. */
+#ifndef THREAD_MANAGER_STACK_SIZE
+#define THREAD_MANAGER_STACK_SIZE  (2 * PAGE_SIZE - 32)
+#endif
+
+/* The base of the "array" of thread stacks.  The array will grow down from
+   here.  Defaults to the calculated bottom of the initial application
+   stack.  */
+#ifndef THREAD_STACK_START_ADDRESS
+#define THREAD_STACK_START_ADDRESS  __pthread_initial_thread_bos
+#endif
+
+/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the
+   architecture doesn't need a memory barrier instruction (e.g. Intel
+   x86).  Still we need the compiler to respect the barrier and emit
+   all outstanding operations which modify memory.  Some architectures
+   distinguish between full, read and write barriers.  */
+
+#ifndef MEMORY_BARRIER
+#define MEMORY_BARRIER() asm ("" : : : "memory")
+#endif
+#ifndef READ_MEMORY_BARRIER
+#define READ_MEMORY_BARRIER() MEMORY_BARRIER()
+#endif
+#ifndef WRITE_MEMORY_BARRIER
+#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER()
+#endif
+
+/* Max number of times we must spin on a spinlock calling sched_yield().
+   After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
+
+#ifndef MAX_SPIN_COUNT
+#define MAX_SPIN_COUNT 50
+#endif
+
+/* Max number of times the spinlock in the adaptive mutex implementation
+   spins actively on SMP systems.  */
+
+#ifndef MAX_ADAPTIVE_SPIN_COUNT
+#define MAX_ADAPTIVE_SPIN_COUNT 100
+#endif
+
+/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock
+   after MAX_SPIN_COUNT iterations of sched_yield().
+   With the 2.0 and 2.1 kernels, this MUST BE > 2ms.
+   (Otherwise the kernel does busy-waiting for realtime threads,
+    giving other threads no chance to run.) */
+
+#ifndef SPIN_SLEEP_DURATION
+#define SPIN_SLEEP_DURATION 2000001
+#endif
+
+/* Defined and used in libc.so.  */
+extern int __libc_multiple_threads attribute_hidden;
+extern int __librt_multiple_threads;
+
+/* Debugging */
+
+#ifdef DEBUG
+#include <assert.h>
+#define ASSERT assert
+#define MSG __pthread_message
+#else
+#define ASSERT(x)
+#define MSG(msg,arg...)
+#endif
+
+/* Internal global functions */
+
+extern void __pthread_do_exit (void *retval, char *currentframe)
+     __attribute__ ((__noreturn__));
+extern void __pthread_destroy_specifics (void);
+extern void __pthread_perform_cleanup (char *currentframe);
+extern void __pthread_init_max_stacksize (void);
+extern int __pthread_initialize_manager (void);
+extern void __pthread_message (const char * fmt, ...);
+extern int __pthread_manager (void *reqfd);
+extern int __pthread_manager_event (void *reqfd);
+extern void __pthread_manager_sighandler (int sig);
+extern void __pthread_reset_main_thread (void);
+extern void __pthread_once_fork_prepare (void);
+extern void __pthread_once_fork_parent (void);
+extern void __pthread_once_fork_child (void);
+extern void __flockfilelist (void);
+extern void __funlockfilelist (void);
+extern void __fresetlockfiles (void);
+extern void __pthread_manager_adjust_prio (int thread_prio);
+extern void __pthread_initialize_minimal (void);
+
+extern int __pthread_attr_setguardsize (pthread_attr_t *__attr,
+					size_t __guardsize);
+extern int __pthread_attr_getguardsize (const pthread_attr_t *__attr,
+					size_t *__guardsize);
+extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr,
+					void *__stackaddr);
+extern int __pthread_attr_getstackaddr (const pthread_attr_t *__attr,
+					void **__stackaddr);
+extern int __pthread_attr_setstacksize (pthread_attr_t *__attr,
+					size_t __stacksize);
+extern int __pthread_attr_getstacksize (const pthread_attr_t *__attr,
+					size_t *__stacksize);
+extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+				    size_t __stacksize);
+extern int __pthread_attr_getstack (const pthread_attr_t *__attr, void **__stackaddr,
+				    size_t *__stacksize);
+extern int __pthread_attr_destroy (pthread_attr_t *attr);
+extern int __pthread_attr_setdetachstate (pthread_attr_t *attr,
+					  int detachstate);
+extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr,
+					  int *detachstate);
+extern int __pthread_attr_setschedparam (pthread_attr_t *attr,
+					 const struct sched_param *param);
+extern int __pthread_attr_getschedparam (const pthread_attr_t *attr,
+					 struct sched_param *param);
+extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy);
+extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr,
+					  int *policy);
+extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit);
+extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr,
+					   int *inherit);
+extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope);
+extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope);
+
+extern int __pthread_getconcurrency (void);
+extern int __pthread_setconcurrency (int __level);
+extern int __pthread_mutex_timedlock (pthread_mutex_t *__mutex,
+				      const struct timespec *__abstime);
+extern int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *__attr,
+					   int *__pshared);
+extern int __pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr,
+					   int __pshared);
+extern int __pthread_mutexattr_gettype (const pthread_mutexattr_t *__attr,
+					int *__kind);
+extern void __pthread_kill_other_threads_np (void);
+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_lock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+#if defined NOT_IN_libc && defined IS_IN_libpthread
+hidden_proto (__pthread_mutex_init)
+hidden_proto (__pthread_mutex_destroy)
+hidden_proto (__pthread_mutex_lock)
+hidden_proto (__pthread_mutex_trylock)
+hidden_proto (__pthread_mutex_unlock)
+#endif
+extern int __pthread_cond_init (pthread_cond_t *cond,
+				const pthread_condattr_t *cond_attr);
+extern int __pthread_cond_destroy (pthread_cond_t *cond);
+extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
+extern int __pthread_cond_timedwait (pthread_cond_t *cond,
+				     pthread_mutex_t *mutex,
+				     const struct timespec *abstime);
+extern int __pthread_cond_signal (pthread_cond_t *cond);
+extern int __pthread_cond_broadcast (pthread_cond_t *cond);
+extern int __pthread_condattr_init (pthread_condattr_t *attr);
+extern int __pthread_condattr_destroy (pthread_condattr_t *attr);
+extern pthread_t __pthread_self (void);
+extern pthread_descr __pthread_thread_self (void);
+extern pthread_descr __pthread_self_stack (void) attribute_hidden;
+extern int __pthread_equal (pthread_t thread1, pthread_t thread2);
+extern void __pthread_exit (void *retval);
+extern int __pthread_getschedparam (pthread_t thread, int *policy,
+				    struct sched_param *param);
+extern int __pthread_setschedparam (pthread_t thread, int policy,
+				    const struct sched_param *param);
+extern int __pthread_setcancelstate (int state, int * oldstate);
+extern int __pthread_setcanceltype (int type, int * oldtype);
+
+extern void __pthread_restart_old(pthread_descr th);
+extern void __pthread_suspend_old(pthread_descr self);
+extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs);
+
+extern void __pthread_restart_new(pthread_descr th);
+extern void __pthread_suspend_new(pthread_descr self);
+extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs);
+
+extern void __pthread_wait_for_restart_signal(pthread_descr self);
+
+extern void __pthread_sigsuspend (const sigset_t *mask) attribute_hidden;
+
+extern int __pthread_yield (void);
+
+extern int __pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock,
+					 __const struct timespec *__restrict
+					 __abstime);
+extern int __pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock,
+					 __const struct timespec *__restrict
+					 __abstime);
+extern int __pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr);
+
+extern int __pthread_barrierattr_getpshared (__const pthread_barrierattr_t *
+					     __restrict __attr,
+					     int *__restrict __pshared);
+
+extern int __pthread_spin_lock (pthread_spinlock_t *__lock);
+extern int __pthread_spin_trylock (pthread_spinlock_t *__lock);
+extern int __pthread_spin_unlock (pthread_spinlock_t *__lock);
+extern int __pthread_spin_init (pthread_spinlock_t *__lock, int __pshared);
+extern int __pthread_spin_destroy (pthread_spinlock_t *__lock);
+
+/* Global pointers to old or new suspend functions */
+
+extern void (*__pthread_restart)(pthread_descr);
+extern void (*__pthread_suspend)(pthread_descr);
+extern int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *);
+
+/* Prototypes for the function without cancelation support when the
+   normal version has it.  */
+extern int __libc_close (int fd);
+extern int __libc_nanosleep (const struct timespec *requested_time,
+			     struct timespec *remaining);
+/* Prototypes for some of the new semaphore functions.  */
+extern int sem_post (sem_t * sem);
+extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value);
+extern int sem_wait (sem_t *__sem);
+extern int sem_trywait (sem_t *__sem);
+extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval);
+extern int sem_destroy (sem_t *__sem);
+
+/* Prototypes for compatibility functions.  */
+extern int __pthread_attr_init (pthread_attr_t *__attr);
+extern int __pthread_create (pthread_t *__restrict __threadp,
+				 const pthread_attr_t *__attr,
+				 void *(*__start_routine) (void *),
+				 void *__restrict __arg);
+
+/* The functions called the signal events.  */
+extern void __linuxthreads_create_event (void);
+extern void __linuxthreads_death_event (void);
+extern void __linuxthreads_reap_event (void);
+
+/* This function is called to initialize the pthread library.  */
+extern void __pthread_initialize (void);
+
+/* TSD.  */
+extern int __pthread_internal_tsd_set (int key, const void * pointer);
+extern void * __pthread_internal_tsd_get (int key);
+extern void ** __attribute__ ((__const__))
+  __pthread_internal_tsd_address (int key);
+
+/* Sighandler wrappers.  */
+extern void __pthread_sighandler(int signo, SIGCONTEXT ctx);
+extern void __pthread_sighandler_rt(int signo, struct siginfo *si,
+				    struct ucontext *uc);
+extern void __pthread_null_sighandler(int sig);
+extern int __pthread_sigaction (int sig, const struct sigaction *act,
+				struct sigaction *oact);
+extern int __pthread_sigwait (const sigset_t *set, int *sig);
+extern int __pthread_raise (int sig);
+
+/* Cancellation.  */
+extern int __pthread_enable_asynccancel (void) attribute_hidden;
+extern void __pthread_disable_asynccancel (int oldtype)
+  internal_function attribute_hidden;
+
+/* The two functions are in libc.so and not exported.  */
+extern int __libc_enable_asynccancel (void) attribute_hidden;
+extern void __libc_disable_asynccancel (int oldtype)
+  internal_function attribute_hidden;
+
+/* The two functions are in libc.so and are exported.  */
+extern int __librt_enable_asynccancel (void);
+extern void __librt_disable_asynccancel (int oldtype) internal_function;
+
+extern void __pthread_cleanup_upto (__jmp_buf target,
+				    char *targetframe) attribute_hidden;
+extern pid_t __pthread_fork (struct fork_block *b) attribute_hidden;
+
+#if !defined NOT_IN_libc
+# define LIBC_CANCEL_ASYNC() \
+  __libc_enable_asynccancel ()
+# define LIBC_CANCEL_RESET(oldtype) \
+  __libc_disable_asynccancel (oldtype)
+# define LIBC_CANCEL_HANDLED() \
+  __asm (".globl " __SYMBOL_PREFIX "__libc_enable_asynccancel"); \
+  __asm (".globl " __SYMBOL_PREFIX "__libc_disable_asynccancel")
+#elif defined IS_IN_libpthread
+# define LIBC_CANCEL_ASYNC() \
+  __pthread_enable_asynccancel ()
+# define LIBC_CANCEL_RESET(oldtype) \
+  __pthread_disable_asynccancel (oldtype)
+# define LIBC_CANCEL_HANDLED() \
+  __asm (".globl " __SYMBOL_PREFIX "__pthread_enable_asynccancel"); \
+  __asm (".globl " __SYMBOL_PREFIX "__pthread_disable_asynccancel")
+#elif defined IS_IN_librt
+# define LIBC_CANCEL_ASYNC() \
+  __librt_enable_asynccancel ()
+# define LIBC_CANCEL_RESET(oldtype) \
+  __librt_disable_asynccancel (oldtype)
+# define LIBC_CANCEL_HANDLED() \
+  __asm (".globl " __SYMBOL_PREFIX "__librt_enable_asynccancel"); \
+  __asm (".globl " __SYMBOL_PREFIX "__librt_disable_asynccancel")
+#else
+# define LIBC_CANCEL_ASYNC()    0 /* Just a dummy value.  */
+# define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it.  */
+# define LIBC_CANCEL_HANDLED()	/* Nothing.  */
+#endif
+
+extern int * __libc_pthread_init (const struct pthread_functions *functions);
+
+#if !defined NOT_IN_libc && !defined FLOATING_STACKS
+# ifdef SHARED
+#  define thread_self() \
+  (*__libc_pthread_functions.ptr_pthread_thread_self) ()
+# else
+weak_extern (__pthread_thread_self)
+#  define thread_self() __pthread_thread_self ()
+# endif
+#endif
+
+#ifndef USE_TLS
+# define __manager_thread (&__pthread_manager_thread)
+#else
+# define __manager_thread __pthread_manager_threadp
+#endif
+
+extern inline __attribute__((always_inline)) pthread_descr
+check_thread_self (void)
+{
+  pthread_descr self = thread_self ();
+#if defined THREAD_SELF && defined INIT_THREAD_SELF
+  if (self == __manager_thread)
+    {
+      /* A new thread might get a cancel signal before it is fully
+	 initialized, so that the thread register might still point to the
+	 manager thread.  Double check that this is really the manager
+	 thread.  */
+      self = __pthread_self_stack();
+      if (self != __manager_thread)
+	/* Oops, thread_self() isn't working yet..  */
+	INIT_THREAD_SELF(self, self->p_nr);
+    }
+#endif
+  return self;
+}
+
+#endif /* internals.h */

+ 220 - 0
libpthread/linuxthreads/join.c

@@ -0,0 +1,220 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Thread termination and joining */
+
+#include <errno.h>
+#include <sched.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+#include <not-cancel.h>
+
+void __pthread_exit(void * retval)
+{
+  __pthread_do_exit (retval, CURRENT_STACK_FRAME);
+}
+strong_alias (__pthread_exit, pthread_exit);
+
+void __pthread_do_exit(void *retval, char *currentframe)
+{
+  pthread_descr self = thread_self();
+  pthread_descr joining;
+  struct pthread_request request;
+
+  /* Reset the cancellation flag to avoid looping if the cleanup handlers
+     contain cancellation points */
+  THREAD_SETMEM(self, p_canceled, 0);
+  /* Call cleanup functions and destroy the thread-specific data */
+  __pthread_perform_cleanup(currentframe);
+  __pthread_destroy_specifics();
+  /* Store return value */
+  __pthread_lock(THREAD_GETMEM(self, p_lock), self);
+  THREAD_SETMEM(self, p_retval, retval);
+  /* See whether we have to signal the death.  */
+  if (THREAD_GETMEM(self, p_report_events))
+    {
+      /* See whether TD_DEATH is in any of the mask.  */
+      int idx = __td_eventword (TD_DEATH);
+      uint32_t mask = __td_eventmask (TD_DEATH);
+
+      if ((mask & (__pthread_threads_events.event_bits[idx]
+		   | THREAD_GETMEM_NC(self,
+				      p_eventbuf.eventmask.event_bits[idx])))
+	  != 0)
+	{
+	  /* Yep, we have to signal the death.  */
+	  THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH);
+	  THREAD_SETMEM(self, p_eventbuf.eventdata, self);
+	  __pthread_last_event = self;
+
+	  /* Now call the function to signal the event.  */
+	  __linuxthreads_death_event();
+	}
+    }
+  /* Say that we've terminated */
+  THREAD_SETMEM(self, p_terminated, 1);
+  /* See if someone is joining on us */
+  joining = THREAD_GETMEM(self, p_joining);
+  __pthread_unlock(THREAD_GETMEM(self, p_lock));
+  /* Restart joining thread if any */
+  if (joining != NULL) restart(joining);
+  /* If this is the initial thread, block until all threads have terminated.
+     If another thread calls exit, we'll be terminated from our signal
+     handler. */
+  if (self == __pthread_main_thread && __pthread_manager_request >= 0) {
+    request.req_thread = self;
+    request.req_kind = REQ_MAIN_THREAD_EXIT;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *)&request, sizeof(request)));
+    suspend(self);
+    /* Main thread flushes stdio streams and runs atexit functions.
+       It also calls a handler within LinuxThreads which sends a process exit
+       request to the thread manager. */
+    exit(0);
+  }
+  /* Threads other than the main one  terminate without flushing stdio streams
+     or running atexit functions. */
+  _exit(0);
+}
+
+/* Function called by pthread_cancel to remove the thread from
+   waiting on a condition variable queue. */
+
+static int join_extricate_func(void *obj, pthread_descr th)
+{
+  volatile pthread_descr self = thread_self();
+  pthread_handle handle = obj;
+  pthread_descr jo;
+  int did_remove = 0;
+
+  __pthread_lock(&handle->h_lock, self);
+  jo = handle->h_descr;
+  did_remove = jo->p_joining != NULL;
+  jo->p_joining = NULL;
+  __pthread_unlock(&handle->h_lock);
+
+  return did_remove;
+}
+
+int pthread_join(pthread_t thread_id, void ** thread_return)
+{
+  volatile pthread_descr self = thread_self();
+  struct pthread_request request;
+  pthread_handle handle = thread_handle(thread_id);
+  pthread_descr th;
+  pthread_extricate_if extr;
+  int already_canceled = 0;
+
+  /* Set up extrication interface */
+  extr.pu_object = handle;
+  extr.pu_extricate_func = join_extricate_func;
+
+  __pthread_lock(&handle->h_lock, self);
+  if (nonexisting_handle(handle, thread_id)) {
+    __pthread_unlock(&handle->h_lock);
+    return ESRCH;
+  }
+  th = handle->h_descr;
+  if (th == self) {
+    __pthread_unlock(&handle->h_lock);
+    return EDEADLK;
+  }
+  /* If detached or already joined, error */
+  if (th->p_detached || th->p_joining != NULL) {
+    __pthread_unlock(&handle->h_lock);
+    return EINVAL;
+  }
+  /* If not terminated yet, suspend ourselves. */
+  if (! th->p_terminated) {
+    /* Register extrication interface */
+    __pthread_set_own_extricate_if(self, &extr);
+    if (!(THREAD_GETMEM(self, p_canceled)
+	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
+      th->p_joining = self;
+    else
+      already_canceled = 1;
+    __pthread_unlock(&handle->h_lock);
+
+    if (already_canceled) {
+      __pthread_set_own_extricate_if(self, 0);
+      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+    }
+
+    suspend(self);
+    /* Deregister extrication interface */
+    __pthread_set_own_extricate_if(self, 0);
+
+    /* This is a cancellation point */
+    if (THREAD_GETMEM(self, p_woken_by_cancel)
+	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+      THREAD_SETMEM(self, p_woken_by_cancel, 0);
+      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+    }
+    __pthread_lock(&handle->h_lock, self);
+  }
+  /* Get return value */
+  if (thread_return != NULL) *thread_return = th->p_retval;
+  __pthread_unlock(&handle->h_lock);
+  /* Send notification to thread manager */
+  if (__pthread_manager_request >= 0) {
+    request.req_thread = self;
+    request.req_kind = REQ_FREE;
+    request.req_args.free.thread_id = thread_id;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *) &request, sizeof(request)));
+  }
+  return 0;
+}
+
+int pthread_detach(pthread_t thread_id)
+{
+  int terminated;
+  struct pthread_request request;
+  pthread_handle handle = thread_handle(thread_id);
+  pthread_descr th;
+
+  __pthread_lock(&handle->h_lock, NULL);
+  if (nonexisting_handle(handle, thread_id)) {
+    __pthread_unlock(&handle->h_lock);
+    return ESRCH;
+  }
+  th = handle->h_descr;
+  /* If already detached, error */
+  if (th->p_detached) {
+    __pthread_unlock(&handle->h_lock);
+    return EINVAL;
+  }
+  /* If already joining, don't do anything. */
+  if (th->p_joining != NULL) {
+    __pthread_unlock(&handle->h_lock);
+    return 0;
+  }
+  /* Mark as detached */
+  th->p_detached = 1;
+  terminated = th->p_terminated;
+  __pthread_unlock(&handle->h_lock);
+  /* If already terminated, notify thread manager to reclaim resources */
+  if (terminated && __pthread_manager_request >= 0) {
+    request.req_thread = thread_self();
+    request.req_kind = REQ_FREE;
+    request.req_args.free.thread_id = thread_id;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *) &request, sizeof(request)));
+  }
+  return 0;
+}

+ 64 - 0
libpthread/linuxthreads/libc-cancellation.c

@@ -0,0 +1,64 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@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 <rpc/rpc.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+#include <bits/libc-lock.h>
+
+#if !defined NOT_IN_libc
+
+# ifndef SHARED
+weak_extern (__pthread_do_exit)
+# endif
+
+int __libc_multiple_threads attribute_hidden __attribute__((nocommon));
+strong_alias (__libc_multiple_threads, __librt_multiple_threads);
+
+/* The next two functions are similar to pthread_setcanceltype() but
+   more specialized for the use in the cancelable functions like write().
+   They do not need to check parameters etc.  */
+int
+attribute_hidden
+__libc_enable_asynccancel (void)
+{
+  pthread_descr self = thread_self();
+  int oldtype = LIBC_THREAD_GETMEM(self, p_canceltype);
+  LIBC_THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_ASYNCHRONOUS);
+  if (__builtin_expect (LIBC_THREAD_GETMEM(self, p_canceled), 0) &&
+      LIBC_THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
+    __libc_maybe_call2 (pthread_do_exit,
+			(PTHREAD_CANCELED, CURRENT_STACK_FRAME), 0);
+  return oldtype;
+}
+strong_alias (__libc_enable_asynccancel, __librt_enable_asynccancel)
+
+void
+internal_function attribute_hidden
+__libc_disable_asynccancel (int oldtype)
+{
+  pthread_descr self = thread_self();
+  LIBC_THREAD_SETMEM(self, p_canceltype, oldtype);
+}
+strong_alias (__libc_disable_asynccancel, __librt_disable_asynccancel)
+
+#endif

+ 47 - 0
libpthread/linuxthreads/libc_pthread_init.c

@@ -0,0 +1,47 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@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 <locale.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef USE_TLS
+#include <tls.h>
+#endif
+#include "internals.h"
+
+int *
+__libc_pthread_init (functions)
+     const struct pthread_functions *functions;
+{
+#ifdef SHARED
+  /* We copy the content of the variable pointed to by the FUNCTIONS
+     parameter to one in libc.so since this means access to the array
+     can be done with one memory access instead of two.  */
+  memcpy (&__libc_pthread_functions, functions,
+	  sizeof (__libc_pthread_functions));
+#endif
+
+#if !(USE_TLS && HAVE___THREAD)
+  /* Initialize thread-locale current locale to point to the global one.
+     With __thread support, the variable's initializer takes care of this.  */
+  __uselocale (LC_GLOBAL_LOCALE);
+#endif
+
+  return &__libc_multiple_threads;
+}

+ 52 - 0
libpthread/linuxthreads/lockfile.c

@@ -0,0 +1,52 @@
+/* lockfile - Handle locking and unlocking of stream.
+   Copyright (C) 1996, 1998, 2000 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 <bits/libc-lock.h>
+#include <stdio.h>
+#include <pthread.h>
+#include "internals.h"
+
+/* Note: glibc puts flockfile, funlockfile, and ftrylockfile in both
+ * libc and libpthread.  In uClibc, they are now in libc only.  */
+
+void
+__flockfilelist(void)
+{
+}
+
+void
+__funlockfilelist(void)
+{
+}
+
+void
+__fresetlockfiles (void)
+{
+  FILE *fp;
+
+  pthread_mutexattr_t attr;
+
+  __pthread_mutexattr_init (&attr);
+  __pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+
+  for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen)
+    pthread_mutex_init (&fp->__lock, &attr);
+
+  pthread_mutexattr_destroy(&attr);
+}

+ 1123 - 0
libpthread/linuxthreads/manager.c

@@ -0,0 +1,1123 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* The "thread manager" thread: manages creation and termination of threads */
+
+#include <assert.h>
+#include <errno.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/poll.h>		/* for poll */
+#include <sys/mman.h>           /* for mmap */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/wait.h>           /* for waitpid macros */
+#include <locale.h>		/* for __uselocale */
+#include <resolv.h>		/* for __resp */
+
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+#include "semaphore.h"
+#include <not-cancel.h>
+
+#define __clone clone
+
+/* For debugging purposes put the maximum number of threads in a variable.  */
+const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX;
+
+#ifndef THREAD_SELF
+/* Indicate whether at least one thread has a user-defined stack (if 1),
+   or if all threads have stacks supplied by LinuxThreads (if 0). */
+int __pthread_nonstandard_stacks;
+#endif
+
+/* Number of active entries in __pthread_handles (used by gdb) */
+volatile int __pthread_handles_num = 2;
+
+/* Whether to use debugger additional actions for thread creation
+   (set to 1 by gdb) */
+volatile int __pthread_threads_debug;
+
+/* Globally enabled events.  */
+volatile td_thr_events_t __pthread_threads_events;
+
+/* Pointer to thread descriptor with last event.  */
+volatile pthread_descr __pthread_last_event;
+
+static pthread_descr manager_thread;
+
+/* Mapping from stack segment to thread descriptor. */
+/* Stack segment numbers are also indices into the __pthread_handles array. */
+/* Stack segment number 0 is reserved for the initial thread. */
+
+#if FLOATING_STACKS
+# define thread_segment(seq) NULL
+#else
+static inline pthread_descr thread_segment(int seg)
+{
+# ifdef _STACK_GROWS_UP
+  return (pthread_descr)(THREAD_STACK_START_ADDRESS + (seg - 1) * STACK_SIZE)
+         + 1;
+# else
+  return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
+         - 1;
+# endif
+}
+#endif
+
+/* Flag set in signal handler to record child termination */
+
+static volatile int terminated_children;
+
+/* Flag set when the initial thread is blocked on pthread_exit waiting
+   for all other threads to terminate */
+
+static int main_thread_exiting;
+
+/* Counter used to generate unique thread identifier.
+   Thread identifier is pthread_threads_counter + segment. */
+
+static pthread_t pthread_threads_counter;
+
+/* Forward declarations */
+
+static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
+                                 void * (*start_routine)(void *), void *arg,
+                                 sigset_t *mask, int father_pid,
+				 int report_events,
+				 td_thr_events_t *event_maskp);
+static void pthread_handle_free(pthread_t th_id);
+static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
+     __attribute__ ((noreturn));
+static void pthread_reap_children(void);
+static void pthread_kill_all_threads(int sig, int main_thread_also);
+static void pthread_for_each_thread(void *arg,
+    void (*fn)(void *, pthread_descr));
+
+/* The server thread managing requests for thread creation and termination */
+
+int
+__attribute__ ((noreturn))
+__pthread_manager(void *arg)
+{
+  pthread_descr self = manager_thread = arg;
+  int reqfd = __pthread_manager_reader;
+  struct pollfd ufd;
+  sigset_t manager_mask;
+  int n;
+  struct pthread_request request;
+
+  /* If we have special thread_self processing, initialize it.  */
+#ifdef INIT_THREAD_SELF
+  INIT_THREAD_SELF(self, 1);
+#endif
+#if !(USE_TLS && HAVE___THREAD)
+  /* Set the error variable.  */
+  self->p_errnop = &self->p_errno;
+  self->p_h_errnop = &self->p_h_errno;
+#endif
+  /* Block all signals except __pthread_sig_cancel and SIGTRAP */
+  sigfillset(&manager_mask);
+  sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
+  sigdelset(&manager_mask, SIGTRAP);            /* for debugging purposes */
+  if (__pthread_threads_debug && __pthread_sig_debug > 0)
+    sigdelset(&manager_mask, __pthread_sig_debug);
+  sigprocmask(SIG_SETMASK, &manager_mask, NULL);
+  /* Raise our priority to match that of main thread */
+  __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
+  /* Synchronize debugging of the thread manager */
+  n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request,
+					 sizeof(request)));
+  ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
+  ufd.fd = reqfd;
+  ufd.events = POLLIN;
+  /* Enter server loop */
+  while(1) {
+    n = __poll(&ufd, 1, 2000);
+
+    /* Check for termination of the main thread */
+    if (getppid() == 1) {
+      pthread_kill_all_threads(SIGKILL, 0);
+      _exit(0);
+    }
+    /* Check for dead children */
+    if (terminated_children) {
+      terminated_children = 0;
+      pthread_reap_children();
+    }
+    /* Read and execute request */
+    if (n == 1 && (ufd.revents & POLLIN)) {
+      n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request,
+					     sizeof(request)));
+#ifdef DEBUG
+      if (n < 0) {
+	char d[64];
+	write(STDERR_FILENO, d, snprintf(d, sizeof(d), "*** read err %m\n"));
+      } else if (n != sizeof(request)) {
+	write(STDERR_FILENO, "*** short read in manager\n", 26);
+      }
+#endif
+
+      switch(request.req_kind) {
+      case REQ_CREATE:
+        request.req_thread->p_retcode =
+          pthread_handle_create((pthread_t *) &request.req_thread->p_retval,
+                                request.req_args.create.attr,
+                                request.req_args.create.fn,
+                                request.req_args.create.arg,
+                                &request.req_args.create.mask,
+                                request.req_thread->p_pid,
+				request.req_thread->p_report_events,
+				&request.req_thread->p_eventbuf.eventmask);
+        restart(request.req_thread);
+        break;
+      case REQ_FREE:
+	pthread_handle_free(request.req_args.free.thread_id);
+        break;
+      case REQ_PROCESS_EXIT:
+        pthread_handle_exit(request.req_thread,
+                            request.req_args.exit.code);
+	/* NOTREACHED */
+        break;
+      case REQ_MAIN_THREAD_EXIT:
+        main_thread_exiting = 1;
+	/* Reap children in case all other threads died and the signal handler
+	   went off before we set main_thread_exiting to 1, and therefore did
+	   not do REQ_KICK. */
+	pthread_reap_children();
+
+        if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {
+          restart(__pthread_main_thread);
+	  /* The main thread will now call exit() which will trigger an
+	     __on_exit handler, which in turn will send REQ_PROCESS_EXIT
+	     to the thread manager. In case you are wondering how the
+	     manager terminates from its loop here. */
+	}
+        break;
+      case REQ_POST:
+        sem_post(request.req_args.post);
+        break;
+      case REQ_DEBUG:
+	/* Make gdb aware of new thread and gdb will restart the
+	   new thread when it is ready to handle the new thread. */
+	if (__pthread_threads_debug && __pthread_sig_debug > 0)
+	  raise(__pthread_sig_debug);
+        break;
+      case REQ_KICK:
+	/* This is just a prod to get the manager to reap some
+	   threads right away, avoiding a potential delay at shutdown. */
+	break;
+      case REQ_FOR_EACH_THREAD:
+	pthread_for_each_thread(request.req_args.for_each.arg,
+	                        request.req_args.for_each.fn);
+	restart(request.req_thread);
+	break;
+      }
+    }
+  }
+}
+
+int __pthread_manager_event(void *arg)
+{
+  pthread_descr self = arg;
+  /* If we have special thread_self processing, initialize it.  */
+#ifdef INIT_THREAD_SELF
+  INIT_THREAD_SELF(self, 1);
+#endif
+
+  /* Get the lock the manager will free once all is correctly set up.  */
+  __pthread_lock (THREAD_GETMEM(self, p_lock), NULL);
+  /* Free it immediately.  */
+  __pthread_unlock (THREAD_GETMEM(self, p_lock));
+
+  return __pthread_manager(arg);
+}
+
+/* Process creation */
+
+static int
+__attribute__ ((noreturn))
+pthread_start_thread(void *arg)
+{
+  pthread_descr self = (pthread_descr) arg;
+  struct pthread_request request;
+  void * outcome;
+#if HP_TIMING_AVAIL
+  hp_timing_t tmpclock;
+#endif
+  /* Initialize special thread_self processing, if any.  */
+#ifdef INIT_THREAD_SELF
+  INIT_THREAD_SELF(self, self->p_nr);
+#endif
+#if HP_TIMING_AVAIL
+  HP_TIMING_NOW (tmpclock);
+  THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);
+#endif
+  /* Make sure our pid field is initialized, just in case we get there
+     before our father has initialized it. */
+  THREAD_SETMEM(self, p_pid, __getpid());
+  /* Initial signal mask is that of the creating thread. (Otherwise,
+     we'd just inherit the mask of the thread manager.) */
+  sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);
+  /* Set the scheduling policy and priority for the new thread, if needed */
+  if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0)
+    /* Explicit scheduling attributes were provided: apply them */
+    __sched_setscheduler(THREAD_GETMEM(self, p_pid),
+			 THREAD_GETMEM(self, p_start_args.schedpolicy),
+                         &self->p_start_args.schedparam);
+  else if (manager_thread->p_priority > 0)
+    /* Default scheduling required, but thread manager runs in realtime
+       scheduling: switch new thread to SCHED_OTHER policy */
+    {
+      struct sched_param default_params;
+      default_params.sched_priority = 0;
+      __sched_setscheduler(THREAD_GETMEM(self, p_pid),
+                           SCHED_OTHER, &default_params);
+    }
+#if !(USE_TLS && HAVE___THREAD)
+  /* Initialize thread-locale current locale to point to the global one.
+     With __thread support, the variable's initializer takes care of this.  */
+  __uselocale (LC_GLOBAL_LOCALE);
+#else
+  /* Initialize __resp.  */
+  __resp = &self->p_res;
+#endif
+  /* Make gdb aware of new thread */
+  if (__pthread_threads_debug && __pthread_sig_debug > 0) {
+    request.req_thread = self;
+    request.req_kind = REQ_DEBUG;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *) &request, sizeof(request)));
+    suspend(self);
+  }
+  /* Run the thread code */
+  outcome = self->p_start_args.start_routine(THREAD_GETMEM(self,
+							   p_start_args.arg));
+  /* Exit with the given return value */
+  __pthread_do_exit(outcome, CURRENT_STACK_FRAME);
+}
+
+static int
+__attribute__ ((noreturn))
+pthread_start_thread_event(void *arg)
+{
+  pthread_descr self = (pthread_descr) arg;
+
+#ifdef INIT_THREAD_SELF
+  INIT_THREAD_SELF(self, self->p_nr);
+#endif
+  /* Make sure our pid field is initialized, just in case we get there
+     before our father has initialized it. */
+  THREAD_SETMEM(self, p_pid, __getpid());
+  /* Get the lock the manager will free once all is correctly set up.  */
+  __pthread_lock (THREAD_GETMEM(self, p_lock), NULL);
+  /* Free it immediately.  */
+  __pthread_unlock (THREAD_GETMEM(self, p_lock));
+
+  /* Continue with the real function.  */
+  pthread_start_thread (arg);
+}
+
+#if defined USE_TLS && !FLOATING_STACKS
+# error "TLS can only work with floating stacks"
+#endif
+
+static int pthread_allocate_stack(const pthread_attr_t *attr,
+                                  pthread_descr default_new_thread,
+                                  int pagesize,
+                                  char ** out_new_thread,
+                                  char ** out_new_thread_bottom,
+                                  char ** out_guardaddr,
+                                  size_t * out_guardsize,
+                                  size_t * out_stacksize)
+{
+  pthread_descr new_thread;
+  char * new_thread_bottom;
+  char * guardaddr;
+  size_t stacksize, guardsize;
+
+#ifdef USE_TLS
+  /* TLS cannot work with fixed thread descriptor addresses.  */
+  assert (default_new_thread == NULL);
+#endif
+
+  if (attr != NULL && attr->__stackaddr_set)
+    {
+#ifdef _STACK_GROWS_UP
+      /* The user provided a stack. */
+# ifdef USE_TLS
+      /* This value is not needed.  */
+      new_thread = (pthread_descr) attr->__stackaddr;
+      new_thread_bottom = (char *) new_thread;
+# else
+      new_thread = (pthread_descr) attr->__stackaddr;
+      new_thread_bottom = (char *) (new_thread + 1);
+# endif
+      guardaddr = attr->__stackaddr + attr->__stacksize;
+      guardsize = 0;
+#else
+      /* The user provided a stack.  For now we interpret the supplied
+	 address as 1 + the highest addr. in the stack segment.  If a
+	 separate register stack is needed, we place it at the low end
+	 of the segment, relying on the associated stacksize to
+	 determine the low end of the segment.  This differs from many
+	 (but not all) other pthreads implementations.  The intent is
+	 that on machines with a single stack growing toward higher
+	 addresses, stackaddr would be the lowest address in the stack
+	 segment, so that it is consistently close to the initial sp
+	 value. */
+# ifdef USE_TLS
+      new_thread = (pthread_descr) attr->__stackaddr;
+# else
+      new_thread =
+        (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
+# endif
+      new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
+      guardaddr = new_thread_bottom;
+      guardsize = 0;
+#endif
+#ifndef THREAD_SELF
+      __pthread_nonstandard_stacks = 1;
+#endif
+#ifndef USE_TLS
+      /* Clear the thread data structure.  */
+      memset (new_thread, '\0', sizeof (*new_thread));
+#endif
+      stacksize = attr->__stacksize;
+    }
+  else
+    {
+#ifdef NEED_SEPARATE_REGISTER_STACK
+      const size_t granularity = 2 * pagesize;
+      /* Try to make stacksize/2 a multiple of pagesize */
+#else
+      const size_t granularity = pagesize;
+#endif
+      void *map_addr;
+
+      /* Allocate space for stack and thread descriptor at default address */
+#if FLOATING_STACKS
+      if (attr != NULL)
+	{
+	  guardsize = page_roundup (attr->__guardsize, granularity);
+	  stacksize = __pthread_max_stacksize - guardsize;
+	  stacksize = MIN (stacksize,
+			   page_roundup (attr->__stacksize, granularity));
+	}
+      else
+	{
+	  guardsize = granularity;
+	  stacksize = __pthread_max_stacksize - guardsize;
+	}
+
+      map_addr = mmap(NULL, stacksize + guardsize,
+		      PROT_READ | PROT_WRITE | PROT_EXEC,
+		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (map_addr == MAP_FAILED)
+        /* No more memory available.  */
+        return -1;
+
+# ifdef NEED_SEPARATE_REGISTER_STACK
+      guardaddr = map_addr + stacksize / 2;
+      if (guardsize > 0)
+	mprotect (guardaddr, guardsize, PROT_NONE);
+
+      new_thread_bottom = (char *) map_addr;
+#  ifdef USE_TLS
+      new_thread = ((pthread_descr) (new_thread_bottom + stacksize
+				     + guardsize));
+#  else
+      new_thread = ((pthread_descr) (new_thread_bottom + stacksize
+				     + guardsize)) - 1;
+#  endif
+# elif _STACK_GROWS_DOWN
+      guardaddr = map_addr;
+      if (guardsize > 0)
+	mprotect (guardaddr, guardsize, PROT_NONE);
+
+      new_thread_bottom = (char *) map_addr + guardsize;
+#  ifdef USE_TLS
+      new_thread = ((pthread_descr) (new_thread_bottom + stacksize));
+#  else
+      new_thread = ((pthread_descr) (new_thread_bottom + stacksize)) - 1;
+#  endif
+# elif _STACK_GROWS_UP
+      guardaddr = map_addr + stacksize;
+      if (guardsize > 0)
+	mprotect (guardaddr, guardsize, PROT_NONE);
+
+      new_thread = (pthread_descr) map_addr;
+#  ifdef USE_TLS
+      new_thread_bottom = (char *) new_thread;
+#  else
+      new_thread_bottom = (char *) (new_thread + 1);
+#  endif
+# else
+#  error You must define a stack direction
+# endif /* Stack direction */
+#else /* !FLOATING_STACKS */
+# if !defined NEED_SEPARATE_REGISTER_STACK && defined _STACK_GROWS_DOWN
+      void *res_addr;
+# endif
+
+      if (attr != NULL)
+	{
+	  guardsize = page_roundup (attr->__guardsize, granularity);
+	  stacksize = STACK_SIZE - guardsize;
+	  stacksize = MIN (stacksize,
+			   page_roundup (attr->__stacksize, granularity));
+	}
+      else
+	{
+	  guardsize = granularity;
+	  stacksize = STACK_SIZE - granularity;
+	}
+
+# ifdef NEED_SEPARATE_REGISTER_STACK
+      new_thread = default_new_thread;
+      new_thread_bottom = (char *) (new_thread + 1) - stacksize - guardsize;
+      /* Includes guard area, unlike the normal case.  Use the bottom
+       end of the segment as backing store for the register stack.
+       Needed on IA64.  In this case, we also map the entire stack at
+       once.  According to David Mosberger, that's cheaper.  It also
+       avoids the risk of intermittent failures due to other mappings
+       in the same region.  The cost is that we might be able to map
+       slightly fewer stacks.  */
+
+      /* First the main stack: */
+      map_addr = (caddr_t)((char *)(new_thread + 1) - stacksize / 2);
+      res_addr = mmap(map_addr, stacksize / 2,
+		      PROT_READ | PROT_WRITE | PROT_EXEC,
+		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (res_addr != map_addr)
+	{
+	  /* Bad luck, this segment is already mapped. */
+	  if (res_addr != MAP_FAILED)
+	    munmap(res_addr, stacksize / 2);
+	  return -1;
+	}
+      /* Then the register stack:	*/
+      map_addr = (caddr_t)new_thread_bottom;
+      res_addr = mmap(map_addr, stacksize/2,
+		      PROT_READ | PROT_WRITE | PROT_EXEC,
+		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (res_addr != map_addr)
+	{
+	  if (res_addr != MAP_FAILED)
+	    munmap(res_addr, stacksize / 2);
+	  munmap((caddr_t)((char *)(new_thread + 1) - stacksize/2),
+		 stacksize/2);
+	  return -1;
+	}
+
+      guardaddr = new_thread_bottom + stacksize/2;
+      /* We leave the guard area in the middle unmapped.	*/
+# else  /* !NEED_SEPARATE_REGISTER_STACK */
+#  ifdef _STACK_GROWS_DOWN
+      new_thread = default_new_thread;
+      new_thread_bottom = (char *) (new_thread + 1) - stacksize;
+      map_addr = new_thread_bottom - guardsize;
+      res_addr = mmap(map_addr, stacksize + guardsize,
+		      PROT_READ | PROT_WRITE | PROT_EXEC,
+		      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (res_addr != map_addr)
+	{
+	  /* Bad luck, this segment is already mapped. */
+	  if (res_addr != MAP_FAILED)
+	    munmap (res_addr, stacksize + guardsize);
+	  return -1;
+	}
+
+      /* We manage to get a stack.  Protect the guard area pages if
+	 necessary.  */
+      guardaddr = map_addr;
+      if (guardsize > 0)
+	mprotect (guardaddr, guardsize, PROT_NONE);
+#  else
+      /* The thread description goes at the bottom of this area, and
+       * the stack starts directly above it.
+       */
+      new_thread = (pthread_descr)((unsigned long)default_new_thread &~ (STACK_SIZE - 1));
+      map_addr = mmap(new_thread, stacksize + guardsize,
+		      PROT_READ | PROT_WRITE | PROT_EXEC,
+		      MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      if (map_addr == MAP_FAILED)
+	  return -1;
+
+      new_thread_bottom = map_addr + sizeof(*new_thread);
+      guardaddr = map_addr + stacksize;
+      if (guardsize > 0)
+	  mprotect (guardaddr, guardsize, PROT_NONE);
+
+#  endif /* stack direction */
+# endif  /* !NEED_SEPARATE_REGISTER_STACK */
+#endif   /* !FLOATING_STACKS */
+    }
+  *out_new_thread = (char *) new_thread;
+  *out_new_thread_bottom = new_thread_bottom;
+  *out_guardaddr = guardaddr;
+  *out_guardsize = guardsize;
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  *out_stacksize = stacksize / 2;
+#else
+  *out_stacksize = stacksize;
+#endif
+  return 0;
+}
+
+static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
+				 void * (*start_routine)(void *), void *arg,
+				 sigset_t * mask, int father_pid,
+				 int report_events,
+				 td_thr_events_t *event_maskp)
+{
+  size_t sseg;
+  int pid;
+  pthread_descr new_thread;
+  char *stack_addr;
+  char * new_thread_bottom;
+  pthread_t new_thread_id;
+  char *guardaddr = NULL;
+  size_t guardsize = 0, stksize = 0;
+  int pagesize = __getpagesize();
+  int saved_errno = 0;
+
+#ifdef USE_TLS
+  new_thread = _dl_allocate_tls (NULL);
+  if (new_thread == NULL)
+    return EAGAIN;
+# if TLS_DTV_AT_TP
+  /* pthread_descr is below TP.  */
+  new_thread = (pthread_descr) ((char *) new_thread - TLS_PRE_TCB_SIZE);
+# endif
+#else
+  /* Prevent warnings.  */
+  new_thread = NULL;
+#endif
+
+  /* First check whether we have to change the policy and if yes, whether
+     we can  do this.  Normally this should be done by examining the
+     return value of the __sched_setscheduler call in pthread_start_thread
+     but this is hard to implement.  FIXME  */
+  if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0)
+    return EPERM;
+  /* Find a free segment for the thread, and allocate a stack if needed */
+  for (sseg = 2; ; sseg++)
+    {
+      if (sseg >= PTHREAD_THREADS_MAX)
+	{
+#ifdef USE_TLS
+# if TLS_DTV_AT_TP
+	  new_thread = (pthread_descr) ((char *) new_thread + TLS_PRE_TCB_SIZE);
+# endif
+	  _dl_deallocate_tls (new_thread, true);
+#endif
+	  return EAGAIN;
+	}
+      if (__pthread_handles[sseg].h_descr != NULL)
+	continue;
+      if (pthread_allocate_stack(attr, thread_segment(sseg),
+				 pagesize, &stack_addr, &new_thread_bottom,
+                                 &guardaddr, &guardsize, &stksize) == 0)
+	{
+#ifdef USE_TLS
+	  new_thread->p_stackaddr = stack_addr;
+#else
+	  new_thread = (pthread_descr) stack_addr;
+#endif
+	  break;
+#ifndef __ARCH_HAS_MMU__
+	} else {
+	  /* When there is MMU, mmap () is used to allocate the stack. If one
+	   * segment is already mapped, we should continue to see if we can
+	   * use the next one. However, when there is no MMU, malloc () is used.
+	   * It's waste of CPU cycles to continue to try if it fails.  */
+	  return EAGAIN;
+#endif
+	}
+    }
+  __pthread_handles_num++;
+  /* Allocate new thread identifier */
+  pthread_threads_counter += PTHREAD_THREADS_MAX;
+  new_thread_id = sseg + pthread_threads_counter;
+  /* Initialize the thread descriptor.  Elements which have to be
+     initialized to zero already have this value.  */
+#if !defined USE_TLS || !TLS_DTV_AT_TP
+  new_thread->p_header.data.tcb = new_thread;
+  new_thread->p_header.data.self = new_thread;
+#endif
+#if TLS_MULTIPLE_THREADS_IN_TCB || !defined USE_TLS || !TLS_DTV_AT_TP
+  new_thread->p_multiple_threads = 1;
+#endif
+  new_thread->p_tid = new_thread_id;
+  new_thread->p_lock = &(__pthread_handles[sseg].h_lock);
+  new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE;
+  new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED;
+#if !(USE_TLS && HAVE___THREAD)
+  new_thread->p_errnop = &new_thread->p_errno;
+  new_thread->p_h_errnop = &new_thread->p_h_errno;
+  new_thread->p_resp = &new_thread->p_res;
+#endif
+  new_thread->p_guardaddr = guardaddr;
+  new_thread->p_guardsize = guardsize;
+  new_thread->p_nr = sseg;
+  new_thread->p_inheritsched = attr ? attr->__inheritsched : 0;
+  new_thread->p_alloca_cutoff = stksize / 4 > __MAX_ALLOCA_CUTOFF
+				 ? __MAX_ALLOCA_CUTOFF : stksize / 4;
+  /* Initialize the thread handle */
+  __pthread_init_lock(&__pthread_handles[sseg].h_lock);
+  __pthread_handles[sseg].h_descr = new_thread;
+  __pthread_handles[sseg].h_bottom = new_thread_bottom;
+  /* Determine scheduling parameters for the thread */
+  new_thread->p_start_args.schedpolicy = -1;
+  if (attr != NULL) {
+    new_thread->p_detached = attr->__detachstate;
+    new_thread->p_userstack = attr->__stackaddr_set;
+
+    switch(attr->__inheritsched) {
+    case PTHREAD_EXPLICIT_SCHED:
+      new_thread->p_start_args.schedpolicy = attr->__schedpolicy;
+      memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam,
+	      sizeof (struct sched_param));
+      break;
+    case PTHREAD_INHERIT_SCHED:
+      new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
+      __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
+      break;
+    }
+    new_thread->p_priority =
+      new_thread->p_start_args.schedparam.sched_priority;
+  }
+  /* Finish setting up arguments to pthread_start_thread */
+  new_thread->p_start_args.start_routine = start_routine;
+  new_thread->p_start_args.arg = arg;
+  new_thread->p_start_args.mask = *mask;
+  /* Make the new thread ID available already now.  If any of the later
+     functions fail we return an error value and the caller must not use
+     the stored thread ID.  */
+  *thread = new_thread_id;
+  /* Raise priority of thread manager if needed */
+  __pthread_manager_adjust_prio(new_thread->p_priority);
+  /* Do the cloning.  We have to use two different functions depending
+     on whether we are debugging or not.  */
+  pid = 0;	/* Note that the thread never can have PID zero.  */
+  if (report_events)
+    {
+      /* See whether the TD_CREATE event bit is set in any of the
+         masks.  */
+      int idx = __td_eventword (TD_CREATE);
+      uint32_t mask = __td_eventmask (TD_CREATE);
+
+      if ((mask & (__pthread_threads_events.event_bits[idx]
+		   | event_maskp->event_bits[idx])) != 0)
+	{
+	  /* Lock the mutex the child will use now so that it will stop.  */
+	  __pthread_lock(new_thread->p_lock, NULL);
+
+	  /* We have to report this event.  */
+#ifdef NEED_SEPARATE_REGISTER_STACK
+	  /* Perhaps this version should be used on all platforms. But
+	   this requires that __clone2 be uniformly supported
+	   everywhere.
+
+	   And there is some argument for changing the __clone2
+	   interface to pass sp and bsp instead, making it more IA64
+	   specific, but allowing stacks to grow outward from each
+	   other, to get less paging and fewer mmaps.  */
+	  pid = __clone2(pthread_start_thread_event,
+  		 (void **)new_thread_bottom,
+			 (char *)stack_addr - new_thread_bottom,
+			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			 __pthread_sig_cancel, new_thread);
+#elif _STACK_GROWS_UP
+	  pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom,
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			__pthread_sig_cancel, new_thread);
+#else
+	  pid = __clone(pthread_start_thread_event, stack_addr,
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			__pthread_sig_cancel, new_thread);
+#endif
+	  saved_errno = errno;
+	  if (pid != -1)
+	    {
+	      /* 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.  */
+	      new_thread->p_eventbuf.eventdata = new_thread;
+	      new_thread->p_eventbuf.eventnum = TD_CREATE;
+	      __pthread_last_event = new_thread;
+
+	      /* We have to set the PID here since the callback function
+		 in the debug library will need it and we cannot guarantee
+		 the child got scheduled before the debugger.  */
+	      new_thread->p_pid = pid;
+
+	      /* Now call the function which signals the event.  */
+	      __linuxthreads_create_event ();
+
+	      /* Now restart the thread.  */
+	      __pthread_unlock(new_thread->p_lock);
+	    }
+	}
+    }
+  if (pid == 0)
+    {
+#ifdef NEED_SEPARATE_REGISTER_STACK
+      pid = __clone2(pthread_start_thread,
+		     (void **)new_thread_bottom,
+                     (char *)stack_addr - new_thread_bottom,
+		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		     __pthread_sig_cancel, new_thread);
+#elif _STACK_GROWS_UP
+      pid = __clone(pthread_start_thread, (void *) new_thread_bottom,
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		    __pthread_sig_cancel, new_thread);
+#else
+      pid = __clone(pthread_start_thread, stack_addr,
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		    __pthread_sig_cancel, new_thread);
+#endif /* !NEED_SEPARATE_REGISTER_STACK */
+      saved_errno = errno;
+    }
+  /* Check if cloning succeeded */
+  if (pid == -1) {
+    /* Free the stack if we allocated it */
+    if (attr == NULL || !attr->__stackaddr_set)
+      {
+#ifdef NEED_SEPARATE_REGISTER_STACK
+	size_t stacksize = ((char *)(new_thread->p_guardaddr)
+			    - new_thread_bottom);
+	munmap((caddr_t)new_thread_bottom,
+	       2 * stacksize + new_thread->p_guardsize);
+#elif _STACK_GROWS_UP
+# ifdef USE_TLS
+	size_t stacksize = guardaddr - stack_addr;
+	munmap(stack_addr, stacksize + guardsize);
+# else
+	size_t stacksize = guardaddr - (char *)new_thread;
+	munmap(new_thread, stacksize + guardsize);
+# endif
+#else
+# ifdef USE_TLS
+	size_t stacksize = stack_addr - new_thread_bottom;
+# else
+	size_t stacksize = (char *)(new_thread+1) - new_thread_bottom;
+# endif
+	munmap(new_thread_bottom - guardsize, guardsize + stacksize);
+#endif
+      }
+#ifdef USE_TLS
+# if TLS_DTV_AT_TP
+    new_thread = (pthread_descr) ((char *) new_thread + TLS_PRE_TCB_SIZE);
+# endif
+    _dl_deallocate_tls (new_thread, true);
+#endif
+    __pthread_handles[sseg].h_descr = NULL;
+    __pthread_handles[sseg].h_bottom = NULL;
+    __pthread_handles_num--;
+    return saved_errno;
+  }
+  /* Insert new thread in doubly linked list of active threads */
+  new_thread->p_prevlive = __pthread_main_thread;
+  new_thread->p_nextlive = __pthread_main_thread->p_nextlive;
+  __pthread_main_thread->p_nextlive->p_prevlive = new_thread;
+  __pthread_main_thread->p_nextlive = new_thread;
+  /* Set pid field of the new thread, in case we get there before the
+     child starts. */
+  new_thread->p_pid = pid;
+  return 0;
+}
+
+
+/* Try to free the resources of a thread when requested by pthread_join
+   or pthread_detach on a terminated thread. */
+
+static void pthread_free(pthread_descr th)
+{
+  pthread_handle handle;
+  pthread_readlock_info *iter, *next;
+
+  ASSERT(th->p_exited);
+  /* Make the handle invalid */
+  handle =  thread_handle(th->p_tid);
+  __pthread_lock(&handle->h_lock, NULL);
+  handle->h_descr = NULL;
+  handle->h_bottom = (char *)(-1L);
+  __pthread_unlock(&handle->h_lock);
+#ifdef FREE_THREAD
+  FREE_THREAD(th, th->p_nr);
+#endif
+  /* One fewer threads in __pthread_handles */
+  __pthread_handles_num--;
+
+  /* Destroy read lock list, and list of free read lock structures.
+     If the former is not empty, it means the thread exited while
+     holding read locks! */
+
+  for (iter = th->p_readlock_list; iter != NULL; iter = next)
+    {
+      next = iter->pr_next;
+      free(iter);
+    }
+
+  for (iter = th->p_readlock_free; iter != NULL; iter = next)
+    {
+      next = iter->pr_next;
+      free(iter);
+    }
+
+  /* If initial thread, nothing to free */
+  if (!th->p_userstack)
+    {
+      size_t guardsize = th->p_guardsize;
+      /* Free the stack and thread descriptor area */
+      char *guardaddr = th->p_guardaddr;
+#ifdef _STACK_GROWS_UP
+# ifdef USE_TLS
+      size_t stacksize = guardaddr - th->p_stackaddr;
+# else
+      size_t stacksize = guardaddr - (char *)th;
+# endif
+      guardaddr = (char *)th;
+#else
+      /* Guardaddr is always set, even if guardsize is 0.  This allows
+	 us to compute everything else.  */
+# ifdef USE_TLS
+      size_t stacksize = th->p_stackaddr - guardaddr - guardsize;
+# else
+      size_t stacksize = (char *)(th+1) - guardaddr - guardsize;
+# endif
+# ifdef NEED_SEPARATE_REGISTER_STACK
+      /* Take account of the register stack, which is below guardaddr.  */
+      guardaddr -= stacksize;
+      stacksize *= 2;
+# endif
+#endif
+      /* Unmap the stack.  */
+      munmap(guardaddr, stacksize + guardsize);
+
+    }
+
+#ifdef USE_TLS
+# if TLS_DTV_AT_TP
+  th = (pthread_descr) ((char *) th + TLS_PRE_TCB_SIZE);
+# endif
+  _dl_deallocate_tls (th, true);
+#endif
+}
+
+/* Handle threads that have exited */
+
+static void pthread_exited(pid_t pid)
+{
+  pthread_descr th;
+  int detached;
+  /* Find thread with that pid */
+  for (th = __pthread_main_thread->p_nextlive;
+       th != __pthread_main_thread;
+       th = th->p_nextlive) {
+    if (th->p_pid == pid) {
+      /* Remove thread from list of active threads */
+      th->p_nextlive->p_prevlive = th->p_prevlive;
+      th->p_prevlive->p_nextlive = th->p_nextlive;
+      /* Mark thread as exited, and if detached, free its resources */
+      __pthread_lock(th->p_lock, NULL);
+      th->p_exited = 1;
+      /* If we have to signal this event do it now.  */
+      if (th->p_report_events)
+	{
+	  /* See whether TD_REAP is in any of the mask.  */
+	  int idx = __td_eventword (TD_REAP);
+	  uint32_t mask = __td_eventmask (TD_REAP);
+
+	  if ((mask & (__pthread_threads_events.event_bits[idx]
+		       | th->p_eventbuf.eventmask.event_bits[idx])) != 0)
+	    {
+	      /* Yep, we have to signal the reapage.  */
+	      th->p_eventbuf.eventnum = TD_REAP;
+	      th->p_eventbuf.eventdata = th;
+	      __pthread_last_event = th;
+
+	      /* Now call the function to signal the event.  */
+	      __linuxthreads_reap_event();
+	    }
+	}
+      detached = th->p_detached;
+      __pthread_unlock(th->p_lock);
+      if (detached)
+	pthread_free(th);
+      break;
+    }
+  }
+  /* If all threads have exited and the main thread is pending on a
+     pthread_exit, wake up the main thread and terminate ourselves. */
+  if (main_thread_exiting &&
+      __pthread_main_thread->p_nextlive == __pthread_main_thread) {
+    restart(__pthread_main_thread);
+    /* Same logic as REQ_MAIN_THREAD_EXIT. */
+  }
+}
+
+static void pthread_reap_children(void)
+{
+  pid_t pid;
+  int status;
+
+  while ((pid = waitpid_not_cancel(-1, &status, WNOHANG | __WCLONE)) > 0) {
+    pthread_exited(pid);
+    if (WIFSIGNALED(status)) {
+      /* If a thread died due to a signal, send the same signal to
+         all other threads, including the main thread. */
+      pthread_kill_all_threads(WTERMSIG(status), 1);
+      _exit(0);
+    }
+  }
+}
+
+/* Try to free the resources of a thread when requested by pthread_join
+   or pthread_detach on a terminated thread. */
+
+static void pthread_handle_free(pthread_t th_id)
+{
+  pthread_handle handle = thread_handle(th_id);
+  pthread_descr th;
+
+  __pthread_lock(&handle->h_lock, NULL);
+  if (nonexisting_handle(handle, th_id)) {
+    /* pthread_reap_children has deallocated the thread already,
+       nothing needs to be done */
+    __pthread_unlock(&handle->h_lock);
+    return;
+  }
+  th = handle->h_descr;
+  if (th->p_exited) {
+    __pthread_unlock(&handle->h_lock);
+    pthread_free(th);
+  } else {
+    /* The Unix process of the thread is still running.
+       Mark the thread as detached so that the thread manager will
+       deallocate its resources when the Unix process exits. */
+    th->p_detached = 1;
+    __pthread_unlock(&handle->h_lock);
+  }
+}
+
+/* Send a signal to all running threads */
+
+static void pthread_kill_all_threads(int sig, int main_thread_also)
+{
+  pthread_descr th;
+  for (th = __pthread_main_thread->p_nextlive;
+       th != __pthread_main_thread;
+       th = th->p_nextlive) {
+    kill(th->p_pid, sig);
+  }
+  if (main_thread_also) {
+    kill(__pthread_main_thread->p_pid, sig);
+  }
+}
+
+static void pthread_for_each_thread(void *arg,
+    void (*fn)(void *, pthread_descr))
+{
+  pthread_descr th;
+
+  for (th = __pthread_main_thread->p_nextlive;
+       th != __pthread_main_thread;
+       th = th->p_nextlive) {
+    fn(arg, th);
+  }
+
+  fn(arg, __pthread_main_thread);
+}
+
+/* Process-wide exit() */
+
+static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
+{
+  pthread_descr th;
+  __pthread_exit_requested = 1;
+  __pthread_exit_code = exitcode;
+  /* A forced asynchronous cancellation follows.  Make sure we won't
+     get stuck later in the main thread with a system lock being held
+     by one of the cancelled threads.  Ideally one would use the same
+     code as in pthread_atfork(), but we can't distinguish system and
+     user handlers there.  */
+  __flockfilelist();
+  /* Send the CANCEL signal to all running threads, including the main
+     thread, but excluding the thread from which the exit request originated
+     (that thread must complete the exit, e.g. calling atexit functions
+     and flushing stdio buffers). */
+  for (th = issuing_thread->p_nextlive;
+       th != issuing_thread;
+       th = th->p_nextlive) {
+    kill(th->p_pid, __pthread_sig_cancel);
+  }
+  /* Now, wait for all these threads, so that they don't become zombies
+     and their times are properly added to the thread manager's times. */
+  for (th = issuing_thread->p_nextlive;
+       th != issuing_thread;
+       th = th->p_nextlive) {
+    waitpid(th->p_pid, NULL, __WCLONE);
+  }
+  __fresetlockfiles();
+  restart(issuing_thread);
+  _exit(0);
+}
+
+/* Handler for __pthread_sig_cancel in thread manager thread */
+
+void __pthread_manager_sighandler(int sig)
+{
+  int kick_manager = terminated_children == 0 && main_thread_exiting;
+  terminated_children = 1;
+
+  /* If the main thread is terminating, kick the thread manager loop
+     each time some threads terminate. This eliminates a two second
+     shutdown delay caused by the thread manager sleeping in the
+     call to __poll(). Instead, the thread manager is kicked into
+     action, reaps the outstanding threads and resumes the main thread
+     so that it can complete the shutdown. */
+
+  if (kick_manager) {
+    struct pthread_request request;
+    request.req_thread = 0;
+    request.req_kind = REQ_KICK;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *) &request, sizeof(request)));
+  }
+}
+
+/* Adjust priority of thread manager so that it always run at a priority
+   higher than all threads */
+
+void __pthread_manager_adjust_prio(int thread_prio)
+{
+  struct sched_param param;
+
+  if (thread_prio <= manager_thread->p_priority) return;
+  param.sched_priority =
+    thread_prio < __sched_get_priority_max(SCHED_FIFO)
+    ? thread_prio + 1 : thread_prio;
+  __sched_setscheduler(manager_thread->p_pid, SCHED_FIFO, &param);
+  manager_thread->p_priority = thread_prio;
+}

+ 362 - 0
libpthread/linuxthreads/mutex.c

@@ -0,0 +1,362 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Mutexes */
+
+#include <bits/libc-lock.h>
+#include <errno.h>
+#include <sched.h>
+#include <stddef.h>
+#include <limits.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "queue.h"
+#include "restart.h"
+
+int __pthread_mutex_init(pthread_mutex_t * mutex,
+                       const pthread_mutexattr_t * mutex_attr)
+{
+  __pthread_init_lock(&mutex->__m_lock);
+  mutex->__m_kind =
+    mutex_attr == NULL ? PTHREAD_MUTEX_TIMED_NP : mutex_attr->__mutexkind;
+  mutex->__m_count = 0;
+  mutex->__m_owner = NULL;
+  return 0;
+}
+strong_alias (__pthread_mutex_init, pthread_mutex_init)
+libc_hidden_def (__pthread_mutex_init)
+
+int __pthread_mutex_destroy(pthread_mutex_t * mutex)
+{
+  switch (mutex->__m_kind) {
+  case PTHREAD_MUTEX_ADAPTIVE_NP:
+  case PTHREAD_MUTEX_RECURSIVE_NP:
+    if ((mutex->__m_lock.__status & 1) != 0)
+      return EBUSY;
+    return 0;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+  case PTHREAD_MUTEX_TIMED_NP:
+    if (mutex->__m_lock.__status != 0)
+      return EBUSY;
+    return 0;
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
+libc_hidden_def (__pthread_mutex_destroy)
+
+int __pthread_mutex_trylock(pthread_mutex_t * mutex)
+{
+  pthread_descr self;
+  int retcode;
+
+  switch(mutex->__m_kind) {
+  case PTHREAD_MUTEX_ADAPTIVE_NP:
+    retcode = __pthread_trylock(&mutex->__m_lock);
+    return retcode;
+  case PTHREAD_MUTEX_RECURSIVE_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) {
+      mutex->__m_count++;
+      return 0;
+    }
+    retcode = __pthread_trylock(&mutex->__m_lock);
+    if (retcode == 0) {
+      mutex->__m_owner = self;
+      mutex->__m_count = 0;
+    }
+    return retcode;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    retcode = __pthread_alt_trylock(&mutex->__m_lock);
+    if (retcode == 0) {
+      mutex->__m_owner = thread_self();
+    }
+    return retcode;
+  case PTHREAD_MUTEX_TIMED_NP:
+    retcode = __pthread_alt_trylock(&mutex->__m_lock);
+    return retcode;
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
+libc_hidden_def (__pthread_mutex_trylock)
+
+int __pthread_mutex_lock(pthread_mutex_t * mutex)
+{
+  pthread_descr self;
+
+  switch(mutex->__m_kind) {
+  case PTHREAD_MUTEX_ADAPTIVE_NP:
+    __pthread_lock(&mutex->__m_lock, NULL);
+    return 0;
+  case PTHREAD_MUTEX_RECURSIVE_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) {
+      mutex->__m_count++;
+      return 0;
+    }
+    __pthread_lock(&mutex->__m_lock, self);
+    mutex->__m_owner = self;
+    mutex->__m_count = 0;
+    return 0;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) return EDEADLK;
+    __pthread_alt_lock(&mutex->__m_lock, self);
+    mutex->__m_owner = self;
+    return 0;
+  case PTHREAD_MUTEX_TIMED_NP:
+    __pthread_alt_lock(&mutex->__m_lock, NULL);
+    return 0;
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
+libc_hidden_def (__pthread_mutex_lock)
+
+int __pthread_mutex_timedlock (pthread_mutex_t *mutex,
+			       const struct timespec *abstime)
+{
+  pthread_descr self;
+  int res;
+
+  if (__builtin_expect (abstime->tv_nsec, 0) < 0
+      || __builtin_expect (abstime->tv_nsec, 0) >= 1000000000)
+    return EINVAL;
+
+  switch(mutex->__m_kind) {
+  case PTHREAD_MUTEX_ADAPTIVE_NP:
+    __pthread_lock(&mutex->__m_lock, NULL);
+    return 0;
+  case PTHREAD_MUTEX_RECURSIVE_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) {
+      mutex->__m_count++;
+      return 0;
+    }
+    __pthread_lock(&mutex->__m_lock, self);
+    mutex->__m_owner = self;
+    mutex->__m_count = 0;
+    return 0;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    self = thread_self();
+    if (mutex->__m_owner == self) return EDEADLK;
+    res = __pthread_alt_timedlock(&mutex->__m_lock, self, abstime);
+    if (res != 0)
+      {
+	mutex->__m_owner = self;
+	return 0;
+      }
+    return ETIMEDOUT;
+  case PTHREAD_MUTEX_TIMED_NP:
+    /* Only this type supports timed out lock. */
+    return (__pthread_alt_timedlock(&mutex->__m_lock, NULL, abstime)
+	    ? 0 : ETIMEDOUT);
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock)
+
+int __pthread_mutex_unlock(pthread_mutex_t * mutex)
+{
+  switch (mutex->__m_kind) {
+  case PTHREAD_MUTEX_ADAPTIVE_NP:
+    __pthread_unlock(&mutex->__m_lock);
+    return 0;
+  case PTHREAD_MUTEX_RECURSIVE_NP:
+    if (mutex->__m_owner != thread_self())
+      return EPERM;
+    if (mutex->__m_count > 0) {
+      mutex->__m_count--;
+      return 0;
+    }
+    mutex->__m_owner = NULL;
+    __pthread_unlock(&mutex->__m_lock);
+    return 0;
+  case PTHREAD_MUTEX_ERRORCHECK_NP:
+    if (mutex->__m_owner != thread_self() || mutex->__m_lock.__status == 0)
+      return EPERM;
+    mutex->__m_owner = NULL;
+    __pthread_alt_unlock(&mutex->__m_lock);
+    return 0;
+  case PTHREAD_MUTEX_TIMED_NP:
+    __pthread_alt_unlock(&mutex->__m_lock);
+    return 0;
+  default:
+    return EINVAL;
+  }
+}
+strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
+libc_hidden_def (__pthread_mutex_unlock)
+
+int __pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+  attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP;
+  return 0;
+}
+strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
+
+int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+  return 0;
+}
+strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
+
+int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind)
+{
+  if (kind != PTHREAD_MUTEX_ADAPTIVE_NP
+      && kind != PTHREAD_MUTEX_RECURSIVE_NP
+      && kind != PTHREAD_MUTEX_ERRORCHECK_NP
+      && kind != PTHREAD_MUTEX_TIMED_NP)
+    return EINVAL;
+  attr->__mutexkind = kind;
+  return 0;
+}
+weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype)
+strong_alias ( __pthread_mutexattr_settype, __pthread_mutexattr_setkind_np)
+weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np)
+
+int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind)
+{
+  *kind = attr->__mutexkind;
+  return 0;
+}
+weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype)
+strong_alias (__pthread_mutexattr_gettype, __pthread_mutexattr_getkind_np)
+weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np)
+
+int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr,
+				   int *pshared)
+{
+  *pshared = PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+weak_alias (__pthread_mutexattr_getpshared, pthread_mutexattr_getpshared)
+
+int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared)
+{
+  if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
+    return EINVAL;
+
+  /* For now it is not possible to shared a conditional variable.  */
+  if (pshared != PTHREAD_PROCESS_PRIVATE)
+    return ENOSYS;
+
+  return 0;
+}
+weak_alias (__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared)
+
+/* Once-only execution */
+
+static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER;
+static int fork_generation = 0;	/* Child process increments this after fork. */
+
+enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 };
+
+/* If a thread is canceled while calling the init_routine out of
+   pthread once, this handler will reset the once_control variable
+   to the NEVER state. */
+
+static void pthread_once_cancelhandler(void *arg)
+{
+    pthread_once_t *once_control = arg;
+
+    pthread_mutex_lock(&once_masterlock);
+    *once_control = NEVER;
+    pthread_mutex_unlock(&once_masterlock);
+    pthread_cond_broadcast(&once_finished);
+}
+
+int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void))
+{
+  /* flag for doing the condition broadcast outside of mutex */
+  int state_changed;
+
+  /* Test without locking first for speed */
+  if (*once_control == DONE) {
+    READ_MEMORY_BARRIER();
+    return 0;
+  }
+  /* Lock and test again */
+
+  state_changed = 0;
+
+  pthread_mutex_lock(&once_masterlock);
+
+  /* If this object was left in an IN_PROGRESS state in a parent
+     process (indicated by stale generation field), reset it to NEVER. */
+  if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation)
+    *once_control = NEVER;
+
+  /* If init_routine is being called from another routine, wait until
+     it completes. */
+  while ((*once_control & 3) == IN_PROGRESS) {
+    pthread_cond_wait(&once_finished, &once_masterlock);
+  }
+  /* Here *once_control is stable and either NEVER or DONE. */
+  if (*once_control == NEVER) {
+    *once_control = IN_PROGRESS | fork_generation;
+    pthread_mutex_unlock(&once_masterlock);
+    pthread_cleanup_push(pthread_once_cancelhandler, once_control);
+    init_routine();
+    pthread_cleanup_pop(0);
+    pthread_mutex_lock(&once_masterlock);
+    WRITE_MEMORY_BARRIER();
+    *once_control = DONE;
+    state_changed = 1;
+  }
+  pthread_mutex_unlock(&once_masterlock);
+
+  if (state_changed)
+    pthread_cond_broadcast(&once_finished);
+
+  return 0;
+}
+strong_alias (__pthread_once, pthread_once)
+
+/*
+ * Handle the state of the pthread_once mechanism across forks.  The
+ * once_masterlock is acquired in the parent process prior to a fork to ensure
+ * that no thread is in the critical region protected by the lock.  After the
+ * fork, the lock is released. In the child, the lock and the condition
+ * variable are simply reset.  The child also increments its generation
+ * counter which lets pthread_once calls detect stale IN_PROGRESS states
+ * and reset them back to NEVER.
+ */
+
+void __pthread_once_fork_prepare(void)
+{
+  pthread_mutex_lock(&once_masterlock);
+}
+
+void __pthread_once_fork_parent(void)
+{
+  pthread_mutex_unlock(&once_masterlock);
+}
+
+void __pthread_once_fork_child(void)
+{
+  pthread_mutex_init(&once_masterlock, NULL);
+  pthread_cond_init(&once_finished, NULL);
+  if (fork_generation <= INT_MAX - 4)
+    fork_generation += 4;	/* leave least significant two bits zero */
+  else
+    fork_generation = 0;
+}

+ 25 - 0
libpthread/linuxthreads/pt-machine.c

@@ -0,0 +1,25 @@
+/* "Instantiation of machine-dependent pthreads inline functions.
+   Copyright (C) 1998 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.  */
+
+#define PT_EI
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+#include <pt-machine.h>

+ 75 - 0
libpthread/linuxthreads/ptcleanup.c

@@ -0,0 +1,75 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)	        */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Redefine siglongjmp and longjmp so that they interact correctly
+   with cleanup handlers */
+
+#define NO_PTR_DEMANGLE
+
+#include <setjmp.h>
+#include "pthread.h"
+#include "internals.h"
+#include <sysdep.h>
+#ifndef NO_PTR_DEMANGLE
+#include <jmpbuf-unwind.h>
+#define __JMPBUF_UNWINDS(a,b,c) _JMPBUF_UNWINDS(a,b,c)
+#else
+#define __JMPBUF_UNWINDS(a,b,c) _JMPBUF_UNWINDS(a,b)
+#endif
+
+#ifndef NO_PTR_DEMANGLE
+static inline uintptr_t
+demangle_ptr (uintptr_t x)
+{
+#ifdef PTR_DEMANGLE
+  PTR_DEMANGLE (x);
+#endif
+  return x;
+}
+#else
+#define demangle_ptr(x) x
+#endif
+
+void __pthread_cleanup_upto (__jmp_buf target, char *targetframe)
+{
+  pthread_descr self = thread_self();
+  struct _pthread_cleanup_buffer * c;
+
+  for (c = THREAD_GETMEM(self, p_cleanup);
+       c != NULL && __JMPBUF_UNWINDS(target, c, demangle_ptr);
+       c = c->__prev)
+    {
+#if _STACK_GROWS_DOWN
+      if ((char *) c <= targetframe)
+	{
+	  c = NULL;
+	  break;
+	}
+#elif _STACK_GROWS_UP
+      if ((char *) c >= targetframe)
+	{
+	  c = NULL;
+	  break;
+	}
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+      c->__routine(c->__arg);
+    }
+  THREAD_SETMEM(self, p_cleanup, c);
+  if (THREAD_GETMEM(self, p_in_sighandler)
+      && __JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler),
+			 demangle_ptr))
+    THREAD_SETMEM(self, p_in_sighandler, NULL);
+}

+ 69 - 0
libpthread/linuxthreads/ptclock_gettime.c

@@ -0,0 +1,69 @@
+/* Copyright (C) 2001, 2004 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 <time.h>
+#include <libc-internal.h>
+#include "internals.h"
+#include "spinlock.h"
+
+
+#if HP_TIMING_AVAIL
+int
+__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
+			 struct timespec *tp)
+{
+  hp_timing_t tsc, cpuclock_offset;
+  pthread_descr self = thread_self ();
+  pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
+  const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE;
+
+  if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread)
+    cpuclock_offset = THREAD_GETMEM (self, p_cpuclock_offset);
+  else
+    {
+      pthread_descr th;
+      pthread_handle handle = thread_handle (thread);
+      __pthread_lock (&handle->h_lock, NULL);
+      th = handle->h_descr;
+      if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated)
+	{
+	  __pthread_unlock (&handle->h_lock);
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+      cpuclock_offset = th->p_cpuclock_offset;
+      __pthread_unlock (&handle->h_lock);
+   }
+
+  /* Get the current counter.  */
+  HP_TIMING_NOW (tsc);
+
+  /* Compute the offset since the start time of the process.  */
+  tsc -= cpuclock_offset;
+
+  /* Compute the seconds.  */
+  tp->tv_sec = tsc / freq;
+
+  /* And the nanoseconds.  This computation should be stable until
+     we get machines with about 16GHz frequency.  */
+  tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq;
+
+  return 0;
+}
+#endif

+ 55 - 0
libpthread/linuxthreads/ptclock_settime.c

@@ -0,0 +1,55 @@
+/* Copyright (C) 2001, 2004 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 <time.h>
+#include <libc-internal.h>
+#include "internals.h"
+#include "spinlock.h"
+
+
+#if HP_TIMING_AVAIL
+int
+__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset)
+{
+  pthread_descr self = thread_self ();
+  pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
+  const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE;
+
+  if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread)
+    /* Our own clock.  */
+    THREAD_SETMEM (self, p_cpuclock_offset, offset);
+  else
+    {
+      pthread_descr th;
+      pthread_handle handle = thread_handle (thread);
+      __pthread_lock (&handle->h_lock, NULL);
+      th = handle->h_descr;
+      if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated)
+	{
+	  __pthread_unlock (&handle->h_lock);
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+      th->p_cpuclock_offset = offset;
+      __pthread_unlock (&handle->h_lock);
+   }
+
+  return 0;
+}
+#endif

+ 93 - 0
libpthread/linuxthreads/ptfork.c

@@ -0,0 +1,93 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* The "atfork" stuff */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "pthread.h"
+#include "internals.h"
+#include <bits/libc-lock.h>
+#include "fork.h"
+
+extern int __libc_fork (void);
+
+pid_t __pthread_fork (struct fork_block *b)
+{
+  pid_t pid;
+  list_t *runp;
+
+  __libc_lock_lock (b->lock);
+
+  /* Run all the registered preparation handlers.  In reverse order.  */
+  list_for_each_prev (runp, &b->prepare_list)
+    {
+      struct fork_handler *curp;
+      curp = list_entry (runp, struct fork_handler, list);
+      curp->handler ();
+    }
+
+  __pthread_once_fork_prepare();
+  __flockfilelist();
+
+  pid = ARCH_FORK ();
+
+  if (pid == 0) {
+    __pthread_reset_main_thread();
+
+    __fresetlockfiles();
+    __pthread_once_fork_child();
+
+    /* Run the handlers registered for the child.  */
+    list_for_each (runp, &b->child_list)
+      {
+	struct fork_handler *curp;
+	curp = list_entry (runp, struct fork_handler, list);
+	curp->handler ();
+      }
+
+    __libc_lock_init (b->lock);
+  } else {
+    __funlockfilelist();
+    __pthread_once_fork_parent();
+
+    /* Run the handlers registered for the parent.  */
+    list_for_each (runp, &b->parent_list)
+      {
+	struct fork_handler *curp;
+	curp = list_entry (runp, struct fork_handler, list);
+	curp->handler ();
+      }
+
+    __libc_lock_unlock (b->lock);
+  }
+
+  return pid;
+}
+
+#ifdef SHARED
+pid_t __fork (void)
+{
+  return __libc_fork ();
+}
+weak_alias (__fork, fork);
+
+pid_t __vfork(void)
+{
+  return __libc_fork ();
+}
+weak_alias (__vfork, vfork);
+#endif

+ 5 - 0
libpthread/linuxthreads/pthandles.c

@@ -0,0 +1,5 @@
+#include "pthread.h"
+#include "internals.h"
+
+/* Array of active threads. Entry 0 is reserved for the initial thread. */
+struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX];

+ 1379 - 0
libpthread/linuxthreads/pthread.c

@@ -0,0 +1,1379 @@
+
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Thread creation, initialization, and basic low-level routines */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+#include "smp.h"
+#include <not-cancel.h>
+
+#define __clone clone
+
+/* Sanity check.  */
+#if !defined __SIGRTMIN || (__SIGRTMAX - __SIGRTMIN) < 3
+# error "This must not happen"
+#endif
+
+/* mods for uClibc: __libc_sigaction is not in any standard headers */
+extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact);
+extern int __cxa_atexit (void (*func) (void *), void *arg, void *d);
+
+#if !(USE_TLS && HAVE___THREAD)
+/* These variables are used by the setup code.  */
+extern int _errno;
+extern int _h_errno;
+
+/* We need the global/static resolver state here.  */
+# include <resolv.h>
+# undef _res
+
+extern struct __res_state _res;
+#endif
+
+#ifdef USE_TLS
+
+/* We need only a few variables.  */
+#define manager_thread __pthread_manager_threadp
+pthread_descr __pthread_manager_threadp attribute_hidden;
+
+#else
+
+/* Descriptor of the initial thread */
+
+struct _pthread_descr_struct __pthread_initial_thread = {
+  .p_header.data.self = &__pthread_initial_thread,
+  .p_nextlive = &__pthread_initial_thread,
+  .p_prevlive = &__pthread_initial_thread,
+  .p_tid = PTHREAD_THREADS_MAX,
+  .p_lock = &__pthread_handles[0].h_lock,
+  .p_start_args = PTHREAD_START_ARGS_INITIALIZER(NULL),
+#if !(USE_TLS && HAVE___THREAD)
+  .p_errnop = &_errno,
+  .p_h_errnop = &_h_errno,
+  .p_resp = &_res,
+#endif
+  .p_userstack = 1,
+  .p_resume_count = __ATOMIC_INITIALIZER,
+  .p_alloca_cutoff = __MAX_ALLOCA_CUTOFF
+};
+
+/* Descriptor of the manager thread; none of this is used but the error
+   variables, the p_pid and p_priority fields,
+   and the address for identification.  */
+
+#define manager_thread (&__pthread_manager_thread)
+struct _pthread_descr_struct __pthread_manager_thread = {
+  .p_header.data.self = &__pthread_manager_thread,
+  .p_header.data.multiple_threads = 1,
+  .p_lock = &__pthread_handles[1].h_lock,
+  .p_start_args = PTHREAD_START_ARGS_INITIALIZER(__pthread_manager),
+#if !(USE_TLS && HAVE___THREAD)
+  .p_errnop = &__pthread_manager_thread.p_errno,
+#endif
+  .p_nr = 1,
+  .p_resume_count = __ATOMIC_INITIALIZER,
+  .p_alloca_cutoff = PTHREAD_STACK_MIN / 4
+};
+#endif
+
+/* Pointer to the main thread (the father of the thread manager thread) */
+/* Originally, this is the initial thread, but this changes after fork() */
+
+#ifdef USE_TLS
+pthread_descr __pthread_main_thread;
+#else
+pthread_descr __pthread_main_thread = &__pthread_initial_thread;
+#endif
+
+/* Limit between the stack of the initial thread (above) and the
+   stacks of other threads (below). Aligned on a STACK_SIZE boundary. */
+
+char *__pthread_initial_thread_bos;
+
+/* File descriptor for sending requests to the thread manager. */
+/* Initially -1, meaning that the thread manager is not running. */
+
+int __pthread_manager_request = -1;
+
+int __pthread_multiple_threads attribute_hidden;
+
+/* Other end of the pipe for sending requests to the thread manager. */
+
+int __pthread_manager_reader;
+
+/* Limits of the thread manager stack */
+
+char *__pthread_manager_thread_bos;
+char *__pthread_manager_thread_tos;
+
+/* For process-wide exit() */
+
+int __pthread_exit_requested;
+int __pthread_exit_code;
+
+/* Maximum stack size.  */
+size_t __pthread_max_stacksize;
+
+/* Nozero if the machine has more than one processor.  */
+int __pthread_smp_kernel;
+
+
+#if !__ASSUME_REALTIME_SIGNALS
+/* Pointers that select new or old suspend/resume functions
+   based on availability of rt signals. */
+
+void (*__pthread_restart)(pthread_descr) = __pthread_restart_old;
+void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old;
+int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old;
+#endif	/* __ASSUME_REALTIME_SIGNALS */
+
+/* Communicate relevant LinuxThreads constants to gdb */
+
+const int __pthread_threads_max = PTHREAD_THREADS_MAX;
+const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct);
+const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct,
+                                              h_descr);
+const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct,
+                                            p_pid);
+const int __linuxthreads_pthread_sizeof_descr
+  = sizeof(struct _pthread_descr_struct);
+
+const int __linuxthreads_initial_report_events;
+
+const char __linuxthreads_version[] = VERSION;
+
+/* Forward declarations */
+
+static void pthread_onexit_process(int retcode, void *arg);
+#ifndef HAVE_Z_NODELETE
+static void pthread_atexit_process(void *arg, int retcode);
+static void pthread_atexit_retcode(void *arg, int retcode);
+#endif
+static void pthread_handle_sigcancel(int sig);
+static void pthread_handle_sigrestart(int sig);
+static void pthread_handle_sigdebug(int sig);
+
+/* Signal numbers used for the communication.
+   In these variables we keep track of the used variables.  If the
+   platform does not support any real-time signals we will define the
+   values to some unreasonable value which will signal failing of all
+   the functions below.  */
+int __pthread_sig_restart = __SIGRTMIN;
+int __pthread_sig_cancel = __SIGRTMIN + 1;
+int __pthread_sig_debug = __SIGRTMIN + 2;
+
+extern int __libc_current_sigrtmin_private (void);
+
+#if !__ASSUME_REALTIME_SIGNALS
+static int rtsigs_initialized;
+
+static void
+init_rtsigs (void)
+{
+  if (rtsigs_initialized)
+    return;
+
+  if (__libc_current_sigrtmin_private () == -1)
+    {
+      __pthread_sig_restart = SIGUSR1;
+      __pthread_sig_cancel = SIGUSR2;
+      __pthread_sig_debug = 0;
+    }
+  else
+    {
+      __pthread_restart = __pthread_restart_new;
+      __pthread_suspend = __pthread_wait_for_restart_signal;
+      __pthread_timedsuspend = __pthread_timedsuspend_new;
+    }
+
+  rtsigs_initialized = 1;
+}
+#endif
+
+
+/* Initialize the pthread library.
+   Initialization is split in two functions:
+   - a constructor function that blocks the __pthread_sig_restart signal
+     (must do this very early, since the program could capture the signal
+      mask with e.g. sigsetjmp before creating the first thread);
+   - a regular function called from pthread_create when needed. */
+
+static void pthread_initialize(void) __attribute__((constructor));
+
+#ifndef HAVE_Z_NODELETE
+extern void *__dso_handle __attribute__ ((weak));
+#endif
+
+
+#if defined USE_TLS && !defined SHARED
+extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
+#endif
+
+struct pthread_functions __pthread_functions =
+  {
+#if !(USE_TLS && HAVE___THREAD)
+    .ptr_pthread_internal_tsd_set = __pthread_internal_tsd_set,
+    .ptr_pthread_internal_tsd_get = __pthread_internal_tsd_get,
+    .ptr_pthread_internal_tsd_address = __pthread_internal_tsd_address,
+#endif
+    .ptr_pthread_fork = __pthread_fork,
+    .ptr_pthread_attr_destroy = __pthread_attr_destroy,
+    .ptr___pthread_attr_init = __pthread_attr_init,
+    .ptr_pthread_attr_getdetachstate = __pthread_attr_getdetachstate,
+    .ptr_pthread_attr_setdetachstate = __pthread_attr_setdetachstate,
+    .ptr_pthread_attr_getinheritsched = __pthread_attr_getinheritsched,
+    .ptr_pthread_attr_setinheritsched = __pthread_attr_setinheritsched,
+    .ptr_pthread_attr_getschedparam = __pthread_attr_getschedparam,
+    .ptr_pthread_attr_setschedparam = __pthread_attr_setschedparam,
+    .ptr_pthread_attr_getschedpolicy = __pthread_attr_getschedpolicy,
+    .ptr_pthread_attr_setschedpolicy = __pthread_attr_setschedpolicy,
+    .ptr_pthread_attr_getscope = __pthread_attr_getscope,
+    .ptr_pthread_attr_setscope = __pthread_attr_setscope,
+    .ptr_pthread_condattr_destroy = __pthread_condattr_destroy,
+    .ptr_pthread_condattr_init = __pthread_condattr_init,
+    .ptr_pthread_cond_broadcast = __pthread_cond_broadcast,
+    .ptr_pthread_cond_destroy = __pthread_cond_destroy,
+    .ptr_pthread_cond_init = __pthread_cond_init,
+    .ptr_pthread_cond_signal = __pthread_cond_signal,
+    .ptr_pthread_cond_wait = __pthread_cond_wait,
+    .ptr_pthread_cond_timedwait = __pthread_cond_timedwait,
+    .ptr_pthread_equal = __pthread_equal,
+    .ptr___pthread_exit = __pthread_exit,
+    .ptr_pthread_getschedparam = __pthread_getschedparam,
+    .ptr_pthread_setschedparam = __pthread_setschedparam,
+    .ptr_pthread_mutex_destroy = __pthread_mutex_destroy,
+    .ptr_pthread_mutex_init = __pthread_mutex_init,
+    .ptr_pthread_mutex_lock = __pthread_mutex_lock,
+    .ptr_pthread_mutex_trylock = __pthread_mutex_trylock,
+    .ptr_pthread_mutex_unlock = __pthread_mutex_unlock,
+    .ptr_pthread_self = __pthread_self,
+    .ptr_pthread_setcancelstate = __pthread_setcancelstate,
+    .ptr_pthread_setcanceltype = __pthread_setcanceltype,
+    .ptr_pthread_do_exit = __pthread_do_exit,
+    .ptr_pthread_thread_self = __pthread_thread_self,
+    .ptr_pthread_cleanup_upto = __pthread_cleanup_upto,
+    .ptr_pthread_sigaction = __pthread_sigaction,
+    .ptr_pthread_sigwait = __pthread_sigwait,
+    .ptr_pthread_raise = __pthread_raise,
+    .ptr__pthread_cleanup_push = _pthread_cleanup_push,
+    .ptr__pthread_cleanup_pop = _pthread_cleanup_pop
+  };
+#ifdef SHARED
+# define ptr_pthread_functions &__pthread_functions
+#else
+# define ptr_pthread_functions NULL
+#endif
+
+static int *__libc_multiple_threads_ptr;
+
+/* Do some minimal initialization which has to be done during the
+   startup of the C library.  */
+void
+__pthread_initialize_minimal(void)
+{
+#ifdef USE_TLS
+  pthread_descr self;
+
+  /* First of all init __pthread_handles[0] and [1] if needed.  */
+# if __LT_SPINLOCK_INIT != 0
+  __pthread_handles[0].h_lock = __LOCK_INITIALIZER;
+  __pthread_handles[1].h_lock = __LOCK_INITIALIZER;
+# endif
+# ifndef SHARED
+  /* Unlike in the dynamically linked case the dynamic linker has not
+     taken care of initializing the TLS data structures.  */
+  __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);
+# elif !USE___THREAD
+  if (__builtin_expect (GL(dl_tls_dtv_slotinfo_list) == NULL, 0))
+    {
+      tcbhead_t *tcbp;
+
+      /* There is no actual TLS being used, so the thread register
+	 was not initialized in the dynamic linker.  */
+
+      /* We need to install special hooks so that the malloc and memalign
+	 calls in _dl_tls_setup and _dl_allocate_tls won't cause full
+	 malloc initialization that will try to set up its thread state.  */
+
+      extern void __libc_malloc_pthread_startup (bool first_time);
+      __libc_malloc_pthread_startup (true);
+
+      if (__builtin_expect (_dl_tls_setup (), 0)
+	  || __builtin_expect ((tcbp = _dl_allocate_tls (NULL)) == NULL, 0))
+	{
+	  static const char msg[] = "\
+cannot allocate TLS data structures for initial thread\n";
+	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO,
+						msg, sizeof msg - 1));
+	  abort ();
+	}
+      const char *lossage = TLS_INIT_TP (tcbp, 0);
+      if (__builtin_expect (lossage != NULL, 0))
+	{
+	  static const char msg[] = "cannot set up thread-local storage: ";
+	  const char nl = '\n';
+	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO,
+						msg, sizeof msg - 1));
+	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO,
+						lossage, strlen (lossage)));
+	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, &nl, 1));
+	}
+
+      /* Though it was allocated with libc's malloc, that was done without
+	 the user's __malloc_hook installed.  A later realloc that uses
+	 the hooks might not work with that block from the plain malloc.
+	 So we record this block as unfreeable just as the dynamic linker
+	 does when it allocates the DTV before the libc malloc exists.  */
+      GL(dl_initial_dtv) = GET_DTV (tcbp);
+
+      __libc_malloc_pthread_startup (false);
+    }
+# endif
+
+  self = THREAD_SELF;
+
+  /* The memory for the thread descriptor was allocated elsewhere as
+     part of the TLS allocation.  We have to initialize the data
+     structure by hand.  This initialization must mirror the struct
+     definition above.  */
+  self->p_nextlive = self->p_prevlive = self;
+  self->p_tid = PTHREAD_THREADS_MAX;
+  self->p_lock = &__pthread_handles[0].h_lock;
+# ifndef HAVE___THREAD
+  self->p_errnop = &_errno;
+  self->p_h_errnop = &_h_errno;
+# endif
+  /* self->p_start_args need not be initialized, it's all zero.  */
+  self->p_userstack = 1;
+# if __LT_SPINLOCK_INIT != 0
+  self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER;
+# endif
+  self->p_alloca_cutoff = __MAX_ALLOCA_CUTOFF;
+
+  /* Another variable which points to the thread descriptor.  */
+  __pthread_main_thread = self;
+
+  /* And fill in the pointer the the thread __pthread_handles array.  */
+  __pthread_handles[0].h_descr = self;
+
+#else  /* USE_TLS */
+
+  /* First of all init __pthread_handles[0] and [1].  */
+# if __LT_SPINLOCK_INIT != 0
+  __pthread_handles[0].h_lock = __LOCK_INITIALIZER;
+  __pthread_handles[1].h_lock = __LOCK_INITIALIZER;
+# endif
+  __pthread_handles[0].h_descr = &__pthread_initial_thread;
+  __pthread_handles[1].h_descr = &__pthread_manager_thread;
+
+  /* If we have special thread_self processing, initialize that for the
+     main thread now.  */
+# ifdef INIT_THREAD_SELF
+  INIT_THREAD_SELF(&__pthread_initial_thread, 0);
+# endif
+#endif
+
+#if HP_TIMING_AVAIL
+# ifdef USE_TLS
+  self->p_cpuclock_offset = GL(dl_cpuclock_offset);
+# else
+  __pthread_initial_thread.p_cpuclock_offset = GL(dl_cpuclock_offset);
+# endif
+#endif
+
+  __libc_multiple_threads_ptr = __libc_pthread_init (ptr_pthread_functions);
+}
+
+
+void
+__pthread_init_max_stacksize(void)
+{
+  struct rlimit limit;
+  size_t max_stack;
+
+  getrlimit(RLIMIT_STACK, &limit);
+#ifdef FLOATING_STACKS
+  if (limit.rlim_cur == RLIM_INFINITY)
+    limit.rlim_cur = ARCH_STACK_MAX_SIZE;
+# ifdef NEED_SEPARATE_REGISTER_STACK
+  max_stack = limit.rlim_cur / 2;
+# else
+  max_stack = limit.rlim_cur;
+# endif
+#else
+  /* Play with the stack size limit to make sure that no stack ever grows
+     beyond STACK_SIZE minus one page (to act as a guard page). */
+# ifdef NEED_SEPARATE_REGISTER_STACK
+  /* STACK_SIZE bytes hold both the main stack and register backing
+     store. The rlimit value applies to each individually.  */
+  max_stack = STACK_SIZE/2 - __getpagesize ();
+# else
+  max_stack = STACK_SIZE - __getpagesize();
+# endif
+  if (limit.rlim_cur > max_stack) {
+    limit.rlim_cur = max_stack;
+    setrlimit(RLIMIT_STACK, &limit);
+  }
+#endif
+  __pthread_max_stacksize = max_stack;
+  if (max_stack / 4 < __MAX_ALLOCA_CUTOFF)
+    {
+#ifdef USE_TLS
+      pthread_descr self = THREAD_SELF;
+      self->p_alloca_cutoff = max_stack / 4;
+#else
+      __pthread_initial_thread.p_alloca_cutoff = max_stack / 4;
+#endif
+    }
+}
+
+#ifdef SHARED
+# if USE___THREAD
+/* When using __thread for this, we do it in libc so as not
+   to give libpthread its own TLS segment just for this.  */
+extern void **__libc_dl_error_tsd (void) __attribute__ ((const));
+# else
+static void ** __attribute__ ((const))
+__libc_dl_error_tsd (void)
+{
+  return &thread_self ()->p_libc_specific[_LIBC_TSD_KEY_DL_ERROR];
+}
+# endif
+#endif
+
+#ifdef USE_TLS
+static inline void __attribute__((always_inline))
+init_one_static_tls (pthread_descr descr, struct link_map *map)
+{
+# if TLS_TCB_AT_TP
+  dtv_t *dtv = GET_DTV (descr);
+  void *dest = (char *) descr - map->l_tls_offset;
+# elif TLS_DTV_AT_TP
+  dtv_t *dtv = GET_DTV ((pthread_descr) ((char *) descr + TLS_PRE_TCB_SIZE));
+  void *dest = (char *) descr + map->l_tls_offset + TLS_PRE_TCB_SIZE;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+  /* Fill in the DTV slot so that a later LD/GD access will find it.  */
+  dtv[map->l_tls_modid].pointer.val = dest;
+  dtv[map->l_tls_modid].pointer.is_static = true;
+
+  /* Initialize the memory.  */
+  memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+	  '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+}
+
+static void
+__pthread_init_static_tls (struct link_map *map)
+{
+  size_t i;
+
+  for (i = 0; i < PTHREAD_THREADS_MAX; ++i)
+    if (__pthread_handles[i].h_descr != NULL && i != 1)
+      {
+        __pthread_lock (&__pthread_handles[i].h_lock, NULL);
+	if (__pthread_handles[i].h_descr != NULL)
+	  init_one_static_tls (__pthread_handles[i].h_descr, map);
+        __pthread_unlock (&__pthread_handles[i].h_lock);
+      }
+}
+#endif
+
+static void pthread_initialize(void)
+{
+  struct sigaction sa;
+  sigset_t mask;
+
+  /* If already done (e.g. by a constructor called earlier!), bail out */
+  if (__pthread_initial_thread_bos != NULL) return;
+#ifdef TEST_FOR_COMPARE_AND_SWAP
+  /* Test if compare-and-swap is available */
+  __pthread_has_cas = compare_and_swap_is_available();
+#endif
+#ifdef FLOATING_STACKS
+  /* We don't need to know the bottom of the stack.  Give the pointer some
+     value to signal that initialization happened.  */
+  __pthread_initial_thread_bos = (void *) -1l;
+#else
+  /* Determine stack size limits .  */
+  __pthread_init_max_stacksize ();
+# ifdef _STACK_GROWS_UP
+  /* The initial thread already has all the stack it needs */
+  __pthread_initial_thread_bos = (char *)
+    ((long)CURRENT_STACK_FRAME &~ (STACK_SIZE - 1));
+# else
+  /* For the initial stack, reserve at least STACK_SIZE bytes of stack
+     below the current stack address, and align that on a
+     STACK_SIZE boundary. */
+  __pthread_initial_thread_bos =
+    (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
+# endif
+#endif
+#ifdef USE_TLS
+  /* Update the descriptor for the initial thread. */
+  THREAD_SETMEM (((pthread_descr) NULL), p_pid, __getpid());
+# ifndef HAVE___THREAD
+  /* Likewise for the resolver state _res.  */
+  THREAD_SETMEM (((pthread_descr) NULL), p_resp, &_res);
+# endif
+#else
+  /* Update the descriptor for the initial thread. */
+  __pthread_initial_thread.p_pid = __getpid();
+  /* Likewise for the resolver state _res.  */
+  __pthread_initial_thread.p_resp = &_res;
+#endif
+#if !__ASSUME_REALTIME_SIGNALS
+  /* Initialize real-time signals. */
+  init_rtsigs ();
+#endif
+  /* Setup signal handlers for the initial thread.
+     Since signal handlers are shared between threads, these settings
+     will be inherited by all other threads. */
+  sa.sa_handler = pthread_handle_sigrestart;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  __libc_sigaction(__pthread_sig_restart, &sa, NULL);
+  sa.sa_handler = pthread_handle_sigcancel;
+  sigaddset(&sa.sa_mask, __pthread_sig_restart);
+  // sa.sa_flags = 0;
+  __libc_sigaction(__pthread_sig_cancel, &sa, NULL);
+  if (__pthread_sig_debug > 0) {
+    sa.sa_handler = pthread_handle_sigdebug;
+    sigemptyset(&sa.sa_mask);
+    // sa.sa_flags = 0;
+    __libc_sigaction(__pthread_sig_debug, &sa, NULL);
+  }
+  /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */
+  sigemptyset(&mask);
+  sigaddset(&mask, __pthread_sig_restart);
+  sigprocmask(SIG_BLOCK, &mask, NULL);
+  /* And unblock __pthread_sig_cancel if it has been blocked. */
+  sigdelset(&mask, __pthread_sig_restart);
+  sigaddset(&mask, __pthread_sig_cancel);
+  sigprocmask(SIG_UNBLOCK, &mask, NULL);
+  /* Register an exit function to kill all other threads. */
+  /* Do it early so that user-registered atexit functions are called
+     before pthread_*exit_process. */
+#ifndef HAVE_Z_NODELETE
+  if (__builtin_expect (&__dso_handle != NULL, 1))
+    __cxa_atexit ((void (*) (void *)) pthread_atexit_process, NULL,
+		  __dso_handle);
+  else
+#endif
+    __on_exit (pthread_onexit_process, NULL);
+  /* How many processors.  */
+  __pthread_smp_kernel = is_smp_system ();
+
+#ifdef SHARED
+  /* Transfer the old value from the dynamic linker's internal location.  */
+  *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
+  GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;
+
+  /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock,
+     keep the lock count from the ld.so implementation.  */
+  GL(dl_rtld_lock_recursive) = (void *) __pthread_mutex_lock;
+  GL(dl_rtld_unlock_recursive) = (void *) __pthread_mutex_unlock;
+  unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__m_count;
+  GL(dl_load_lock).mutex.__m_count = 0;
+  while (rtld_lock_count-- > 0)
+    __pthread_mutex_lock (&GL(dl_load_lock).mutex);
+#endif
+
+#ifdef USE_TLS
+  GL(dl_init_static_tls) = &__pthread_init_static_tls;
+#endif
+}
+
+void __pthread_initialize(void)
+{
+  pthread_initialize();
+}
+
+int __pthread_initialize_manager(void)
+{
+  int manager_pipe[2];
+  int pid;
+  struct pthread_request request;
+  int report_events;
+  pthread_descr mgr;
+#ifdef USE_TLS
+  tcbhead_t *tcbp;
+#endif
+
+  __pthread_multiple_threads = 1;
+#if TLS_MULTIPLE_THREADS_IN_TCB || !defined USE_TLS || !TLS_DTV_AT_TP
+  __pthread_main_thread->p_multiple_threads = 1;
+#endif
+  *__libc_multiple_threads_ptr = 1;
+
+#ifndef HAVE_Z_NODELETE
+  if (__builtin_expect (&__dso_handle != NULL, 1))
+    __cxa_atexit ((void (*) (void *)) pthread_atexit_retcode, NULL,
+		  __dso_handle);
+#endif
+
+  if (__pthread_max_stacksize == 0)
+    __pthread_init_max_stacksize ();
+  /* If basic initialization not done yet (e.g. we're called from a
+     constructor run before our constructor), do it now */
+  if (__pthread_initial_thread_bos == NULL) pthread_initialize();
+  /* Setup stack for thread manager */
+  __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE);
+  if (__pthread_manager_thread_bos == NULL) return -1;
+  __pthread_manager_thread_tos =
+    __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE;
+  /* Setup pipe to communicate with thread manager */
+  if (pipe(manager_pipe) == -1) {
+    free(__pthread_manager_thread_bos);
+    return -1;
+  }
+
+#ifdef USE_TLS
+  /* Allocate memory for the thread descriptor and the dtv.  */
+  tcbp = _dl_allocate_tls (NULL);
+  if (tcbp == NULL) {
+    free(__pthread_manager_thread_bos);
+    close_not_cancel(manager_pipe[0]);
+    close_not_cancel(manager_pipe[1]);
+    return -1;
+  }
+
+# if TLS_TCB_AT_TP
+  mgr = (pthread_descr) tcbp;
+# elif TLS_DTV_AT_TP
+  /* pthread_descr is located right below tcbhead_t which _dl_allocate_tls
+     returns.  */
+  mgr = (pthread_descr) ((char *) tcbp - TLS_PRE_TCB_SIZE);
+# endif
+  __pthread_handles[1].h_descr = manager_thread = mgr;
+
+  /* Initialize the descriptor.  */
+#if !defined USE_TLS || !TLS_DTV_AT_TP
+  mgr->p_header.data.tcb = tcbp;
+  mgr->p_header.data.self = mgr;
+  mgr->p_header.data.multiple_threads = 1;
+#elif TLS_MULTIPLE_THREADS_IN_TCB
+  mgr->p_multiple_threads = 1;
+#endif
+  mgr->p_lock = &__pthread_handles[1].h_lock;
+# ifndef HAVE___THREAD
+  mgr->p_errnop = &mgr->p_errno;
+# endif
+  mgr->p_start_args = (struct pthread_start_args) PTHREAD_START_ARGS_INITIALIZER(__pthread_manager);
+  mgr->p_nr = 1;
+# if __LT_SPINLOCK_INIT != 0
+  self->p_resume_count = (struct pthread_atomic) __ATOMIC_INITIALIZER;
+# endif
+  mgr->p_alloca_cutoff = PTHREAD_STACK_MIN / 4;
+#else
+  mgr = &__pthread_manager_thread;
+#endif
+
+  __pthread_manager_request = manager_pipe[1]; /* writing end */
+  __pthread_manager_reader = manager_pipe[0]; /* reading end */
+
+  /* Start the thread manager */
+  pid = 0;
+#ifdef USE_TLS
+  if (__linuxthreads_initial_report_events != 0)
+    THREAD_SETMEM (((pthread_descr) NULL), p_report_events,
+		   __linuxthreads_initial_report_events);
+  report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events);
+#else
+  if (__linuxthreads_initial_report_events != 0)
+    __pthread_initial_thread.p_report_events
+      = __linuxthreads_initial_report_events;
+  report_events = __pthread_initial_thread.p_report_events;
+#endif
+  if (__builtin_expect (report_events, 0))
+    {
+      /* It's a bit more complicated.  We have to report the creation of
+	 the manager thread.  */
+      int idx = __td_eventword (TD_CREATE);
+      uint32_t mask = __td_eventmask (TD_CREATE);
+      uint32_t event_bits;
+
+#ifdef USE_TLS
+      event_bits = THREAD_GETMEM_NC (((pthread_descr) NULL),
+				     p_eventbuf.eventmask.event_bits[idx]);
+#else
+      event_bits = __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx];
+#endif
+
+      if ((mask & (__pthread_threads_events.event_bits[idx] | event_bits))
+	  != 0)
+	{
+	  __pthread_lock(mgr->p_lock, NULL);
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+	  pid = __clone2(__pthread_manager_event,
+			 (void **) __pthread_manager_thread_bos,
+			 THREAD_MANAGER_STACK_SIZE,
+			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
+			 mgr);
+#elif _STACK_GROWS_UP
+	  pid = __clone(__pthread_manager_event,
+			(void **) __pthread_manager_thread_bos,
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
+			mgr);
+#else
+	  pid = __clone(__pthread_manager_event,
+			(void **) __pthread_manager_thread_tos,
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
+			mgr);
+#endif
+
+	  if (pid != -1)
+	    {
+	      /* 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.  */
+	      mgr->p_eventbuf.eventdata = mgr;
+	      mgr->p_eventbuf.eventnum = TD_CREATE;
+	      __pthread_last_event = mgr;
+	      mgr->p_tid = 2* PTHREAD_THREADS_MAX + 1;
+	      mgr->p_pid = pid;
+
+	      /* Now call the function which signals the event.  */
+	      __linuxthreads_create_event ();
+	    }
+
+	  /* Now restart the thread.  */
+	  __pthread_unlock(mgr->p_lock);
+	}
+    }
+
+  if (__builtin_expect (pid, 0) == 0)
+    {
+#ifdef NEED_SEPARATE_REGISTER_STACK
+      pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos,
+		     THREAD_MANAGER_STACK_SIZE,
+		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
+#elif _STACK_GROWS_UP
+      pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos,
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
+#else
+      pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
+#endif
+    }
+  if (__builtin_expect (pid, 0) == -1) {
+#ifdef USE_TLS
+    _dl_deallocate_tls (tcbp, true);
+#endif
+    free(__pthread_manager_thread_bos);
+    close_not_cancel(manager_pipe[0]);
+    close_not_cancel(manager_pipe[1]);
+    return -1;
+  }
+  mgr->p_tid = 2* PTHREAD_THREADS_MAX + 1;
+  mgr->p_pid = pid;
+  /* Make gdb aware of new thread manager */
+  if (__builtin_expect (__pthread_threads_debug, 0) && __pthread_sig_debug > 0)
+    {
+      raise(__pthread_sig_debug);
+      /* We suspend ourself and gdb will wake us up when it is
+	 ready to handle us. */
+      __pthread_wait_for_restart_signal(thread_self());
+    }
+  /* Synchronize debugging of the thread manager */
+  request.req_kind = REQ_DEBUG;
+  TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+				      (char *) &request, sizeof(request)));
+  return 0;
+}
+
+/* Thread creation */
+
+int __pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+			 void * (*start_routine)(void *), void *arg)
+{
+  pthread_descr self = thread_self();
+  struct pthread_request request;
+  int retval;
+  if (__builtin_expect (__pthread_manager_request, 0) < 0) {
+    if (__pthread_initialize_manager() < 0) return EAGAIN;
+  }
+  request.req_thread = self;
+  request.req_kind = REQ_CREATE;
+  request.req_args.create.attr = attr;
+  request.req_args.create.fn = start_routine;
+  request.req_args.create.arg = arg;
+  sigprocmask(SIG_SETMASK, (const sigset_t *) NULL,
+              &request.req_args.create.mask);
+  TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+				      (char *) &request, sizeof(request)));
+  suspend(self);
+  retval = THREAD_GETMEM(self, p_retcode);
+  if (__builtin_expect (retval, 0) == 0)
+    *thread = (pthread_t) THREAD_GETMEM(self, p_retval);
+  return retval;
+}
+strong_alias (__pthread_create, pthread_create)
+
+/* Simple operations on thread identifiers */
+
+pthread_descr __pthread_thread_self(void)
+{
+  return thread_self();
+}
+
+pthread_t __pthread_self(void)
+{
+  pthread_descr self = thread_self();
+  return THREAD_GETMEM(self, p_tid);
+}
+strong_alias (__pthread_self, pthread_self);
+
+int __pthread_equal(pthread_t thread1, pthread_t thread2)
+{
+  return thread1 == thread2;
+}
+strong_alias (__pthread_equal, pthread_equal);
+
+/* Helper function for thread_self in the case of user-provided stacks */
+
+#ifndef THREAD_SELF
+
+pthread_descr __pthread_find_self(void)
+{
+  char * sp = CURRENT_STACK_FRAME;
+  pthread_handle h;
+
+  /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is
+     the manager threads handled specially in thread_self(), so start at 2 */
+  h = __pthread_handles + 2;
+# ifdef _STACK_GROWS_UP
+  while (! (sp >= (char *) h->h_descr && sp < (char *) h->h_descr->p_guardaddr)) h++;
+# else
+  while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++;
+# endif
+  return h->h_descr;
+}
+
+#else
+
+pthread_descr __pthread_self_stack(void)
+{
+  char *sp = CURRENT_STACK_FRAME;
+  pthread_handle h;
+
+  if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos)
+    return manager_thread;
+  h = __pthread_handles + 2;
+# ifdef USE_TLS
+#  ifdef _STACK_GROWS_UP
+  while (h->h_descr == NULL
+	 || ! (sp >= h->h_descr->p_stackaddr && sp < h->h_descr->p_guardaddr))
+    h++;
+#  else
+  while (h->h_descr == NULL
+	 || ! (sp <= (char *) h->h_descr->p_stackaddr && sp >= h->h_bottom))
+    h++;
+#  endif
+# else
+#  ifdef _STACK_GROWS_UP
+  while (! (sp >= (char *) h->h_descr && sp < h->h_descr->p_guardaddr))
+    h++;
+#  else
+  while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom))
+    h++;
+#  endif
+# endif
+  return h->h_descr;
+}
+
+#endif
+
+/* Thread scheduling */
+
+int __pthread_setschedparam(pthread_t thread, int policy,
+                            const struct sched_param *param)
+{
+  pthread_handle handle = thread_handle(thread);
+  pthread_descr th;
+
+  __pthread_lock(&handle->h_lock, NULL);
+  if (__builtin_expect (invalid_handle(handle, thread), 0)) {
+    __pthread_unlock(&handle->h_lock);
+    return ESRCH;
+  }
+  th = handle->h_descr;
+  if (__builtin_expect (__sched_setscheduler(th->p_pid, policy, param) == -1,
+			0)) {
+    __pthread_unlock(&handle->h_lock);
+    return errno;
+  }
+  th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority;
+  __pthread_unlock(&handle->h_lock);
+  if (__pthread_manager_request >= 0)
+    __pthread_manager_adjust_prio(th->p_priority);
+  return 0;
+}
+strong_alias (__pthread_setschedparam, pthread_setschedparam);
+
+int __pthread_getschedparam(pthread_t thread, int *policy,
+                            struct sched_param *param)
+{
+  pthread_handle handle = thread_handle(thread);
+  int pid, pol;
+
+  __pthread_lock(&handle->h_lock, NULL);
+  if (__builtin_expect (invalid_handle(handle, thread), 0)) {
+    __pthread_unlock(&handle->h_lock);
+    return ESRCH;
+  }
+  pid = handle->h_descr->p_pid;
+  __pthread_unlock(&handle->h_lock);
+  pol = __sched_getscheduler(pid);
+  if (__builtin_expect (pol, 0) == -1) return errno;
+  if (__sched_getparam(pid, param) == -1) return errno;
+  *policy = pol;
+  return 0;
+}
+strong_alias (__pthread_getschedparam, pthread_getschedparam);
+
+int __pthread_yield (void)
+{
+  /* For now this is equivalent with the POSIX call.  */
+  return sched_yield ();
+}
+weak_alias (__pthread_yield, pthread_yield)
+
+/* Process-wide exit() request */
+
+static void pthread_onexit_process(int retcode, void *arg)
+{
+  if (__builtin_expect (__pthread_manager_request, 0) >= 0) {
+    struct pthread_request request;
+    pthread_descr self = thread_self();
+
+    request.req_thread = self;
+    request.req_kind = REQ_PROCESS_EXIT;
+    request.req_args.exit.code = retcode;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *) &request, sizeof(request)));
+    suspend(self);
+    /* Main thread should accumulate times for thread manager and its
+       children, so that timings for main thread account for all threads. */
+    if (self == __pthread_main_thread)
+      {
+#ifdef USE_TLS
+	waitpid(manager_thread->p_pid, NULL, __WCLONE);
+#else
+	waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+#endif
+	/* Since all threads have been asynchronously terminated
+           (possibly holding locks), free cannot be used any more.
+           For mtrace, we'd like to print something though.  */
+	/* #ifdef USE_TLS
+	   tcbhead_t *tcbp = (tcbhead_t *) manager_thread;
+	   # if TLS_DTV_AT_TP
+	   tcbp = (tcbhead_t) ((char *) tcbp + TLS_PRE_TCB_SIZE);
+	   # endif
+	   _dl_deallocate_tls (tcbp, true);
+	   #endif
+	   free (__pthread_manager_thread_bos); */
+	__pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL;
+      }
+  }
+}
+
+#ifndef HAVE_Z_NODELETE
+static int __pthread_atexit_retcode;
+
+static void pthread_atexit_process(void *arg, int retcode)
+{
+  pthread_onexit_process (retcode ?: __pthread_atexit_retcode, arg);
+}
+
+static void pthread_atexit_retcode(void *arg, int retcode)
+{
+  __pthread_atexit_retcode = retcode;
+}
+#endif
+
+/* The handler for the RESTART signal just records the signal received
+   in the thread descriptor, and optionally performs a siglongjmp
+   (for pthread_cond_timedwait). */
+
+static void pthread_handle_sigrestart(int sig)
+{
+  pthread_descr self = check_thread_self();
+  THREAD_SETMEM(self, p_signal, sig);
+  if (THREAD_GETMEM(self, p_signal_jmp) != NULL)
+    siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1);
+}
+
+/* The handler for the CANCEL signal checks for cancellation
+   (in asynchronous mode), for process-wide exit and exec requests.
+   For the thread manager thread, redirect the signal to
+   __pthread_manager_sighandler. */
+
+static void pthread_handle_sigcancel(int sig)
+{
+  pthread_descr self = check_thread_self();
+  sigjmp_buf * jmpbuf;
+
+  if (self == manager_thread)
+    {
+      __pthread_manager_sighandler(sig);
+      return;
+    }
+  if (__builtin_expect (__pthread_exit_requested, 0)) {
+    /* Main thread should accumulate times for thread manager and its
+       children, so that timings for main thread account for all threads. */
+    if (self == __pthread_main_thread) {
+#ifdef USE_TLS
+      waitpid(manager_thread->p_pid, NULL, __WCLONE);
+#else
+      waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+#endif
+    }
+    _exit(__pthread_exit_code);
+  }
+  if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+    if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS)
+      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+    jmpbuf = THREAD_GETMEM(self, p_cancel_jmp);
+    if (jmpbuf != NULL) {
+      THREAD_SETMEM(self, p_cancel_jmp, NULL);
+      siglongjmp(*jmpbuf, 1);
+    }
+  }
+}
+
+/* Handler for the DEBUG signal.
+   The debugging strategy is as follows:
+   On reception of a REQ_DEBUG request (sent by new threads created to
+   the thread manager under debugging mode), the thread manager throws
+   __pthread_sig_debug to itself. The debugger (if active) intercepts
+   this signal, takes into account new threads and continue execution
+   of the thread manager by propagating the signal because it doesn't
+   know what it is specifically done for. In the current implementation,
+   the thread manager simply discards it. */
+
+static void pthread_handle_sigdebug(int sig)
+{
+  /* Nothing */
+}
+
+/* Reset the state of the thread machinery after a fork().
+   Close the pipe used for requests and set the main thread to the forked
+   thread.
+   Notice that we can't free the stack segments, as the forked thread
+   may hold pointers into them. */
+
+void __pthread_reset_main_thread(void)
+{
+  pthread_descr self = thread_self();
+
+  if (__pthread_manager_request != -1) {
+    /* Free the thread manager stack */
+    free(__pthread_manager_thread_bos);
+    __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL;
+    /* Close the two ends of the pipe */
+    close_not_cancel(__pthread_manager_request);
+    close_not_cancel(__pthread_manager_reader);
+    __pthread_manager_request = __pthread_manager_reader = -1;
+  }
+
+  /* Update the pid of the main thread */
+  THREAD_SETMEM(self, p_pid, __getpid());
+  /* Make the forked thread the main thread */
+  __pthread_main_thread = self;
+  THREAD_SETMEM(self, p_nextlive, self);
+  THREAD_SETMEM(self, p_prevlive, self);
+#if !(USE_TLS && HAVE___THREAD)
+  /* Now this thread modifies the global variables.  */
+  THREAD_SETMEM(self, p_errnop, &_errno);
+  THREAD_SETMEM(self, p_h_errnop, &_h_errno);
+  THREAD_SETMEM(self, p_resp, &_res);
+#endif
+
+#ifndef FLOATING_STACKS
+  /* This is to undo the setrlimit call in __pthread_init_max_stacksize.
+     XXX This can be wrong if the user set the limit during the run.  */
+ {
+   struct rlimit limit;
+   if (getrlimit (RLIMIT_STACK, &limit) == 0
+       && limit.rlim_cur != limit.rlim_max)
+     {
+       limit.rlim_cur = limit.rlim_max;
+       setrlimit(RLIMIT_STACK, &limit);
+     }
+ }
+#endif
+}
+
+/* Process-wide exec() request */
+
+void __pthread_kill_other_threads_np(void)
+{
+  struct sigaction sa;
+  /* Terminate all other threads and thread manager */
+  pthread_onexit_process(0, NULL);
+  /* Make current thread the main thread in case the calling thread
+     changes its mind, does not exec(), and creates new threads instead. */
+  __pthread_reset_main_thread();
+
+  /* Reset the signal handlers behaviour for the signals the
+     implementation uses since this would be passed to the new
+     process.  */
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  sa.sa_handler = SIG_DFL;
+  __libc_sigaction(__pthread_sig_restart, &sa, NULL);
+  __libc_sigaction(__pthread_sig_cancel, &sa, NULL);
+  if (__pthread_sig_debug > 0)
+    __libc_sigaction(__pthread_sig_debug, &sa, NULL);
+}
+weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np)
+
+/* Concurrency symbol level.  */
+static int current_level;
+
+int __pthread_setconcurrency(int level)
+{
+  /* We don't do anything unless we have found a useful interpretation.  */
+  current_level = level;
+  return 0;
+}
+weak_alias (__pthread_setconcurrency, pthread_setconcurrency)
+
+int __pthread_getconcurrency(void)
+{
+  return current_level;
+}
+weak_alias (__pthread_getconcurrency, pthread_getconcurrency)
+
+/* Primitives for controlling thread execution */
+
+void __pthread_wait_for_restart_signal(pthread_descr self)
+{
+  sigset_t mask;
+
+  sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */
+  sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */
+  THREAD_SETMEM(self, p_signal, 0);
+  do {
+    __pthread_sigsuspend(&mask);	/* Wait for signal.  Must not be a
+					   cancellation point. */
+  } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart);
+
+  READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */
+}
+
+#if !__ASSUME_REALTIME_SIGNALS
+/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT
+   signals.
+   On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation.
+   Since the restart signal does not queue, we use an atomic counter to create
+   queuing semantics. This is needed to resolve a rare race condition in
+   pthread_cond_timedwait_relative. */
+
+void __pthread_restart_old(pthread_descr th)
+{
+  if (atomic_increment(&th->p_resume_count) == -1)
+    kill(th->p_pid, __pthread_sig_restart);
+}
+
+void __pthread_suspend_old(pthread_descr self)
+{
+  if (atomic_decrement(&self->p_resume_count) <= 0)
+    __pthread_wait_for_restart_signal(self);
+}
+
+int
+__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime)
+{
+  sigset_t unblock, initial_mask;
+  int was_signalled = 0;
+  sigjmp_buf jmpbuf;
+
+  if (atomic_decrement(&self->p_resume_count) == 0) {
+    /* Set up a longjmp handler for the restart signal, unblock
+       the signal and sleep. */
+
+    if (sigsetjmp(jmpbuf, 1) == 0) {
+      THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
+      THREAD_SETMEM(self, p_signal, 0);
+      /* Unblock the restart signal */
+      sigemptyset(&unblock);
+      sigaddset(&unblock, __pthread_sig_restart);
+      sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
+
+      while (1) {
+	struct timeval now;
+	struct timespec reltime;
+
+	/* Compute a time offset relative to now.  */
+	__gettimeofday (&now, NULL);
+	reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
+	reltime.tv_sec = abstime->tv_sec - now.tv_sec;
+	if (reltime.tv_nsec < 0) {
+	  reltime.tv_nsec += 1000000000;
+	  reltime.tv_sec -= 1;
+	}
+
+	/* Sleep for the required duration. If woken by a signal,
+	   resume waiting as required by Single Unix Specification.  */
+	if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
+	  break;
+      }
+
+      /* Block the restart signal again */
+      sigprocmask(SIG_SETMASK, &initial_mask, NULL);
+      was_signalled = 0;
+    } else {
+      was_signalled = 1;
+    }
+    THREAD_SETMEM(self, p_signal_jmp, NULL);
+  }
+
+  /* Now was_signalled is true if we exited the above code
+     due to the delivery of a restart signal.  In that case,
+     we know we have been dequeued and resumed and that the
+     resume count is balanced.  Otherwise, there are some
+     cases to consider. First, try to bump up the resume count
+     back to zero. If it goes to 1, it means restart() was
+     invoked on this thread. The signal must be consumed
+     and the count bumped down and everything is cool. We
+     can return a 1 to the caller.
+     Otherwise, no restart was delivered yet, so a potential
+     race exists; we return a 0 to the caller which must deal
+     with this race in an appropriate way; for example by
+     atomically removing the thread from consideration for a
+     wakeup---if such a thing fails, it means a restart is
+     being delivered. */
+
+  if (!was_signalled) {
+    if (atomic_increment(&self->p_resume_count) != -1) {
+      __pthread_wait_for_restart_signal(self);
+      atomic_decrement(&self->p_resume_count); /* should be zero now! */
+      /* woke spontaneously and consumed restart signal */
+      return 1;
+    }
+    /* woke spontaneously but did not consume restart---caller must resolve */
+    return 0;
+  }
+  /* woken due to restart signal */
+  return 1;
+}
+#endif /* __ASSUME_REALTIME_SIGNALS */
+
+void __pthread_restart_new(pthread_descr th)
+{
+  /* The barrier is proabably not needed, in which case it still documents
+     our assumptions. The intent is to commit previous writes to shared
+     memory so the woken thread will have a consistent view.  Complementary
+     read barriers are present to the suspend functions. */
+  WRITE_MEMORY_BARRIER();
+  kill(th->p_pid, __pthread_sig_restart);
+}
+
+/* There is no __pthread_suspend_new because it would just
+   be a wasteful wrapper for __pthread_wait_for_restart_signal */
+
+int
+__pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime)
+{
+  sigset_t unblock, initial_mask;
+  int was_signalled = 0;
+  sigjmp_buf jmpbuf;
+
+  if (sigsetjmp(jmpbuf, 1) == 0) {
+    THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
+    THREAD_SETMEM(self, p_signal, 0);
+    /* Unblock the restart signal */
+    sigemptyset(&unblock);
+    sigaddset(&unblock, __pthread_sig_restart);
+    sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
+
+    while (1) {
+      struct timeval now;
+      struct timespec reltime;
+
+      /* Compute a time offset relative to now.  */
+      __gettimeofday (&now, NULL);
+      reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
+      reltime.tv_sec = abstime->tv_sec - now.tv_sec;
+      if (reltime.tv_nsec < 0) {
+	reltime.tv_nsec += 1000000000;
+	reltime.tv_sec -= 1;
+      }
+
+      /* Sleep for the required duration. If woken by a signal,
+	 resume waiting as required by Single Unix Specification.  */
+      if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
+	break;
+    }
+
+    /* Block the restart signal again */
+    sigprocmask(SIG_SETMASK, &initial_mask, NULL);
+    was_signalled = 0;
+  } else {
+    was_signalled = 1;
+  }
+  THREAD_SETMEM(self, p_signal_jmp, NULL);
+
+  /* Now was_signalled is true if we exited the above code
+     due to the delivery of a restart signal.  In that case,
+     everything is cool. We have been removed from whatever
+     we were waiting on by the other thread, and consumed its signal.
+
+     Otherwise we this thread woke up spontaneously, or due to a signal other
+     than restart. This is an ambiguous case  that must be resolved by
+     the caller; the thread is still eligible for a restart wakeup
+     so there is a race. */
+
+  READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */
+  return was_signalled;
+}
+
+
+/* Debugging aid */
+
+#ifdef DEBUG
+#include <stdarg.h>
+
+void __pthread_message(const char * fmt, ...)
+{
+  char buffer[1024];
+  va_list args;
+  sprintf(buffer, "%05d : ", __getpid());
+  va_start(args, fmt);
+  vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args);
+  va_end(args);
+  TEMP_FAILURE_RETRY(write_not_cancel(2, buffer, strlen(buffer)));
+}
+
+#endif

+ 57 - 0
libpthread/linuxthreads/pthread_atfork.c

@@ -0,0 +1,57 @@
+/* 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.
+
+   In addition to the permissions in the GNU Lesser 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 GNU Lesser 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.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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 "internals.h"
+#include <fork.h>
+
+/* This is defined by newer gcc version unique for each module.  */
+extern void *__dso_handle __attribute__ ((__weak__));
+
+
+/* Hide the symbol so that no definition but the one locally in the
+   executable or DSO is used.  */
+int
+/* Don't mark the compatibility function as hidden.  */
+attribute_hidden
+__pthread_atfork (prepare, parent, child)
+     void (*prepare) (void);
+     void (*parent) (void);
+     void (*child) (void);
+{
+  return __register_atfork (prepare, parent, child,
+			    &__dso_handle == NULL ? NULL : __dso_handle);
+}
+strong_alias (__pthread_atfork, pthread_atfork)

+ 27 - 0
libpthread/linuxthreads/pthread_setegid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setegid_np (gid_t gid)
+{
+  return setegid (gid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_seteuid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_seteuid_np (uid_t uid)
+{
+  return seteuid (uid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_setgid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setgid_np (gid_t gid)
+{
+  return setgid (gid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_setregid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setregid_np (gid_t rgid, gid_t egid)
+{
+  return setregid (rgid, egid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_setresgid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setresgid_np (gid_t rgid, gid_t egid, gid_t sgid)
+{
+  return setresgid (rgid, egid, sgid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_setresuid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setresuid_np (uid_t ruid, uid_t euid, uid_t suid)
+{
+  return setresuid (ruid, euid, suid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_setreuid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setreuid_np (uid_t ruid, uid_t euid)
+{
+  return setreuid (ruid, euid);
+}

+ 27 - 0
libpthread/linuxthreads/pthread_setuid.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2004 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 <pthread.h>
+#include <unistd.h>
+
+
+int
+pthread_setuid_np (uid_t uid)
+{
+  return setuid (uid);
+}

+ 61 - 0
libpthread/linuxthreads/queue.h

@@ -0,0 +1,61 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Waiting queues */
+
+/* Waiting queues are represented by lists of thread descriptors
+   linked through their p_nextwaiting field.  The lists are kept
+   sorted by decreasing priority, and then decreasing waiting time. */
+
+static inline void enqueue(pthread_descr * q, pthread_descr th)
+{
+  int prio = th->p_priority;
+  ASSERT(th->p_nextwaiting == NULL);
+  for (; *q != NULL; q = &((*q)->p_nextwaiting)) {
+    if (prio > (*q)->p_priority) {
+      th->p_nextwaiting = *q;
+      *q = th;
+      return;
+    }
+  }
+  *q = th;
+}
+
+static inline pthread_descr dequeue(pthread_descr * q)
+{
+  pthread_descr th;
+  th = *q;
+  if (th != NULL) {
+    *q = th->p_nextwaiting;
+    th->p_nextwaiting = NULL;
+  }
+  return th;
+}
+
+static inline int remove_from_queue(pthread_descr * q, pthread_descr th)
+{
+  for (; *q != NULL; q = &((*q)->p_nextwaiting)) {
+    if (*q == th) {
+      *q = th->p_nextwaiting;
+      th->p_nextwaiting = NULL;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static inline int queue_is_empty(pthread_descr * q)
+{
+    return *q == NULL;
+}

+ 49 - 0
libpthread/linuxthreads/restart.h

@@ -0,0 +1,49 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+#include <signal.h>
+#include <kernel-features.h>
+
+/* Primitives for controlling thread execution */
+
+static inline void restart(pthread_descr th)
+{
+  /* See pthread.c */
+#if __ASSUME_REALTIME_SIGNALS
+  __pthread_restart_new(th);
+#else
+  __pthread_restart(th);
+#endif
+}
+
+static inline void suspend(pthread_descr self)
+{
+  /* See pthread.c */
+#if __ASSUME_REALTIME_SIGNALS
+  __pthread_wait_for_restart_signal(self);
+#else
+  __pthread_suspend(self);
+#endif
+}
+
+static inline int timedsuspend(pthread_descr self,
+		const struct timespec *abstime)
+{
+  /* See pthread.c */
+#if __ASSUME_REALTIME_SIGNALS
+  return __pthread_timedsuspend_new(self, abstime);
+#else
+  return __pthread_timedsuspend(self, abstime);
+#endif
+}

+ 658 - 0
libpthread/linuxthreads/rwlock.c

@@ -0,0 +1,658 @@
+/* Read-write lock implementation.
+   Copyright (C) 1998, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Xavier Leroy <Xavier.Leroy@inria.fr>
+   and Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   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 <bits/libc-lock.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include "internals.h"
+#include "queue.h"
+#include "spinlock.h"
+#include "restart.h"
+
+/* Function called by pthread_cancel to remove the thread from
+   waiting inside pthread_rwlock_timedrdlock or pthread_rwlock_timedwrlock. */
+
+static int rwlock_rd_extricate_func(void *obj, pthread_descr th)
+{
+  pthread_rwlock_t *rwlock = obj;
+  int did_remove = 0;
+
+  __pthread_lock(&rwlock->__rw_lock, NULL);
+  did_remove = remove_from_queue(&rwlock->__rw_read_waiting, th);
+  __pthread_unlock(&rwlock->__rw_lock);
+
+  return did_remove;
+}
+
+static int rwlock_wr_extricate_func(void *obj, pthread_descr th)
+{
+  pthread_rwlock_t *rwlock = obj;
+  int did_remove = 0;
+
+  __pthread_lock(&rwlock->__rw_lock, NULL);
+  did_remove = remove_from_queue(&rwlock->__rw_write_waiting, th);
+  __pthread_unlock(&rwlock->__rw_lock);
+
+  return did_remove;
+}
+
+/*
+ * Check whether the calling thread already owns one or more read locks on the
+ * specified lock. If so, return a pointer to the read lock info structure
+ * corresponding to that lock.
+ */
+
+static pthread_readlock_info *
+rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock)
+{
+  pthread_readlock_info *info;
+
+  for (info = THREAD_GETMEM (self, p_readlock_list); info != NULL;
+       info = info->pr_next)
+    {
+      if (info->pr_lock == rwlock)
+	return info;
+    }
+
+  return NULL;
+}
+
+/*
+ * Add a new lock to the thread's list of locks for which it has a read lock.
+ * A new info node must be allocated for this, which is taken from the thread's
+ * free list, or by calling malloc. If malloc fails, a null pointer is
+ * returned. Otherwise the lock info structure is initialized and pushed
+ * onto the thread's list.
+ */
+
+static pthread_readlock_info *
+rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock)
+{
+  pthread_readlock_info *info = THREAD_GETMEM (self, p_readlock_free);
+
+  if (info != NULL)
+    THREAD_SETMEM (self, p_readlock_free, info->pr_next);
+  else
+    info = malloc(sizeof *info);
+
+  if (info == NULL)
+    return NULL;
+
+  info->pr_lock_count = 1;
+  info->pr_lock = rwlock;
+  info->pr_next = THREAD_GETMEM (self, p_readlock_list);
+  THREAD_SETMEM (self, p_readlock_list, info);
+
+  return info;
+}
+
+/*
+ * If the thread owns a read lock over the given pthread_rwlock_t,
+ * and this read lock is tracked in the thread's lock list,
+ * this function returns a pointer to the info node in that list.
+ * It also decrements the lock count within that node, and if
+ * it reaches zero, it removes the node from the list.
+ * If nothing is found, it returns a null pointer.
+ */
+
+static pthread_readlock_info *
+rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock)
+{
+  pthread_readlock_info **pinfo;
+
+  for (pinfo = &self->p_readlock_list; *pinfo != NULL; pinfo = &(*pinfo)->pr_next)
+    {
+      if ((*pinfo)->pr_lock == rwlock)
+	{
+	  pthread_readlock_info *info = *pinfo;
+	  if (--info->pr_lock_count == 0)
+	    *pinfo = info->pr_next;
+	  return info;
+	}
+    }
+
+  return NULL;
+}
+
+/*
+ * This function checks whether the conditions are right to place a read lock.
+ * It returns 1 if so, otherwise zero. The rwlock's internal lock must be
+ * locked upon entry.
+ */
+
+static int
+rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already)
+{
+  /* Can't readlock; it is write locked. */
+  if (rwlock->__rw_writer != NULL)
+    return 0;
+
+  /* Lock prefers readers; get it. */
+  if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP)
+    return 1;
+
+  /* Lock prefers writers, but none are waiting. */
+  if (queue_is_empty(&rwlock->__rw_write_waiting))
+    return 1;
+
+  /* Writers are waiting, but this thread already has a read lock */
+  if (have_lock_already)
+    return 1;
+
+  /* Writers are waiting, and this is a new lock */
+  return 0;
+}
+
+/*
+ * This function helps support brain-damaged recursive read locking
+ * semantics required by Unix 98, while maintaining write priority.
+ * This basically determines whether this thread already holds a read lock
+ * already. It returns 1 if so, otherwise it returns 0.
+ *
+ * If the thread has any ``untracked read locks'' then it just assumes
+ * that this lock is among them, just to be safe, and returns 1.
+ *
+ * Also, if it finds the thread's lock in the list, it sets the pointer
+ * referenced by pexisting to refer to the list entry.
+ *
+ * If the thread has no untracked locks, and the lock is not found
+ * in its list, then it is added to the list. If this fails,
+ * then *pout_of_mem is set to 1.
+ */
+
+static int
+rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock,
+    pthread_readlock_info **pexisting, int *pout_of_mem)
+{
+  pthread_readlock_info *existing = NULL;
+  int out_of_mem = 0, have_lock_already = 0;
+  pthread_descr self = *pself;
+
+  if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
+    {
+      if (!self)
+	*pself = self = thread_self();
+
+      existing = rwlock_is_in_list(self, rwlock);
+
+      if (existing != NULL
+	  || THREAD_GETMEM (self, p_untracked_readlock_count) > 0)
+	have_lock_already = 1;
+      else
+	{
+	  existing = rwlock_add_to_list(self, rwlock);
+	  if (existing == NULL)
+	    out_of_mem = 1;
+	}
+    }
+
+  *pout_of_mem = out_of_mem;
+  *pexisting = existing;
+
+  return have_lock_already;
+}
+
+int
+__pthread_rwlock_init (pthread_rwlock_t *rwlock,
+		       const pthread_rwlockattr_t *attr)
+{
+  __pthread_init_lock(&rwlock->__rw_lock);
+  rwlock->__rw_readers = 0;
+  rwlock->__rw_writer = NULL;
+  rwlock->__rw_read_waiting = NULL;
+  rwlock->__rw_write_waiting = NULL;
+
+  if (attr == NULL)
+    {
+      rwlock->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP;
+      rwlock->__rw_pshared = PTHREAD_PROCESS_PRIVATE;
+    }
+  else
+    {
+      rwlock->__rw_kind = attr->__lockkind;
+      rwlock->__rw_pshared = attr->__pshared;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_init, pthread_rwlock_init)
+
+
+int
+__pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+  int readers;
+  _pthread_descr writer;
+
+  __pthread_lock (&rwlock->__rw_lock, NULL);
+  readers = rwlock->__rw_readers;
+  writer = rwlock->__rw_writer;
+  __pthread_unlock (&rwlock->__rw_lock);
+
+  if (readers > 0 || writer != NULL)
+    return EBUSY;
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy)
+
+int
+__pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
+{
+  pthread_descr self = NULL;
+  pthread_readlock_info *existing;
+  int out_of_mem, have_lock_already;
+
+  have_lock_already = rwlock_have_already(&self, rwlock,
+					  &existing, &out_of_mem);
+
+  if (self == NULL)
+    self = thread_self ();
+
+  for (;;)
+    {
+      __pthread_lock (&rwlock->__rw_lock, self);
+
+      if (rwlock_can_rdlock(rwlock, have_lock_already))
+	break;
+
+      enqueue (&rwlock->__rw_read_waiting, self);
+      __pthread_unlock (&rwlock->__rw_lock);
+      suspend (self); /* This is not a cancellation point */
+    }
+
+  ++rwlock->__rw_readers;
+  __pthread_unlock (&rwlock->__rw_lock);
+
+  if (have_lock_already || out_of_mem)
+    {
+      if (existing != NULL)
+	++existing->pr_lock_count;
+      else
+	++self->p_untracked_readlock_count;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_rdlock, pthread_rwlock_rdlock)
+
+int
+__pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock,
+			      const struct timespec *abstime)
+{
+  pthread_descr self = NULL;
+  pthread_readlock_info *existing;
+  int out_of_mem, have_lock_already;
+  pthread_extricate_if extr;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  have_lock_already = rwlock_have_already(&self, rwlock,
+					  &existing, &out_of_mem);
+
+  if (self == NULL)
+    self = thread_self ();
+
+  /* Set up extrication interface */
+  extr.pu_object = rwlock;
+  extr.pu_extricate_func = rwlock_rd_extricate_func;
+
+  /* Register extrication interface */
+  __pthread_set_own_extricate_if (self, &extr);
+
+  for (;;)
+    {
+      __pthread_lock (&rwlock->__rw_lock, self);
+
+      if (rwlock_can_rdlock(rwlock, have_lock_already))
+	break;
+
+      enqueue (&rwlock->__rw_read_waiting, self);
+      __pthread_unlock (&rwlock->__rw_lock);
+      /* This is not a cancellation point */
+      if (timedsuspend (self, abstime) == 0)
+	{
+	  int was_on_queue;
+
+	  __pthread_lock (&rwlock->__rw_lock, self);
+	  was_on_queue = remove_from_queue (&rwlock->__rw_read_waiting, self);
+	  __pthread_unlock (&rwlock->__rw_lock);
+
+	  if (was_on_queue)
+	    {
+	      __pthread_set_own_extricate_if (self, 0);
+	      return ETIMEDOUT;
+	    }
+
+	  /* Eat the outstanding restart() from the signaller */
+	  suspend (self);
+	}
+    }
+
+  __pthread_set_own_extricate_if (self, 0);
+
+  ++rwlock->__rw_readers;
+  __pthread_unlock (&rwlock->__rw_lock);
+
+  if (have_lock_already || out_of_mem)
+    {
+      if (existing != NULL)
+	++existing->pr_lock_count;
+      else
+	++self->p_untracked_readlock_count;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_timedrdlock, pthread_rwlock_timedrdlock)
+
+int
+__pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+{
+  pthread_descr self = thread_self();
+  pthread_readlock_info *existing;
+  int out_of_mem, have_lock_already;
+  int retval = EBUSY;
+
+  have_lock_already = rwlock_have_already(&self, rwlock,
+      &existing, &out_of_mem);
+
+  __pthread_lock (&rwlock->__rw_lock, self);
+
+  /* 0 is passed to here instead of have_lock_already.
+     This is to meet Single Unix Spec requirements:
+     if writers are waiting, pthread_rwlock_tryrdlock
+     does not acquire a read lock, even if the caller has
+     one or more read locks already. */
+
+  if (rwlock_can_rdlock(rwlock, 0))
+    {
+      ++rwlock->__rw_readers;
+      retval = 0;
+    }
+
+  __pthread_unlock (&rwlock->__rw_lock);
+
+  if (retval == 0)
+    {
+      if (have_lock_already || out_of_mem)
+	{
+	  if (existing != NULL)
+	    ++existing->pr_lock_count;
+	  else
+	    ++self->p_untracked_readlock_count;
+	}
+    }
+
+  return retval;
+}
+strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock)
+
+
+int
+__pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
+{
+  pthread_descr self = thread_self ();
+
+  while(1)
+    {
+      __pthread_lock (&rwlock->__rw_lock, self);
+      if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
+	{
+	  rwlock->__rw_writer = self;
+	  __pthread_unlock (&rwlock->__rw_lock);
+	  return 0;
+	}
+
+      /* Suspend ourselves, then try again */
+      enqueue (&rwlock->__rw_write_waiting, self);
+      __pthread_unlock (&rwlock->__rw_lock);
+      suspend (self); /* This is not a cancellation point */
+    }
+}
+strong_alias (__pthread_rwlock_wrlock, pthread_rwlock_wrlock)
+
+
+int
+__pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock,
+			      const struct timespec *abstime)
+{
+  pthread_descr self;
+  pthread_extricate_if extr;
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
+    return EINVAL;
+
+  self = thread_self ();
+
+  /* Set up extrication interface */
+  extr.pu_object = rwlock;
+  extr.pu_extricate_func =  rwlock_wr_extricate_func;
+
+  /* Register extrication interface */
+  __pthread_set_own_extricate_if (self, &extr);
+
+  while(1)
+    {
+      __pthread_lock (&rwlock->__rw_lock, self);
+
+      if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
+	{
+	  rwlock->__rw_writer = self;
+	  __pthread_set_own_extricate_if (self, 0);
+	  __pthread_unlock (&rwlock->__rw_lock);
+	  return 0;
+	}
+
+      /* Suspend ourselves, then try again */
+      enqueue (&rwlock->__rw_write_waiting, self);
+      __pthread_unlock (&rwlock->__rw_lock);
+      /* This is not a cancellation point */
+      if (timedsuspend (self, abstime) == 0)
+	{
+	  int was_on_queue;
+
+	  __pthread_lock (&rwlock->__rw_lock, self);
+	  was_on_queue = remove_from_queue (&rwlock->__rw_write_waiting, self);
+	  __pthread_unlock (&rwlock->__rw_lock);
+
+	  if (was_on_queue)
+	    {
+	      __pthread_set_own_extricate_if (self, 0);
+	      return ETIMEDOUT;
+	    }
+
+	  /* Eat the outstanding restart() from the signaller */
+	  suspend (self);
+	}
+    }
+}
+strong_alias (__pthread_rwlock_timedwrlock, pthread_rwlock_timedwrlock)
+
+
+int
+__pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+{
+  int result = EBUSY;
+
+  __pthread_lock (&rwlock->__rw_lock, NULL);
+  if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL)
+    {
+      rwlock->__rw_writer = thread_self ();
+      result = 0;
+    }
+  __pthread_unlock (&rwlock->__rw_lock);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock)
+
+
+int
+__pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+{
+  pthread_descr torestart;
+  pthread_descr th;
+
+  __pthread_lock (&rwlock->__rw_lock, NULL);
+  if (rwlock->__rw_writer != NULL)
+    {
+      /* Unlocking a write lock.  */
+      if (rwlock->__rw_writer != thread_self ())
+	{
+	  __pthread_unlock (&rwlock->__rw_lock);
+	  return EPERM;
+	}
+      rwlock->__rw_writer = NULL;
+
+      if ((rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP
+	   && !queue_is_empty(&rwlock->__rw_read_waiting))
+	  || (th = dequeue(&rwlock->__rw_write_waiting)) == NULL)
+	{
+	  /* Restart all waiting readers.  */
+	  torestart = rwlock->__rw_read_waiting;
+	  rwlock->__rw_read_waiting = NULL;
+	  __pthread_unlock (&rwlock->__rw_lock);
+	  while ((th = dequeue (&torestart)) != NULL)
+	    restart (th);
+	}
+      else
+	{
+	  /* Restart one waiting writer.  */
+	  __pthread_unlock (&rwlock->__rw_lock);
+	  restart (th);
+	}
+    }
+  else
+    {
+      /* Unlocking a read lock.  */
+      if (rwlock->__rw_readers == 0)
+	{
+	  __pthread_unlock (&rwlock->__rw_lock);
+	  return EPERM;
+	}
+
+      --rwlock->__rw_readers;
+      if (rwlock->__rw_readers == 0)
+	/* Restart one waiting writer, if any.  */
+	th = dequeue (&rwlock->__rw_write_waiting);
+      else
+	th = NULL;
+
+      __pthread_unlock (&rwlock->__rw_lock);
+      if (th != NULL)
+	restart (th);
+
+      /* Recursive lock fixup */
+
+      if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP)
+	{
+	  pthread_descr self = thread_self();
+	  pthread_readlock_info *victim = rwlock_remove_from_list(self, rwlock);
+
+	  if (victim != NULL)
+	    {
+	      if (victim->pr_lock_count == 0)
+		{
+		  victim->pr_next = THREAD_GETMEM (self, p_readlock_free);
+		  THREAD_SETMEM (self, p_readlock_free, victim);
+		}
+	    }
+	  else
+	    {
+	      int val = THREAD_GETMEM (self, p_untracked_readlock_count);
+	      if (val > 0)
+		THREAD_SETMEM (self, p_untracked_readlock_count, val - 1);
+	    }
+	}
+    }
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_unlock, pthread_rwlock_unlock)
+
+
+
+int
+pthread_rwlockattr_init (pthread_rwlockattr_t *attr)
+{
+  attr->__lockkind = 0;
+  attr->__pshared = PTHREAD_PROCESS_PRIVATE;
+
+  return 0;
+}
+
+
+int
+__pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr)
+{
+  return 0;
+}
+strong_alias (__pthread_rwlockattr_destroy, pthread_rwlockattr_destroy)
+
+
+int
+pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared)
+{
+  *pshared = attr->__pshared;
+  return 0;
+}
+
+
+int
+pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared)
+{
+  if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
+    return EINVAL;
+
+  /* For now it is not possible to shared a conditional variable.  */
+  if (pshared != PTHREAD_PROCESS_PRIVATE)
+    return ENOSYS;
+
+  attr->__pshared = pshared;
+
+  return 0;
+}
+
+
+int
+pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref)
+{
+  *pref = attr->__lockkind;
+  return 0;
+}
+
+
+int
+pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref)
+{
+  if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
+      && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP
+      && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
+      && pref != PTHREAD_RWLOCK_DEFAULT_NP)
+    return EINVAL;
+
+  attr->__lockkind = pref;
+
+  return 0;
+}

+ 298 - 0
libpthread/linuxthreads/semaphore.c

@@ -0,0 +1,298 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Semaphores a la POSIX 1003.1b */
+
+#include <errno.h>
+#include "pthread.h"
+#include "semaphore.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+#include "queue.h"
+#include <not-cancel.h>
+
+int sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+  if (value > SEM_VALUE_MAX) {
+    errno = EINVAL;
+    return -1;
+  }
+  if (pshared) {
+    errno = ENOSYS;
+    return -1;
+  }
+  __pthread_init_lock(&sem->__sem_lock);
+  sem->__sem_value = value;
+  sem->__sem_waiting = NULL;
+  return 0;
+}
+
+/* Function called by pthread_cancel to remove the thread from
+   waiting inside sem_wait. */
+
+static int new_sem_extricate_func(void *obj, pthread_descr th)
+{
+  volatile pthread_descr self = thread_self();
+  sem_t *sem = obj;
+  int did_remove = 0;
+
+  __pthread_lock(&sem->__sem_lock, self);
+  did_remove = remove_from_queue(&sem->__sem_waiting, th);
+  __pthread_unlock(&sem->__sem_lock);
+
+  return did_remove;
+}
+
+int sem_wait(sem_t * sem)
+{
+  volatile pthread_descr self = thread_self();
+  pthread_extricate_if extr;
+  int already_canceled = 0;
+  int spurious_wakeup_count;
+
+  /* Set up extrication interface */
+  extr.pu_object = sem;
+  extr.pu_extricate_func = new_sem_extricate_func;
+
+  __pthread_lock(&sem->__sem_lock, self);
+  if (sem->__sem_value > 0) {
+    sem->__sem_value--;
+    __pthread_unlock(&sem->__sem_lock);
+    return 0;
+  }
+  /* Register extrication interface */
+  THREAD_SETMEM(self, p_sem_avail, 0);
+  __pthread_set_own_extricate_if(self, &extr);
+  /* Enqueue only if not already cancelled. */
+  if (!(THREAD_GETMEM(self, p_canceled)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
+    enqueue(&sem->__sem_waiting, self);
+  else
+    already_canceled = 1;
+  __pthread_unlock(&sem->__sem_lock);
+
+  if (already_canceled) {
+    __pthread_set_own_extricate_if(self, 0);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+
+  /* Wait for sem_post or cancellation, or fall through if already canceled */
+  spurious_wakeup_count = 0;
+  while (1)
+    {
+      suspend(self);
+      if (THREAD_GETMEM(self, p_sem_avail) == 0
+	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+	{
+	  /* Count resumes that don't belong to us. */
+	  spurious_wakeup_count++;
+	  continue;
+	}
+      break;
+    }
+  __pthread_set_own_extricate_if(self, 0);
+
+  /* Terminate only if the wakeup came from cancellation. */
+  /* Otherwise ignore cancellation because we got the semaphore. */
+
+  if (THREAD_GETMEM(self, p_woken_by_cancel)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+    THREAD_SETMEM(self, p_woken_by_cancel, 0);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+  /* We got the semaphore */
+  return 0;
+}
+
+int sem_trywait(sem_t * sem)
+{
+  int retval;
+
+  __pthread_lock(&sem->__sem_lock, NULL);
+  if (sem->__sem_value == 0) {
+    errno = EAGAIN;
+    retval = -1;
+  } else {
+    sem->__sem_value--;
+    retval = 0;
+  }
+  __pthread_unlock(&sem->__sem_lock);
+  return retval;
+}
+
+int sem_post(sem_t * sem)
+{
+  pthread_descr self = thread_self();
+  pthread_descr th;
+  struct pthread_request request;
+
+  if (THREAD_GETMEM(self, p_in_sighandler) == NULL) {
+    __pthread_lock(&sem->__sem_lock, self);
+    if (sem->__sem_waiting == NULL) {
+      if (sem->__sem_value >= SEM_VALUE_MAX) {
+        /* Overflow */
+        errno = ERANGE;
+        __pthread_unlock(&sem->__sem_lock);
+        return -1;
+      }
+      sem->__sem_value++;
+      __pthread_unlock(&sem->__sem_lock);
+    } else {
+      th = dequeue(&sem->__sem_waiting);
+      __pthread_unlock(&sem->__sem_lock);
+      th->p_sem_avail = 1;
+      WRITE_MEMORY_BARRIER();
+      restart(th);
+    }
+  } else {
+    /* If we're in signal handler, delegate post operation to
+       the thread manager. */
+    if (__pthread_manager_request < 0) {
+      if (__pthread_initialize_manager() < 0) {
+        errno = EAGAIN;
+        return -1;
+      }
+    }
+    request.req_kind = REQ_POST;
+    request.req_args.post = sem;
+    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					(char *) &request, sizeof(request)));
+  }
+  return 0;
+}
+
+int sem_getvalue(sem_t * sem, int * sval)
+{
+  *sval = sem->__sem_value;
+  return 0;
+}
+
+int sem_destroy(sem_t * sem)
+{
+  if (sem->__sem_waiting != NULL) {
+    __set_errno (EBUSY);
+    return -1;
+  }
+  return 0;
+}
+
+sem_t *sem_open(const char *name, int oflag, ...)
+{
+  __set_errno (ENOSYS);
+  return SEM_FAILED;
+}
+
+int sem_close(sem_t *sem)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+
+int sem_unlink(const char *name)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+
+int sem_timedwait(sem_t *sem, const struct timespec *abstime)
+{
+  pthread_descr self = thread_self();
+  pthread_extricate_if extr;
+  int already_canceled = 0;
+  int spurious_wakeup_count;
+
+  __pthread_lock(&sem->__sem_lock, self);
+  if (sem->__sem_value > 0) {
+    --sem->__sem_value;
+    __pthread_unlock(&sem->__sem_lock);
+    return 0;
+  }
+
+  if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
+    /* The standard requires that if the function would block and the
+       time value is illegal, the function returns with an error.  */
+    __pthread_unlock(&sem->__sem_lock);
+    __set_errno (EINVAL);
+    return -1;
+  }
+
+  /* Set up extrication interface */
+  extr.pu_object = sem;
+  extr.pu_extricate_func = new_sem_extricate_func;
+
+  /* Register extrication interface */
+  THREAD_SETMEM(self, p_sem_avail, 0);
+  __pthread_set_own_extricate_if(self, &extr);
+  /* Enqueue only if not already cancelled. */
+  if (!(THREAD_GETMEM(self, p_canceled)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
+    enqueue(&sem->__sem_waiting, self);
+  else
+    already_canceled = 1;
+  __pthread_unlock(&sem->__sem_lock);
+
+  if (already_canceled) {
+    __pthread_set_own_extricate_if(self, 0);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+
+  spurious_wakeup_count = 0;
+  while (1)
+    {
+      if (timedsuspend(self, abstime) == 0) {
+	int was_on_queue;
+
+	/* __pthread_lock will queue back any spurious restarts that
+	   may happen to it. */
+
+	__pthread_lock(&sem->__sem_lock, self);
+	was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
+	__pthread_unlock(&sem->__sem_lock);
+
+	if (was_on_queue) {
+	  __pthread_set_own_extricate_if(self, 0);
+	  __set_errno (ETIMEDOUT);
+	  return -1;
+	}
+
+	/* Eat the outstanding restart() from the signaller */
+	suspend(self);
+      }
+
+      if (THREAD_GETMEM(self, p_sem_avail) == 0
+	  && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
+	      || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
+	{
+	  /* Count resumes that don't belong to us. */
+	  spurious_wakeup_count++;
+	  continue;
+	}
+      break;
+    }
+
+ __pthread_set_own_extricate_if(self, 0);
+
+  /* Terminate only if the wakeup came from cancellation. */
+  /* Otherwise ignore cancellation because we got the semaphore. */
+
+  if (THREAD_GETMEM(self, p_woken_by_cancel)
+      && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
+    THREAD_SETMEM(self, p_woken_by_cancel, 0);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
+  }
+  /* We got the semaphore */
+  return 0;
+}

+ 87 - 0
libpthread/linuxthreads/semaphore.h

@@ -0,0 +1,87 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+#ifndef _SEMAPHORE_H
+#define _SEMAPHORE_H    1
+
+#include <features.h>
+#include <sys/types.h>
+#ifdef __USE_XOPEN2K
+# define __need_timespec
+# include <time.h>
+#endif
+
+#ifndef _PTHREAD_DESCR_DEFINED
+/* Thread descriptors.  Needed for `sem_t' definition.  */
+typedef struct _pthread_descr_struct *_pthread_descr;
+# define _PTHREAD_DESCR_DEFINED
+#endif
+
+/* System specific semaphore definition.  */
+typedef struct
+{
+  struct _pthread_fastlock __sem_lock;
+  int __sem_value;
+  _pthread_descr __sem_waiting;
+} sem_t;
+
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED	((sem_t *) 0)
+
+/* Maximum value the semaphore can have.  */
+#define SEM_VALUE_MAX 	(2147483647)
+
+
+__BEGIN_DECLS
+
+/* Initialize semaphore object SEM to VALUE.  If PSHARED then share it
+   with other processes.  */
+extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) __THROW;
+
+/* Free resources associated with semaphore object SEM.  */
+extern int sem_destroy (sem_t *__sem) __THROW;
+
+/* Open a named semaphore NAME with open flaot OFLAG.  */
+extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW;
+
+/* Close descriptor for named semaphore SEM.  */
+extern int sem_close (sem_t *__sem) __THROW;
+
+/* Remove named semaphore NAME.  */
+extern int sem_unlink (__const char *__name) __THROW;
+
+/* Wait for SEM being posted.  */
+extern int sem_wait (sem_t *__sem);
+
+#ifdef __USE_XOPEN2K
+/* Similar to `sem_wait' but wait only until ABSTIME.  */
+extern int sem_timedwait (sem_t *__restrict __sem,
+			  __const struct timespec *__restrict __abstime);
+#endif
+
+/* Test whether SEM is posted.  */
+extern int sem_trywait (sem_t *__sem) __THROW;
+
+/* Post SEM.  */
+extern int sem_post (sem_t *__sem) __THROW;
+
+/* Get current value of SEM and store it in *SVAL.  */
+extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval)
+     __THROW;
+
+__END_DECLS
+
+#endif  /* semaphore.h */

+ 71 - 0
libpthread/linuxthreads/sighandler.c

@@ -0,0 +1,71 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Signal handlers */
+
+#include "internals.h"
+
+
+/* The wrapper around user-provided signal handlers */
+void __pthread_sighandler(int signo, SIGCONTEXT ctx)
+{
+  pthread_descr self;
+  char * in_sighandler;
+  self = check_thread_self();
+
+  /* If we're in a sigwait operation, just record the signal received
+     and return without calling the user's handler */
+  if (THREAD_GETMEM(self, p_sigwaiting)) {
+    THREAD_SETMEM(self, p_sigwaiting, 0);
+    THREAD_SETMEM(self, p_signal, signo);
+    return;
+  }
+  /* Record that we're in a signal handler and call the user's
+     handler function */
+  in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
+  if (in_sighandler == NULL)
+    THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
+  CALL_SIGHANDLER(__sighandler[signo].old, signo, ctx);
+  if (in_sighandler == NULL)
+    THREAD_SETMEM(self, p_in_sighandler, NULL);
+}
+
+/* The same, this time for real-time signals.  */
+void __pthread_sighandler_rt(int signo, struct siginfo *si,
+			     struct ucontext *uc)
+{
+  pthread_descr self;
+  char * in_sighandler;
+  self = check_thread_self();
+
+  /* If we're in a sigwait operation, just record the signal received
+     and return without calling the user's handler */
+  if (THREAD_GETMEM(self, p_sigwaiting)) {
+    THREAD_SETMEM(self, p_sigwaiting, 0);
+    THREAD_SETMEM(self, p_signal, signo);
+    return;
+  }
+  /* Record that we're in a signal handler and call the user's
+     handler function */
+  in_sighandler = THREAD_GETMEM(self, p_in_sighandler);
+  if (in_sighandler == NULL)
+    THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME);
+  __sighandler[signo].rt(signo, si, uc);
+  if (in_sighandler == NULL)
+    THREAD_SETMEM(self, p_in_sighandler, NULL);
+}
+
+
+/* A signal handler that does nothing */
+void __pthread_null_sighandler(int sig) { }

+ 215 - 0
libpthread/linuxthreads/signals.c

@@ -0,0 +1,215 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Handling of signals */
+
+#include <errno.h>
+#include <signal.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include <ucontext.h>
+
+/* mods for uClibc: __libc_sigaction is not in any standard headers */
+extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact);
+
+int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
+{
+  sigset_t mask;
+
+  if (newmask != NULL) {
+    mask = *newmask;
+    /* Don't allow __pthread_sig_restart to be unmasked.
+       Don't allow __pthread_sig_cancel to be masked. */
+    switch(how) {
+    case SIG_SETMASK:
+      sigaddset(&mask, __pthread_sig_restart);
+      sigdelset(&mask, __pthread_sig_cancel);
+      if (__pthread_sig_debug > 0)
+	sigdelset(&mask, __pthread_sig_debug);
+      break;
+    case SIG_BLOCK:
+      sigdelset(&mask, __pthread_sig_cancel);
+      if (__pthread_sig_debug > 0)
+	sigdelset(&mask, __pthread_sig_debug);
+      break;
+    case SIG_UNBLOCK:
+      sigdelset(&mask, __pthread_sig_restart);
+      break;
+    }
+    newmask = &mask;
+  }
+  if (sigprocmask(how, newmask, oldmask) == -1)
+    return errno;
+  else
+    return 0;
+}
+
+int pthread_kill(pthread_t thread, int signo)
+{
+  pthread_handle handle = thread_handle(thread);
+  int pid;
+
+  __pthread_lock(&handle->h_lock, NULL);
+  if (invalid_handle(handle, thread)) {
+    __pthread_unlock(&handle->h_lock);
+    return ESRCH;
+  }
+  pid = handle->h_descr->p_pid;
+  __pthread_unlock(&handle->h_lock);
+  if (kill(pid, signo) == -1)
+    return errno;
+  else
+    return 0;
+}
+
+union sighandler __sighandler[NSIG] =
+  { [1 ... NSIG - 1] = { (arch_sighandler_t) SIG_ERR } };
+
+/* The wrapper around sigaction.  Install our own signal handler
+   around the signal. */
+int __pthread_sigaction(int sig, const struct sigaction * act,
+			struct sigaction * oact)
+{
+  struct sigaction newact;
+  struct sigaction *newactp;
+  __sighandler_t old = SIG_DFL;
+
+  if (sig == __pthread_sig_restart ||
+      sig == __pthread_sig_cancel ||
+      (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+  if (sig > 0 && sig < NSIG)
+    old = (__sighandler_t) __sighandler[sig].old;
+  if (act)
+    {
+      newact = *act;
+      if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
+	  && sig > 0 && sig < NSIG)
+	{
+	  if (act->sa_flags & SA_SIGINFO)
+	    newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
+	  else
+	    newact.sa_handler = (__sighandler_t) __pthread_sighandler;
+	  if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR)
+	    __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
+	}
+      newactp = &newact;
+    }
+  else
+    newactp = NULL;
+  if (__libc_sigaction(sig, newactp, oact) == -1)
+    {
+      if (act)
+	__sighandler[sig].old = (arch_sighandler_t) old;
+      return -1;
+    }
+  if (sig > 0 && sig < NSIG)
+    {
+      if (oact != NULL
+	  /* We may have inherited SIG_IGN from the parent, so return the
+	     kernel's idea of the signal handler the first time
+	     through.  */
+	  && old != SIG_ERR)
+	oact->sa_handler = old;
+      if (act)
+	/* For the assignment it does not matter whether it's a normal
+	   or real-time signal.  */
+	__sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
+    }
+  return 0;
+}
+#ifdef SHARED
+strong_alias(__pthread_sigaction, __sigaction)
+strong_alias(__pthread_sigaction, sigaction)
+#endif
+
+/* sigwait -- synchronously wait for a signal */
+int __pthread_sigwait(const sigset_t * set, int * sig)
+{
+  volatile pthread_descr self = thread_self();
+  sigset_t mask;
+  int s;
+  sigjmp_buf jmpbuf;
+  struct sigaction sa;
+
+  /* Get ready to block all signals except those in set
+     and the cancellation signal.
+     Also check that handlers are installed on all signals in set,
+     and if not, install our dummy handler.  This is conformant to
+     POSIX: "The effect of sigwait() on the signal actions for the
+     signals in set is unspecified." */
+  sigfillset(&mask);
+  sigdelset(&mask, __pthread_sig_cancel);
+  for (s = 1; s < NSIG; s++) {
+    if (sigismember(set, s) &&
+        s != __pthread_sig_restart &&
+        s != __pthread_sig_cancel &&
+        s != __pthread_sig_debug) {
+      sigdelset(&mask, s);
+      if (__sighandler[s].old == (arch_sighandler_t) SIG_ERR ||
+          __sighandler[s].old == (arch_sighandler_t) SIG_DFL ||
+          __sighandler[s].old == (arch_sighandler_t) SIG_IGN) {
+        sa.sa_handler = __pthread_null_sighandler;
+        sigfillset(&sa.sa_mask);
+        sa.sa_flags = 0;
+        sigaction(s, &sa, NULL);
+      }
+    }
+  }
+  /* Test for cancellation */
+  if (sigsetjmp(jmpbuf, 1) == 0) {
+    THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf);
+    if (! (THREAD_GETMEM(self, p_canceled)
+	   && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) {
+      /* Reset the signal count */
+      THREAD_SETMEM(self, p_signal, 0);
+      /* Say we're in sigwait */
+      THREAD_SETMEM(self, p_sigwaiting, 1);
+      /* Unblock the signals and wait for them */
+      sigsuspend(&mask);
+    }
+  }
+  THREAD_SETMEM(self, p_cancel_jmp, NULL);
+  /* The signals are now reblocked.  Check for cancellation */
+  pthread_testcancel();
+  /* We should have self->p_signal != 0 and equal to the signal received */
+  *sig = THREAD_GETMEM(self, p_signal);
+  return 0;
+}
+#ifdef SHARED
+strong_alias (__pthread_sigwait, sigwait)
+#endif
+
+/* Redefine raise() to send signal to calling thread only,
+   as per POSIX 1003.1c */
+int __pthread_raise (int sig)
+{
+  int retcode = pthread_kill(pthread_self(), sig);
+  if (retcode == 0)
+    return 0;
+  else {
+    errno = retcode;
+    return -1;
+  }
+}
+#ifdef SHARED
+strong_alias (__pthread_raise, raise)
+#endif
+
+/* This files handles cancellation internally.  */
+LIBC_CANCEL_HANDLED ();

+ 241 - 0
libpthread/linuxthreads/specific.c

@@ -0,0 +1,241 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Thread-specific data */
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+#include <bits/libc-lock.h>
+#include <not-cancel.h>
+
+/* Table of keys. */
+
+static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] =
+  { { 0, NULL } };
+
+/* For debugging purposes put the maximum number of keys in a variable.  */
+const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX;
+const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
+
+/* Mutex to protect access to pthread_keys */
+
+static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Create a new key */
+
+int __pthread_key_create(pthread_key_t * key, destr_function destr)
+{
+  int i;
+
+  pthread_mutex_lock(&pthread_keys_mutex);
+  for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
+    if (! pthread_keys[i].in_use) {
+      /* Mark key in use */
+      pthread_keys[i].in_use = 1;
+      pthread_keys[i].destr = destr;
+      pthread_mutex_unlock(&pthread_keys_mutex);
+      *key = i;
+      return 0;
+    }
+  }
+  pthread_mutex_unlock(&pthread_keys_mutex);
+  return EAGAIN;
+}
+strong_alias (__pthread_key_create, pthread_key_create)
+
+/* Reset deleted key's value to NULL in each live thread.
+ * NOTE: this executes in the context of the thread manager! */
+
+struct pthread_key_delete_helper_args {
+  /* Damn, we need lexical closures in C! ;) */
+  unsigned int idx1st, idx2nd;
+  pthread_descr self;
+};
+
+static void pthread_key_delete_helper(void *arg, pthread_descr th)
+{
+  struct pthread_key_delete_helper_args *args = arg;
+  unsigned int idx1st = args->idx1st;
+  unsigned int idx2nd = args->idx2nd;
+  pthread_descr self = args->self;
+
+  if (self == 0)
+    self = args->self = thread_self();
+
+  if (!th->p_terminated) {
+    /* pthread_exit() may try to free th->p_specific[idx1st] concurrently. */
+    __pthread_lock(th->p_lock, self);
+    if (th->p_specific[idx1st] != NULL)
+      th->p_specific[idx1st][idx2nd] = NULL;
+    __pthread_unlock(th->p_lock);
+  }
+}
+
+/* Delete a key */
+int pthread_key_delete(pthread_key_t key)
+{
+  pthread_descr self = thread_self();
+
+  pthread_mutex_lock(&pthread_keys_mutex);
+  if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
+    pthread_mutex_unlock(&pthread_keys_mutex);
+    return EINVAL;
+  }
+  pthread_keys[key].in_use = 0;
+  pthread_keys[key].destr = NULL;
+
+  /* Set the value of the key to NULL in all running threads, so
+     that if the key is reallocated later by pthread_key_create, its
+     associated values will be NULL in all threads.
+
+     If no threads have been created yet, clear it just in the
+     current thread.  */
+
+  struct pthread_key_delete_helper_args args;
+  args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+  args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+  if (__pthread_manager_request != -1)
+    {
+      struct pthread_request request;
+
+      args.self = 0;
+
+      request.req_thread = self;
+      request.req_kind = REQ_FOR_EACH_THREAD;
+      request.req_args.for_each.arg = &args;
+      request.req_args.for_each.fn = pthread_key_delete_helper;
+
+      TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
+					  (char *) &request, sizeof(request)));
+      suspend(self);
+    }
+  else
+    {
+      if (self->p_specific[args.idx1st] != NULL)
+	self->p_specific[args.idx1st][args.idx2nd] = NULL;
+    }
+
+  pthread_mutex_unlock(&pthread_keys_mutex);
+  return 0;
+}
+
+/* Set the value of a key */
+
+int __pthread_setspecific(pthread_key_t key, const void * pointer)
+{
+  pthread_descr self = thread_self();
+  unsigned int idx1st, idx2nd;
+
+  if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use)
+    return EINVAL;
+  idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+  idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+  if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) {
+    void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *));
+    if (newp == NULL)
+      return ENOMEM;
+    THREAD_SETMEM_NC(self, p_specific[idx1st], newp);
+  }
+  THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer;
+  return 0;
+}
+strong_alias (__pthread_setspecific, pthread_setspecific)
+
+/* Get the value of a key */
+
+void * __pthread_getspecific(pthread_key_t key)
+{
+  pthread_descr self = thread_self();
+  unsigned int idx1st, idx2nd;
+
+  if (key >= PTHREAD_KEYS_MAX)
+    return NULL;
+  idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+  idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+  if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL
+      || !pthread_keys[key].in_use)
+    return NULL;
+  return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd];
+}
+strong_alias (__pthread_getspecific, pthread_getspecific)
+
+/* Call the destruction routines on all keys */
+
+void __pthread_destroy_specifics()
+{
+  pthread_descr self = thread_self();
+  int i, j, round, found_nonzero;
+  destr_function destr;
+  void * data;
+
+  for (round = 0, found_nonzero = 1;
+       found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
+       round++) {
+    found_nonzero = 0;
+    for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
+      if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL)
+        for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) {
+          destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr;
+          data = THREAD_GETMEM_NC(self, p_specific[i])[j];
+          if (destr != NULL && data != NULL) {
+            THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL;
+            destr(data);
+            found_nonzero = 1;
+          }
+        }
+  }
+  __pthread_lock(THREAD_GETMEM(self, p_lock), self);
+  for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
+    if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
+      free(THREAD_GETMEM_NC(self, p_specific[i]));
+      THREAD_SETMEM_NC(self, p_specific[i], NULL);
+    }
+  }
+  __pthread_unlock(THREAD_GETMEM(self, p_lock));
+}
+
+#if !(USE_TLS && HAVE___THREAD)
+
+/* Thread-specific data for libc. */
+
+int
+__pthread_internal_tsd_set (int key, const void * pointer)
+{
+  pthread_descr self = thread_self();
+
+  THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer);
+  return 0;
+}
+
+void *
+__pthread_internal_tsd_get (int key)
+{
+  pthread_descr self = thread_self();
+
+  return THREAD_GETMEM_NC(self, p_libc_specific[key]);
+}
+
+void ** __attribute__ ((__const__))
+__pthread_internal_tsd_address (int key)
+{
+  pthread_descr self = thread_self();
+  return &self->p_libc_specific[key];
+}
+
+#endif

+ 720 - 0
libpthread/linuxthreads/spinlock.c

@@ -0,0 +1,720 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+/* Internal locks */
+
+#include <errno.h>
+#include <sched.h>
+#include <time.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "pthread.h"
+#include "internals.h"
+#include "spinlock.h"
+#include "restart.h"
+
+static void __pthread_acquire(int * spinlock);
+
+static inline void __pthread_release(int * spinlock)
+{
+  WRITE_MEMORY_BARRIER();
+  *spinlock = __LT_SPINLOCK_INIT;
+  __asm __volatile ("" : "=m" (*spinlock) : "m" (*spinlock));
+}
+
+
+/* The status field of a spinlock is a pointer whose least significant
+   bit is a locked flag.
+
+   Thus the field values have the following meanings:
+
+   status == 0:       spinlock is free
+   status == 1:       spinlock is taken; no thread is waiting on it
+
+   (status & 1) == 1: spinlock is taken and (status & ~1L) is a
+                      pointer to the first waiting thread; other
+		      waiting threads are linked via the p_nextlock
+		      field.
+   (status & 1) == 0: same as above, but spinlock is not taken.
+
+   The waiting list is not sorted by priority order.
+   Actually, we always insert at top of list (sole insertion mode
+   that can be performed without locking).
+   For __pthread_unlock, we perform a linear search in the list
+   to find the highest-priority, oldest waiting thread.
+   This is safe because there are no concurrent __pthread_unlock
+   operations -- only the thread that locked the mutex can unlock it. */
+
+
+void internal_function __pthread_lock(struct _pthread_fastlock * lock,
+				      pthread_descr self)
+{
+#if defined HAS_COMPARE_AND_SWAP
+  long oldstatus, newstatus;
+  int successful_seizure, spurious_wakeup_count;
+  int spin_count;
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_acquire(&lock->__spinlock);
+    return;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  /* First try it without preparation.  Maybe it's a completely
+     uncontested lock.  */
+  if (lock->__status == 0 && __compare_and_swap (&lock->__status, 0, 1))
+    return;
+
+  spurious_wakeup_count = 0;
+  spin_count = 0;
+
+  /* On SMP, try spinning to get the lock. */
+
+  if (__pthread_smp_kernel) {
+    int max_count = lock->__spinlock * 2 + 10;
+
+    if (max_count > MAX_ADAPTIVE_SPIN_COUNT)
+      max_count = MAX_ADAPTIVE_SPIN_COUNT;
+
+    for (spin_count = 0; spin_count < max_count; spin_count++) {
+      if (((oldstatus = lock->__status) & 1) == 0) {
+	if(__compare_and_swap(&lock->__status, oldstatus, oldstatus | 1))
+	{
+	  if (spin_count)
+	    lock->__spinlock += (spin_count - lock->__spinlock) / 8;
+	  READ_MEMORY_BARRIER();
+	  return;
+	}
+      }
+#ifdef BUSY_WAIT_NOP
+      BUSY_WAIT_NOP;
+#endif
+      __asm __volatile ("" : "=m" (lock->__status) : "m" (lock->__status));
+    }
+
+    lock->__spinlock += (spin_count - lock->__spinlock) / 8;
+  }
+
+again:
+
+  /* No luck, try once more or suspend. */
+
+  do {
+    oldstatus = lock->__status;
+    successful_seizure = 0;
+
+    if ((oldstatus & 1) == 0) {
+      newstatus = oldstatus | 1;
+      successful_seizure = 1;
+    } else {
+      if (self == NULL)
+	self = thread_self();
+      newstatus = (long) self | 1;
+    }
+
+    if (self != NULL) {
+      THREAD_SETMEM(self, p_nextlock, (pthread_descr) (oldstatus));
+      /* Make sure the store in p_nextlock completes before performing
+         the compare-and-swap */
+      MEMORY_BARRIER();
+    }
+  } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
+
+  /* Suspend with guard against spurious wakeup.
+     This can happen in pthread_cond_timedwait_relative, when the thread
+     wakes up due to timeout and is still on the condvar queue, and then
+     locks the queue to remove itself. At that point it may still be on the
+     queue, and may be resumed by a condition signal. */
+
+  if (!successful_seizure) {
+    for (;;) {
+      suspend(self);
+      if (self->p_nextlock != NULL) {
+	/* Count resumes that don't belong to us. */
+	spurious_wakeup_count++;
+	continue;
+      }
+      break;
+    }
+    goto again;
+  }
+
+  /* Put back any resumes we caught that don't belong to us. */
+  while (spurious_wakeup_count--)
+    restart(self);
+
+  READ_MEMORY_BARRIER();
+#endif
+}
+
+int __pthread_unlock(struct _pthread_fastlock * lock)
+{
+#if defined HAS_COMPARE_AND_SWAP
+  long oldstatus;
+  pthread_descr thr, * ptr, * maxptr;
+  int maxprio;
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_release(&lock->__spinlock);
+    return 0;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  WRITE_MEMORY_BARRIER();
+
+again:
+  while ((oldstatus = lock->__status) == 1) {
+    if (__compare_and_swap_with_release_semantics(&lock->__status,
+	oldstatus, 0))
+      return 0;
+  }
+
+  /* Find thread in waiting queue with maximal priority */
+  ptr = (pthread_descr *) &lock->__status;
+  thr = (pthread_descr) (oldstatus & ~1L);
+  maxprio = 0;
+  maxptr = ptr;
+
+  /* Before we iterate over the wait queue, we need to execute
+     a read barrier, otherwise we may read stale contents of nodes that may
+     just have been inserted by other processors. One read barrier is enough to
+     ensure we have a stable list; we don't need one for each pointer chase
+     through the list, because we are the owner of the lock; other threads
+     can only add nodes at the front; if a front node is consistent,
+     the ones behind it must also be. */
+
+  READ_MEMORY_BARRIER();
+
+  while (thr != 0) {
+    if (thr->p_priority >= maxprio) {
+      maxptr = ptr;
+      maxprio = thr->p_priority;
+    }
+    ptr = &(thr->p_nextlock);
+    thr = (pthread_descr)((long)(thr->p_nextlock) & ~1L);
+  }
+
+  /* Remove max prio thread from waiting list. */
+  if (maxptr == (pthread_descr *) &lock->__status) {
+    /* If max prio thread is at head, remove it with compare-and-swap
+       to guard against concurrent lock operation. This removal
+       also has the side effect of marking the lock as released
+       because the new status comes from thr->p_nextlock whose
+       least significant bit is clear. */
+    thr = (pthread_descr) (oldstatus & ~1L);
+    if (! __compare_and_swap_with_release_semantics
+	    (&lock->__status, oldstatus, (long)(thr->p_nextlock) & ~1L))
+      goto again;
+  } else {
+    /* No risk of concurrent access, remove max prio thread normally.
+       But in this case we must also flip the least significant bit
+       of the status to mark the lock as released. */
+    thr = (pthread_descr)((long)*maxptr & ~1L);
+    *maxptr = thr->p_nextlock;
+
+    /* Ensure deletion from linked list completes before we
+       release the lock. */
+    WRITE_MEMORY_BARRIER();
+
+    do {
+      oldstatus = lock->__status;
+    } while (!__compare_and_swap_with_release_semantics(&lock->__status,
+	     oldstatus, oldstatus & ~1L));
+  }
+
+  /* Wake up the selected waiting thread. Woken thread can check
+     its own p_nextlock field for NULL to detect that it has been removed. No
+     barrier is needed here, since restart() and suspend() take
+     care of memory synchronization. */
+
+  thr->p_nextlock = NULL;
+  restart(thr);
+
+  return 0;
+#endif
+}
+
+/*
+ * Alternate fastlocks do not queue threads directly. Instead, they queue
+ * these wait queue node structures. When a timed wait wakes up due to
+ * a timeout, it can leave its wait node in the queue (because there
+ * is no safe way to remove from the quue). Some other thread will
+ * deallocate the abandoned node.
+ */
+
+
+struct wait_node {
+  struct wait_node *next;	/* Next node in null terminated linked list */
+  pthread_descr thr;		/* The thread waiting with this node */
+  int abandoned;		/* Atomic flag */
+};
+
+static long wait_node_free_list;
+static int wait_node_free_list_spinlock;
+
+/* Allocate a new node from the head of the free list using an atomic
+   operation, or else using malloc if that list is empty.  A fundamental
+   assumption here is that we can safely access wait_node_free_list->next.
+   That's because we never free nodes once we allocate them, so a pointer to a
+   node remains valid indefinitely. */
+
+static struct wait_node *wait_node_alloc(void)
+{
+    struct wait_node *new_node = 0;
+
+    __pthread_acquire(&wait_node_free_list_spinlock);
+    if (wait_node_free_list != 0) {
+      new_node = (struct wait_node *) wait_node_free_list;
+      wait_node_free_list = (long) new_node->next;
+    }
+    WRITE_MEMORY_BARRIER();
+    __pthread_release(&wait_node_free_list_spinlock);
+
+    if (new_node == 0)
+      return malloc(sizeof *wait_node_alloc());
+
+    return new_node;
+}
+
+/* Return a node to the head of the free list using an atomic
+   operation. */
+
+static void wait_node_free(struct wait_node *wn)
+{
+    __pthread_acquire(&wait_node_free_list_spinlock);
+    wn->next = (struct wait_node *) wait_node_free_list;
+    wait_node_free_list = (long) wn;
+    WRITE_MEMORY_BARRIER();
+    __pthread_release(&wait_node_free_list_spinlock);
+    return;
+}
+
+#if defined HAS_COMPARE_AND_SWAP
+
+/* Remove a wait node from the specified queue.  It is assumed
+   that the removal takes place concurrently with only atomic insertions at the
+   head of the queue. */
+
+static void wait_node_dequeue(struct wait_node **pp_head,
+			      struct wait_node **pp_node,
+			      struct wait_node *p_node)
+{
+  /* If the node is being deleted from the head of the
+     list, it must be deleted using atomic compare-and-swap.
+     Otherwise it can be deleted in the straightforward way. */
+
+  if (pp_node == pp_head) {
+    /* We don't need a read barrier between these next two loads,
+       because it is assumed that the caller has already ensured
+       the stability of *p_node with respect to p_node. */
+
+    long oldvalue = (long) p_node;
+    long newvalue = (long) p_node->next;
+
+    if (__compare_and_swap((long *) pp_node, oldvalue, newvalue))
+      return;
+
+    /* Oops! Compare and swap failed, which means the node is
+       no longer first. We delete it using the ordinary method.  But we don't
+       know the identity of the node which now holds the pointer to the node
+       being deleted, so we must search from the beginning. */
+
+    for (pp_node = pp_head; p_node != *pp_node; ) {
+      pp_node = &(*pp_node)->next;
+      READ_MEMORY_BARRIER(); /* Stabilize *pp_node for next iteration. */
+    }
+  }
+
+  *pp_node = p_node->next;
+  return;
+}
+
+#endif
+
+void __pthread_alt_lock(struct _pthread_fastlock * lock,
+		        pthread_descr self)
+{
+#if defined HAS_COMPARE_AND_SWAP
+  long oldstatus, newstatus;
+#endif
+  struct wait_node wait_node;
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    int suspend_needed = 0;
+    __pthread_acquire(&lock->__spinlock);
+
+    if (lock->__status == 0)
+      lock->__status = 1;
+    else {
+      if (self == NULL)
+	self = thread_self();
+
+      wait_node.abandoned = 0;
+      wait_node.next = (struct wait_node *) lock->__status;
+      wait_node.thr = self;
+      lock->__status = (long) &wait_node;
+      suspend_needed = 1;
+    }
+
+    __pthread_release(&lock->__spinlock);
+
+    if (suspend_needed)
+      suspend (self);
+    return;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  do {
+    oldstatus = lock->__status;
+    if (oldstatus == 0) {
+      newstatus = 1;
+    } else {
+      if (self == NULL)
+	self = thread_self();
+      wait_node.thr = self;
+      newstatus = (long) &wait_node;
+    }
+    wait_node.abandoned = 0;
+    wait_node.next = (struct wait_node *) oldstatus;
+    /* Make sure the store in wait_node.next completes before performing
+       the compare-and-swap */
+    MEMORY_BARRIER();
+  } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
+
+  /* Suspend. Note that unlike in __pthread_lock, we don't worry
+     here about spurious wakeup. That's because this lock is not
+     used in situations where that can happen; the restart can
+     only come from the previous lock owner. */
+
+  if (oldstatus != 0)
+    suspend(self);
+
+  READ_MEMORY_BARRIER();
+#endif
+}
+
+/* Timed-out lock operation; returns 0 to indicate timeout. */
+
+int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
+			    pthread_descr self, const struct timespec *abstime)
+{
+  long oldstatus = 0;
+#if defined HAS_COMPARE_AND_SWAP
+  long newstatus;
+#endif
+  struct wait_node *p_wait_node = wait_node_alloc();
+
+  /* Out of memory, just give up and do ordinary lock. */
+  if (p_wait_node == 0) {
+    __pthread_alt_lock(lock, self);
+    return 1;
+  }
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_acquire(&lock->__spinlock);
+
+    if (lock->__status == 0)
+      lock->__status = 1;
+    else {
+      if (self == NULL)
+	self = thread_self();
+
+      p_wait_node->abandoned = 0;
+      p_wait_node->next = (struct wait_node *) lock->__status;
+      p_wait_node->thr = self;
+      lock->__status = (long) p_wait_node;
+      oldstatus = 1; /* force suspend */
+    }
+
+    __pthread_release(&lock->__spinlock);
+    goto suspend;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  do {
+    oldstatus = lock->__status;
+    if (oldstatus == 0) {
+      newstatus = 1;
+    } else {
+      if (self == NULL)
+	self = thread_self();
+      p_wait_node->thr = self;
+      newstatus = (long) p_wait_node;
+    }
+    p_wait_node->abandoned = 0;
+    p_wait_node->next = (struct wait_node *) oldstatus;
+    /* Make sure the store in wait_node.next completes before performing
+       the compare-and-swap */
+    MEMORY_BARRIER();
+  } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
+#endif
+
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  suspend:
+#endif
+
+  /* If we did not get the lock, do a timed suspend. If we wake up due
+     to a timeout, then there is a race; the old lock owner may try
+     to remove us from the queue. This race is resolved by us and the owner
+     doing an atomic testandset() to change the state of the wait node from 0
+     to 1. If we succeed, then it's a timeout and we abandon the node in the
+     queue. If we fail, it means the owner gave us the lock. */
+
+  if (oldstatus != 0) {
+    if (timedsuspend(self, abstime) == 0) {
+      if (!testandset(&p_wait_node->abandoned))
+	return 0; /* Timeout! */
+
+      /* Eat oustanding resume from owner, otherwise wait_node_free() below
+	 will race with owner's wait_node_dequeue(). */
+      suspend(self);
+    }
+  }
+
+  wait_node_free(p_wait_node);
+
+  READ_MEMORY_BARRIER();
+
+  return 1; /* Got the lock! */
+}
+
+void __pthread_alt_unlock(struct _pthread_fastlock *lock)
+{
+  struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio;
+  struct wait_node ** const pp_head = (struct wait_node **) &lock->__status;
+  int maxprio;
+
+  WRITE_MEMORY_BARRIER();
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_acquire(&lock->__spinlock);
+  }
+#endif
+
+  while (1) {
+
+  /* If no threads are waiting for this lock, try to just
+     atomically release it. */
+#if defined TEST_FOR_COMPARE_AND_SWAP
+    if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+    {
+      if (lock->__status == 0 || lock->__status == 1) {
+	lock->__status = 0;
+	break;
+      }
+    }
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+    else
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+    {
+      long oldstatus = lock->__status;
+      if (oldstatus == 0 || oldstatus == 1) {
+	if (__compare_and_swap_with_release_semantics (&lock->__status, oldstatus, 0))
+	  break;
+	else
+	  continue;
+      }
+    }
+#endif
+
+    /* Process the entire queue of wait nodes. Remove all abandoned
+       wait nodes and put them into the global free queue, and
+       remember the one unabandoned node which refers to the thread
+       having the highest priority. */
+
+    pp_max_prio = pp_node = pp_head;
+    p_max_prio = p_node = *pp_head;
+    maxprio = INT_MIN;
+
+    READ_MEMORY_BARRIER(); /* Prevent access to stale data through p_node */
+
+    while (p_node != (struct wait_node *) 1) {
+      int prio;
+
+      if (p_node->abandoned) {
+	/* Remove abandoned node. */
+#if defined TEST_FOR_COMPARE_AND_SWAP
+	if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+	  *pp_node = p_node->next;
+#endif
+#if defined TEST_FOR_COMPARE_AND_SWAP
+	else
+#endif
+#if defined HAS_COMPARE_AND_SWAP
+	  wait_node_dequeue(pp_head, pp_node, p_node);
+#endif
+	wait_node_free(p_node);
+	/* Note that the next assignment may take us to the beginning
+	   of the queue, to newly inserted nodes, if pp_node == pp_head.
+	   In that case we need a memory barrier to stabilize the first of
+	   these new nodes. */
+	p_node = *pp_node;
+	if (pp_node == pp_head)
+	  READ_MEMORY_BARRIER(); /* No stale reads through p_node */
+	continue;
+      } else if ((prio = p_node->thr->p_priority) >= maxprio) {
+	/* Otherwise remember it if its thread has a higher or equal priority
+	   compared to that of any node seen thus far. */
+	maxprio = prio;
+	pp_max_prio = pp_node;
+	p_max_prio = p_node;
+      }
+
+      /* This canno6 jump backward in the list, so no further read
+         barrier is needed. */
+      pp_node = &p_node->next;
+      p_node = *pp_node;
+    }
+
+    /* If all threads abandoned, go back to top */
+    if (maxprio == INT_MIN)
+      continue;
+
+    ASSERT (p_max_prio != (struct wait_node *) 1);
+
+    /* Now we want to to remove the max priority thread's wait node from
+       the list. Before we can do this, we must atomically try to change the
+       node's abandon state from zero to nonzero. If we succeed, that means we
+       have the node that we will wake up. If we failed, then it means the
+       thread timed out and abandoned the node in which case we repeat the
+       whole unlock operation. */
+
+    if (!testandset(&p_max_prio->abandoned)) {
+#if defined TEST_FOR_COMPARE_AND_SWAP
+      if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+	*pp_max_prio = p_max_prio->next;
+#endif
+#if defined TEST_FOR_COMPARE_AND_SWAP
+      else
+#endif
+#if defined HAS_COMPARE_AND_SWAP
+	wait_node_dequeue(pp_head, pp_max_prio, p_max_prio);
+#endif
+      restart(p_max_prio->thr);
+      break;
+    }
+  }
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_release(&lock->__spinlock);
+  }
+#endif
+}
+
+
+/* Compare-and-swap emulation with a spinlock */
+
+#ifdef TEST_FOR_COMPARE_AND_SWAP
+int __pthread_has_cas = 0;
+#endif
+
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+
+int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
+                               int * spinlock)
+{
+  int res;
+
+  __pthread_acquire(spinlock);
+
+  if (*ptr == oldval) {
+    *ptr = newval; res = 1;
+  } else {
+    res = 0;
+  }
+
+  __pthread_release(spinlock);
+
+  return res;
+}
+
+#endif
+
+/* The retry strategy is as follows:
+   - We test and set the spinlock MAX_SPIN_COUNT times, calling
+     sched_yield() each time.  This gives ample opportunity for other
+     threads with priority >= our priority to make progress and
+     release the spinlock.
+   - If a thread with priority < our priority owns the spinlock,
+     calling sched_yield() repeatedly is useless, since we're preventing
+     the owning thread from making progress and releasing the spinlock.
+     So, after MAX_SPIN_LOCK attemps, we suspend the calling thread
+     using nanosleep().  This again should give time to the owning thread
+     for releasing the spinlock.
+     Notice that the nanosleep() interval must not be too small,
+     since the kernel does busy-waiting for short intervals in a realtime
+     process (!).  The smallest duration that guarantees thread
+     suspension is currently 2ms.
+   - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT
+     sched_yield(), then sleeping again if needed. */
+
+static void __pthread_acquire(int * spinlock)
+{
+  int cnt = 0;
+  struct timespec tm;
+
+  READ_MEMORY_BARRIER();
+
+  while (testandset(spinlock)) {
+    if (cnt < MAX_SPIN_COUNT) {
+      sched_yield();
+      cnt++;
+    } else {
+      tm.tv_sec = 0;
+      tm.tv_nsec = SPIN_SLEEP_DURATION;
+      nanosleep(&tm, NULL);
+      cnt = 0;
+    }
+  }
+}

+ 218 - 0
libpthread/linuxthreads/spinlock.h

@@ -0,0 +1,218 @@
+/* Linuxthreads - a simple clone()-based implementation of Posix        */
+/* threads for Linux.                                                   */
+/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr)              */
+/*                                                                      */
+/* This program 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.               */
+/*                                                                      */
+/* This program 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.                 */
+
+#include <bits/initspin.h>
+
+
+/* There are 2 compare and swap synchronization primitives with
+   different semantics:
+
+	1. compare_and_swap, which has acquire semantics (i.e. it
+	completes befor subsequent writes.)
+	2. compare_and_swap_with_release_semantics, which has release
+	semantics (it completes after previous writes.)
+
+   For those platforms on which they are the same. HAS_COMPARE_AND_SWAP
+   should be defined. For those platforms on which they are different,
+   HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS has to be defined.  */
+
+#ifndef HAS_COMPARE_AND_SWAP
+#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS
+#define HAS_COMPARE_AND_SWAP
+#endif
+#endif
+
+#if defined(TEST_FOR_COMPARE_AND_SWAP)
+
+extern int __pthread_has_cas;
+extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
+                                      int * spinlock);
+
+static inline int compare_and_swap(long * ptr, long oldval, long newval,
+                                   int * spinlock)
+{
+  if (__builtin_expect (__pthread_has_cas, 1))
+    return __compare_and_swap(ptr, oldval, newval);
+  else
+    return __pthread_compare_and_swap(ptr, oldval, newval, spinlock);
+}
+
+#elif defined(HAS_COMPARE_AND_SWAP)
+
+#ifdef IMPLEMENT_TAS_WITH_CAS
+#define testandset(p) !__compare_and_swap((long int *) p, 0, 1)
+#endif
+
+#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS
+
+static inline int
+compare_and_swap_with_release_semantics (long * ptr, long oldval,
+					 long newval, int * spinlock)
+{
+  return __compare_and_swap_with_release_semantics (ptr, oldval,
+						    newval);
+}
+
+#endif
+
+static inline int compare_and_swap(long * ptr, long oldval, long newval,
+                                   int * spinlock)
+{
+  return __compare_and_swap(ptr, oldval, newval);
+}
+
+#else
+
+extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
+                                      int * spinlock);
+
+static inline int compare_and_swap(long * ptr, long oldval, long newval,
+                                   int * spinlock)
+{
+  return __pthread_compare_and_swap(ptr, oldval, newval, spinlock);
+}
+
+#endif
+
+#ifndef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS
+#define compare_and_swap_with_release_semantics compare_and_swap
+#define __compare_and_swap_with_release_semantics __compare_and_swap
+#endif
+
+/* Internal locks */
+
+extern void internal_function __pthread_lock(struct _pthread_fastlock * lock,
+					     pthread_descr self);
+extern int __pthread_unlock(struct _pthread_fastlock *lock);
+
+static inline void __pthread_init_lock(struct _pthread_fastlock * lock)
+{
+  lock->__status = 0;
+  lock->__spinlock = __LT_SPINLOCK_INIT;
+}
+
+static inline int __pthread_trylock (struct _pthread_fastlock * lock)
+{
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    return (testandset(&lock->__spinlock) ? EBUSY : 0);
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  do {
+    if (lock->__status != 0) return EBUSY;
+  } while(! __compare_and_swap(&lock->__status, 0, 1));
+  return 0;
+#endif
+}
+
+/* Variation of internal lock used for pthread_mutex_t, supporting
+   timed-out waits.  Warning: do not mix these operations with the above ones
+   over the same lock object! */
+
+extern void __pthread_alt_lock(struct _pthread_fastlock * lock,
+			       pthread_descr self);
+
+extern int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
+			       pthread_descr self, const struct timespec *abstime);
+
+extern void __pthread_alt_unlock(struct _pthread_fastlock *lock);
+
+static inline void __pthread_alt_init_lock(struct _pthread_fastlock * lock)
+{
+  lock->__status = 0;
+  lock->__spinlock = __LT_SPINLOCK_INIT;
+}
+
+static inline int __pthread_alt_trylock (struct _pthread_fastlock * lock)
+{
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    int res = EBUSY;
+
+    if (testandset(&lock->__spinlock) == 0)
+      {
+	if (lock->__status == 0)
+	  {
+	    lock->__status = 1;
+	    WRITE_MEMORY_BARRIER();
+	    res = 0;
+	  }
+	lock->__spinlock = __LT_SPINLOCK_INIT;
+      }
+    return res;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+  do {
+    if (lock->__status != 0) return EBUSY;
+  } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock));
+  return 0;
+#endif
+}
+
+/* Operations on pthread_atomic, which is defined in internals.h */
+
+static inline long atomic_increment(struct pthread_atomic *pa)
+{
+    long oldval;
+
+    do {
+	oldval = pa->p_count;
+    } while (!compare_and_swap(&pa->p_count, oldval, oldval + 1, &pa->p_spinlock));
+
+    return oldval;
+}
+
+
+static inline long atomic_decrement(struct pthread_atomic *pa)
+{
+    long oldval;
+
+    do {
+	oldval = pa->p_count;
+    } while (!compare_and_swap(&pa->p_count, oldval, oldval - 1, &pa->p_spinlock));
+
+    return oldval;
+}
+
+
+static inline __attribute__((always_inline)) void
+__pthread_set_own_extricate_if (pthread_descr self, pthread_extricate_if *peif)
+{
+  /* Only store a non-null peif if the thread has cancellation enabled.
+     Otherwise pthread_cancel will unconditionally call the extricate handler,
+     and restart the thread giving rise to forbidden spurious wakeups. */
+  if (peif == NULL
+      || THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)
+    {
+      /* If we are removing the extricate interface, we need to synchronize
+	 against pthread_cancel so that it does not continue with a pointer
+         to a deallocated pthread_extricate_if struct! The thread lock
+         is (ab)used for this synchronization purpose. */
+      if (peif == NULL)
+	__pthread_lock (THREAD_GETMEM(self, p_lock), self);
+      THREAD_SETMEM(self, p_extricate, peif);
+      if (peif == NULL)
+	__pthread_unlock (THREAD_GETMEM(self, p_lock));
+    }
+}

+ 14 - 0
libpthread/linuxthreads/sysdeps/CVS/Entries

@@ -0,0 +1,14 @@
+D/alpha////
+D/cris////
+D/i386////
+D/ia64////
+D/m68k////
+D/mips////
+D/powerpc////
+D/pthread////
+D/s390////
+D/sh////
+D/sparc////
+D/unix////
+D/x86_64////
+D/hppa////

+ 1 - 0
libpthread/linuxthreads/sysdeps/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps

+ 1 - 0
libpthread/linuxthreads/sysdeps/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 4 - 0
libpthread/linuxthreads/sysdeps/alpha/CVS/Entries

@@ -0,0 +1,4 @@
+D/elf////
+/pspinlock.c/1.3/Tue Nov 15 14:20:47 2005//
+/pt-machine.h/1.13/Tue Nov 15 14:20:47 2005//
+/tls.h/1.6/Tue Nov 15 14:20:47 2005//

+ 2 - 0
libpthread/linuxthreads/sysdeps/alpha/CVS/Entries.Log

@@ -0,0 +1,2 @@
+A D/bits////
+R D/bits////

+ 1 - 0
libpthread/linuxthreads/sysdeps/alpha/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/alpha

+ 1 - 0
libpthread/linuxthreads/sysdeps/alpha/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 2 - 0
libpthread/linuxthreads/sysdeps/alpha/elf/CVS/Entries

@@ -0,0 +1,2 @@
+/pt-initfini.c/1.4/Tue Nov 15 14:20:47 2005//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/alpha/elf/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/alpha/elf

+ 1 - 0
libpthread/linuxthreads/sysdeps/alpha/elf/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 90 - 0
libpthread/linuxthreads/sysdeps/alpha/elf/pt-initfini.c

@@ -0,0 +1,90 @@
+/* Special .init and .fini section support for Alpha.  Linuxthreads version.
+   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* 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.
+
+   This differs from what would be generated by the generic code in that
+   we save and restore the GP within the function.  In order for linker
+   relaxation to work, the value in the GP register on exit from a function
+   must be valid for the function entry point.  Normally, a function is
+   contained within one object file and this is not an issue, provided
+   that the function reloads the gp after making any function calls.
+   However, _init and _fini are constructed from pieces of many object
+   files, all of which may have different GP values.  So we must reload
+   the GP value from crti.o in crtn.o.  */
+
+__asm__ ("						\n\
+#include \"defs.h\"					\n\
+							\n\
+/*@HEADER_ENDS*/					\n\
+							\n\
+/*@_init_PROLOG_BEGINS*/				\n\
+	.section .init, \"ax\", @progbits		\n\
+	.globl	_init					\n\
+	.type	_init,@function				\n\
+	.usepv	_init,std				\n\
+_init:							\n\
+	ldgp	$29, 0($27)				\n\
+	subq	$30, 16, $30				\n\
+	stq	$26, 0($30)				\n\
+	stq	$29, 8($30)				\n\
+	jsr	$26, __pthread_initialize_minimal	\n\
+	ldq	$29, 8($30)				\n\
+	.align 3					\n\
+/*@_init_PROLOG_ENDS*/					\n\
+							\n\
+/*@_init_EPILOG_BEGINS*/				\n\
+	.section .init, \"ax\", @progbits		\n\
+	ldq	$26, 0($30)				\n\
+	ldq	$29, 8($30)				\n\
+	addq	$30, 16, $30				\n\
+	ret						\n\
+/*@_init_EPILOG_ENDS*/					\n\
+							\n\
+/*@_fini_PROLOG_BEGINS*/				\n\
+	.section .fini, \"ax\", @progbits		\n\
+	.globl	_fini					\n\
+	.type	_fini,@function				\n\
+	.usepv	_fini,std				\n\
+_fini:							\n\
+	ldgp	$29, 0($27)				\n\
+	subq	$30, 16, $30				\n\
+	stq	$26, 0($30)				\n\
+	stq	$29, 8($30)				\n\
+	.align 3					\n\
+/*@_fini_PROLOG_ENDS*/					\n\
+							\n\
+/*@_fini_EPILOG_BEGINS*/				\n\
+	.section .fini, \"ax\", @progbits		\n\
+	ldq	$26, 0($30)				\n\
+	ldq	$29, 8($30)				\n\
+	addq	$30, 16, $30				\n\
+	ret						\n\
+/*@_fini_EPILOG_ENDS*/					\n\
+							\n\
+/*@TRAILER_BEGINS*/					\n\
+");

+ 110 - 0
libpthread/linuxthreads/sysdeps/alpha/pspinlock.c

@@ -0,0 +1,110 @@
+/* POSIX spinlock implementation.  Alpha version.
+   Copyright (C) 2000 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 "internals.h"
+
+
+/* This implementation is similar to the one used in the Linux kernel.
+   But the kernel is byte instructions for the memory access.  This is
+   faster but unusable here.  The problem is that only 128
+   threads/processes could use the spinlock at the same time.  If (by
+   a design error in the program) a thread/process would hold the
+   spinlock for a time long enough to accumulate 128 waiting
+   processes, the next one will find a positive value in the spinlock
+   and assume it is unlocked.  We cannot accept that.  */
+
+int
+__pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  unsigned int tmp;
+  asm volatile
+    ("1:	ldl_l	%0,%1\n"
+     "		blbs	%0,2f\n"
+     "		or	%0,1,%0\n"
+     "		stl_c	%0,%1\n"
+     "		beq	%0,2f\n"
+     "		mb\n"
+     ".subsection 2\n"
+     "2:	ldl	%0,%1\n"
+     "		blbs	%0,2b\n"
+     "		br	1b\n"
+     ".previous"
+     : "=r" (tmp), "=m" (lock)
+     : "m" (lock));
+  return 0;
+}
+weak_alias (__pthread_spin_lock, pthread_spin_lock)
+
+
+int
+__pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  unsigned long int oldval;
+  unsigned long int temp;
+
+  asm volatile
+    ("1:	ldl_l	%0,%1\n"
+     "		and	%0,%3,%2\n"
+     "		bne	%2,2f\n"
+     "		xor	%0,%3,%0\n"
+     "		stl_c	%0,%1\n"
+     "		beq	%0,3f\n"
+     "		mb\n"
+     "2:\n"
+     ".subsection 2\n"
+     "3:	br	1b\n"
+     ".previous"
+     : "=&r" (temp), "=m" (*lock), "=&r" (oldval)
+     : "Ir" (1UL), "m" (*lock));
+
+  return oldval == 0 ? 0 : EBUSY;
+}
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock)
+
+
+int
+__pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  asm volatile ("mb");
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock)
+
+
+int
+__pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  /* We can ignore the `pshared' parameter.  Since we are busy-waiting
+     all processes which can access the memory location `lock' points
+     to can use the spinlock.  */
+  *lock = 0;
+  return 0;
+}
+weak_alias (__pthread_spin_init, pthread_spin_init)
+
+
+int
+__pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy)

+ 128 - 0
libpthread/linuxthreads/sysdeps/alpha/pt-machine.h

@@ -0,0 +1,128 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   Alpha version.
+   Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
+
+   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.  */
+
+#ifndef _PT_MACHINE_H
+#define _PT_MACHINE_H   1
+
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+
+#ifdef __linux__
+# include <asm/pal.h>
+#else
+# include <machine/pal.h>
+#endif
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.  */
+#define CURRENT_STACK_FRAME  stack_pointer
+register char *stack_pointer __asm__("$30");
+
+
+/* Memory barrier; default is to do nothing */
+#define MEMORY_BARRIER() __asm__ __volatile__("mb" : : : "memory")
+/* Write barrier.  */
+#define WRITE_MEMORY_BARRIER() __asm__ __volatile__("wmb" : : : "memory")
+
+
+/* Spinlock implementation; required.  */
+PT_EI long int
+testandset (int *spinlock)
+{
+  long int ret, temp;
+
+  __asm__ __volatile__(
+	"/* Inline spinlock test & set */\n"
+	"1:\t"
+	"ldl_l %0,%3\n\t"
+	"bne %0,2f\n\t"
+	"or $31,1,%1\n\t"
+	"stl_c %1,%2\n\t"
+	"beq %1,1b\n"
+	"2:\tmb\n"
+	"/* End spinlock test & set */"
+	: "=&r"(ret), "=&r"(temp), "=m"(*spinlock)
+	: "m"(*spinlock)
+        : "memory");
+
+  return ret;
+}
+
+
+/* Begin allocating thread stacks at this address.  Default is to allocate
+   them just below the initial program stack.  */
+#define THREAD_STACK_START_ADDRESS  0x40000000000
+
+
+/* Return the thread descriptor for the current thread.  */
+#define THREAD_SELF \
+({									      \
+  register pthread_descr __self __asm__("$0");				      \
+  __asm__ ("call_pal %1" : "=r"(__self) : "i"(PAL_rduniq));		      \
+  __self;								      \
+})
+
+/* Initialize the thread-unique value.  */
+#define INIT_THREAD_SELF(descr, nr) \
+{									      \
+  register pthread_descr __self __asm__("$16") = (descr);		      \
+  __asm__ __volatile__ ("call_pal %1" : : "r"(__self), "i"(PAL_wruniq));      \
+}
+
+
+/* Compare-and-swap for semaphores. */
+
+#define HAS_COMPARE_AND_SWAP
+PT_EI int
+__compare_and_swap (long int *p, long int oldval, long int newval)
+{
+  long int ret;
+
+  __asm__ __volatile__ (
+	"/* Inline compare & swap */\n"
+	"1:\t"
+	"ldq_l %0,%4\n\t"
+	"cmpeq %0,%2,%0\n\t"
+	"beq %0,2f\n\t"
+	"mov %3,%0\n\t"
+	"stq_c %0,%1\n\t"
+	"beq %0,1b\n\t"
+	"2:\tmb\n"
+	"/* End compare & swap */"
+	: "=&r"(ret), "=m"(*p)
+	: "r"(oldval), "r"(newval), "m"(*p)
+        : "memory");
+
+  return ret;
+}
+
+/* We want the OS to assign stack addresses.  */
+#define FLOATING_STACKS 1
+
+/* Maximum size of the stack if the rlimit is unlimited.  */
+#define ARCH_STACK_MAX_SIZE     32*1024*1024
+
+#endif /* pt-machine.h */

+ 134 - 0
libpthread/linuxthreads/sysdeps/alpha/tls.h

@@ -0,0 +1,134 @@
+/* Definitions for thread-local data handling.  linuxthreads/Alpha version.
+   Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <pt-machine.h>
+# include <stdbool.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+
+typedef struct
+{
+  dtv_t *dtv;
+
+  /* Reserved for the thread implementation.  Unused in LinuxThreads.  */
+  void *private;
+} tcbhead_t;
+#endif
+
+
+#ifdef HAVE_TLS_SUPPORT
+
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+# ifndef __ASSEMBLER__
+/* Get system call information.  */
+#  include <sysdep.h>
+
+/* This is the size of the initial TCB.  */
+#  define TLS_INIT_TCB_SIZE	sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+#  define TLS_INIT_TCB_ALIGN	__alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+#  define TLS_TCB_SIZE		sizeof (tcbhead_t)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN		__alignof__ (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+#  define TLS_PRE_TCB_SIZE	sizeof (struct _pthread_descr_struct)
+
+/* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
+#  define TLS_DTV_AT_TP 1
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(TCBP, DTVP) \
+  (((tcbhead_t *) (TCBP))->dtv = (DTVP) + 1)
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(DTV) \
+  (((tcbhead_t *)__builtin_thread_pointer ())->dtv = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(TCBP) \
+  (((tcbhead_t *) (TCBP))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(TCBP, SECONDCALL) \
+  (__builtin_set_thread_pointer (TCBP), 0)
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  (((tcbhead_t *)__builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#  undef THREAD_SELF
+#  define THREAD_SELF \
+  ((pthread_descr)__builtin_thread_pointer () - 1)
+
+#  undef INIT_THREAD_SELF
+#  define INIT_THREAD_SELF(DESCR, NR) \
+  __builtin_set_thread_pointer ((struct _pthread_descr_struct *)(DESCR) + 1)
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+/* ??? Generic bits of LinuxThreads may call these macros with
+   DESCR set to NULL.  We are expected to be able to reference
+   the "current" value.
+
+   In our case, we'd really prefer to use DESCR, since lots of
+   PAL_code calls would be expensive.  We can only trust that
+   the compiler does its job and unifies the multiple
+   __builtin_thread_pointer instances.  */
+
+#define THREAD_GETMEM(descr, member) \
+  ((void) sizeof (descr), THREAD_SELF->member)
+#define THREAD_GETMEM_NC(descr, member) \
+  ((void) sizeof (descr), THREAD_SELF->member)
+#define THREAD_SETMEM(descr, member, value) \
+  ((void) sizeof (descr), THREAD_SELF->member = (value))
+#define THREAD_SETMEM_NC(descr, member, value) \
+  ((void) sizeof (descr), THREAD_SELF->member = (value))
+
+# endif	/* HAVE_TLS_SUPPORT */
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */

+ 4 - 0
libpthread/linuxthreads/sysdeps/arm/CVS/Entries

@@ -0,0 +1,4 @@
+/pspinlock.c/1.3/Wed Nov 16 21:06:54 2005//
+/pt-machine.h/1.7/Wed Nov 16 21:06:54 2005//
+/tls.h/1.1/Wed Nov 16 21:06:54 2005//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/arm/CVS/Repository

@@ -0,0 +1 @@
+ports/sysdeps/arm/linuxthreads

+ 1 - 0
libpthread/linuxthreads/sysdeps/arm/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 82 - 0
libpthread/linuxthreads/sysdeps/arm/pspinlock.c

@@ -0,0 +1,82 @@
+/* POSIX spinlock implementation.  Arm version.
+   Copyright (C) 2000 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 "internals.h"
+
+
+int
+__pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  unsigned int val;
+
+  do
+    asm volatile ("swp %0, %1, [%2]"
+		  : "=r" (val)
+		  : "0" (1), "r" (lock)
+		  : "memory");
+  while (val != 0);
+
+  return 0;
+}
+weak_alias (__pthread_spin_lock, pthread_spin_lock)
+
+
+int
+__pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  unsigned int val;
+
+  asm volatile ("swp %0, %1, [%2]"
+		: "=r" (val)
+		: "0" (1), "r" (lock)
+		: "memory");
+
+  return val ? EBUSY : 0;
+}
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock)
+
+
+int
+__pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock)
+
+
+int
+__pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  /* We can ignore the `pshared' parameter.  Since we are busy-waiting
+     all processes which can access the memory location `lock' points
+     to can use the spinlock.  */
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_init, pthread_spin_init)
+
+
+int
+__pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy)

+ 55 - 0
libpthread/linuxthreads/sysdeps/arm/pt-machine.h

@@ -0,0 +1,55 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   ARM version.
+   Copyright (C) 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Philip Blundell <philb@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; 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 _PT_MACHINE_H
+#define _PT_MACHINE_H   1
+
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+/* This will not work on ARM1 or ARM2 because SWP is lacking on those
+   machines.  Unfortunately we have no way to detect this at compile
+   time; let's hope nobody tries to use one.  */
+
+/* Spinlock implementation; required.  */
+PT_EI long int
+testandset (int *spinlock)
+{
+  register unsigned int ret;
+
+  __asm__ __volatile__("swp %0, %1, [%2]"
+		       : "=r"(ret)
+		       : "0"(1), "r"(spinlock));
+
+  return ret;
+}
+
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.  */
+#define CURRENT_STACK_FRAME  stack_pointer
+register char * stack_pointer __asm__ ("sp");
+
+#endif /* pt-machine.h */

+ 172 - 0
libpthread/linuxthreads/sysdeps/arm/tls.h

@@ -0,0 +1,172 @@
+/* Definitions for thread-local data handling.  linuxthreads/ARM version.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <stdbool.h>
+# include <pt-machine.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+typedef struct
+{
+  dtv_t *dtv;
+
+  /* Reserved for the thread implementation.  Unused in LinuxThreads.  */
+  void *private;
+} tcbhead_t;
+#endif
+
+
+/* We can support TLS only if the floating-stack support is available.
+   However, we want to compile in the support and test at runtime whether
+   the running kernel can support it or not.  To avoid bothering with the
+   TLS support code at all, use configure --without-tls.
+
+   We need USE_TLS to be consistently defined, for ldsodefs.h conditionals.
+   But some of the code below can cause problems in building libpthread
+   (e.g. useldt.h will defined FLOATING_STACKS when it shouldn't).  */
+
+/* LinuxThreads can only support TLS if both floating stacks and support
+   from the tools are available.
+
+   We have to define USE_TLS consistently, or ldsodefs.h will lay out types
+   differently between an NPTL build and a LinuxThreads build.  It can be set
+   for libc.so and not libpthread.so, but only if we provide appropriate padding
+   in the _pthread_descr_struct.
+
+   Currently nothing defines FLOATING_STACKS.  We could assume this based on
+   kernel version once the TLS patches are available in kernel.org.
+
+   To avoid bothering with the TLS support code at all, use configure
+   --without-tls.  */
+
+#if defined HAVE_TLS_SUPPORT \
+    && (defined FLOATING_STACKS || !defined IS_IN_libpthread)
+
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+/* Include padding in _pthread_descr_struct so that libc can find p_errno,
+   if libpthread will only include the padding because of the !IS_IN_libpthread
+   check.  */
+#ifndef FLOATING_STACKS
+# define INCLUDE_TLS_PADDING	1
+#endif
+
+# ifndef __ASSEMBLER__
+/* Get system call information.  */
+#  include <sysdep.h>
+
+/* This is the size of the initial TCB.  */
+#  define TLS_INIT_TCB_SIZE	sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+#  define TLS_INIT_TCB_ALIGN	__alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+#  define TLS_TCB_SIZE		sizeof (tcbhead_t)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN		__alignof__ (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+#  define TLS_PRE_TCB_SIZE	sizeof (struct _pthread_descr_struct)
+
+/* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
+#  define TLS_DTV_AT_TP 1
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(TCBP, DTVP) \
+  (((tcbhead_t *) (TCBP))->dtv = (DTVP) + 1)
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(DTV) \
+  (((tcbhead_t *)__builtin_thread_pointer ())->dtv = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(TCBP) \
+  (((tcbhead_t *) (TCBP))->dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(TCBP, SECONDCALL) \
+  ({ INTERNAL_SYSCALL_DECL (err);					\
+     long result_var;							\
+     result_var = INTERNAL_SYSCALL_ARM (set_tls, err, 1, (TCBP));	\
+     INTERNAL_SYSCALL_ERROR_P (result_var, err)				\
+       ? "unknown error" : NULL; })
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  (((tcbhead_t *)__builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#  undef THREAD_SELF
+#  define THREAD_SELF \
+  ((pthread_descr)__builtin_thread_pointer () - 1)
+
+#  undef INIT_THREAD_SELF
+#  define INIT_THREAD_SELF(DESCR, NR) \
+  TLS_INIT_TP ((struct _pthread_descr_struct *)(DESCR) + 1, 0)
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+/* ??? Generic bits of LinuxThreads may call these macros with
+   DESCR set to NULL.  We are expected to be able to reference
+   the "current" value.
+
+   In our case, we'd really prefer to use DESCR, since lots of
+   PAL_code calls would be expensive.  We can only trust that
+   the compiler does its job and unifies the multiple
+   __builtin_thread_pointer instances.  */
+
+#define THREAD_GETMEM(descr, member) \
+  ((void) sizeof (descr), THREAD_SELF->member)
+#define THREAD_GETMEM_NC(descr, member) \
+  ((void) sizeof (descr), THREAD_SELF->member)
+#define THREAD_SETMEM(descr, member, value) \
+  ((void) sizeof (descr), THREAD_SELF->member = (value))
+#define THREAD_SETMEM_NC(descr, member, value) \
+  ((void) sizeof (descr), THREAD_SELF->member = (value))
+
+/* Initializing the thread pointer will generate a SIGILL if the syscall
+   is not available.  */
+#define TLS_INIT_TP_EXPENSIVE 1
+
+# endif	/* HAVE_TLS_SUPPORT */
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */

+ 3 - 0
libpthread/linuxthreads/sysdeps/cris/CVS/Entries

@@ -0,0 +1,3 @@
+/pspinlock.c/1.2/Tue Nov 15 14:20:47 2005//
+/pt-machine.h/1.5/Tue Nov 15 14:20:47 2005//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/cris/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/cris

+ 1 - 0
libpthread/linuxthreads/sysdeps/cris/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 72 - 0
libpthread/linuxthreads/sysdeps/cris/pspinlock.c

@@ -0,0 +1,72 @@
+/* POSIX spinlock implementation.  CRIS version.
+   Copyright (C) 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 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 "internals.h"
+
+/* FIXME: These are just dummies.  I don't know why or if they're needed;
+   configury should default to these definitions.  We just follow the
+   crowd here.  */
+
+int
+__pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (testandset (lock) != 0)
+    ;
+
+  return 0;
+}
+weak_alias (__pthread_spin_lock, pthread_spin_lock)
+
+
+int
+__pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return testandset (lock) != 0 ? EBUSY : 0;
+}
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock)
+
+
+int
+__pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock)
+
+
+int
+__pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  /* We can ignore the `pshared' parameter.  Since we are busy-waiting
+     all processes which can access the memory location `lock' points
+     to can use the spinlock.  */
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_init, pthread_spin_init)
+
+
+int
+__pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy)

+ 58 - 0
libpthread/linuxthreads/sysdeps/cris/pt-machine.h

@@ -0,0 +1,58 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   CRIS version.
+   Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; 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 _PT_MACHINE_H
+#define _PT_MACHINE_H   1
+
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+PT_EI long int
+testandset (int *spinlock)
+{
+  register unsigned long int ret;
+
+  /* Note the use of a dummy output of *spinlock to expose the write.  The
+     memory barrier is to stop *other* writes being moved past this code.  */
+  __asm__ __volatile__("clearf\n"
+		       "0:\n\t"
+		       "movu.b [%2],%0\n\t"
+		       "ax\n\t"
+		       "move.b %3,[%2]\n\t"
+		       "bwf 0b\n\t"
+		       "clearf"
+		       : "=&r" (ret), "=m" (*spinlock)
+		       : "r" (spinlock), "r" ((int) 1)
+		       : "memory");
+  return ret;
+}
+
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.
+   I don't trust register variables, so let's do this the safe way.  */
+#define CURRENT_STACK_FRAME \
+ ({ char *sp; __asm__ ("move.d $sp,%0" : "=rm" (sp)); sp; })
+
+#endif /* pt-machine.h */

+ 3 - 0
libpthread/linuxthreads/sysdeps/hppa/CVS/Entries

@@ -0,0 +1,3 @@
+/pspinlock.c/1.3/Mon Aug 26 22:39:51 2002//
+/pt-machine.h/1.6/Thu Jul 31 19:15:42 2003//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/hppa/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/hppa

+ 1 - 0
libpthread/linuxthreads/sysdeps/hppa/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 81 - 0
libpthread/linuxthreads/sysdeps/hppa/pspinlock.c

@@ -0,0 +1,81 @@
+/* POSIX spinlock implementation.  hppa version.
+   Copyright (C) 2000 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 "internals.h"
+
+int
+__pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  unsigned int val;
+
+  do
+    asm volatile ("ldcw %1,%0"
+		  : "=r" (val), "=m" (*lock)
+		  : "m" (*lock));
+  while (!val);
+
+  return 0;
+}
+weak_alias (__pthread_spin_lock, pthread_spin_lock)
+
+
+int
+__pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  unsigned int val;
+
+  asm volatile ("ldcw %1,%0"
+		: "=r" (val), "=m" (*lock)
+		: "m" (*lock));
+
+  return val ? 0 : EBUSY;
+}
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock)
+
+
+int
+__pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  *lock = 1;
+  return 0;
+}
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock)
+
+
+int
+__pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  /* We can ignore the `pshared' parameter.  Since we are busy-waiting
+     all processes which can access the memory location `lock' points
+     to can use the spinlock.  */
+  *lock = 1;
+  return 0;
+}
+weak_alias (__pthread_spin_init, pthread_spin_init)
+
+
+int
+__pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy)

+ 62 - 0
libpthread/linuxthreads/sysdeps/hppa/pt-machine.h

@@ -0,0 +1,62 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   hppa version.
+   Copyright (C) 2000, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
+
+   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.  */
+
+#ifndef _PT_MACHINE_H
+#define _PT_MACHINE_H   1
+
+#include <bits/initspin.h>
+
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.  */
+#define CURRENT_STACK_FRAME  stack_pointer
+register char * stack_pointer __asm__ ("%r30");
+
+
+/* The hppa only has one atomic read and modify memory operation,
+   load and clear, so hppa spinlocks must use zero to signify that
+   someone is holding the lock.  */
+
+#define xstr(s) str(s)
+#define str(s) #s
+/* Spinlock implementation; required.  */
+PT_EI long int
+testandset (int *spinlock)
+{
+  int ret;
+
+  __asm__ __volatile__(
+       "ldcw 0(%2),%0"
+       : "=r"(ret), "=m"(*spinlock)
+       : "r"(spinlock));
+
+  return ret == 0;
+}
+#undef str
+#undef xstr
+
+#endif /* pt-machine.h */

+ 8 - 0
libpthread/linuxthreads/sysdeps/i386/CVS/Entries

@@ -0,0 +1,8 @@
+D/i586////
+D/i686////
+/Makefile/1.8/Tue Nov 15 14:20:47 2005//
+/pt-machine.h/1.18/Tue Nov 15 14:20:47 2005//
+/tcb-offsets.sym/1.1/Tue Nov 15 14:20:47 2005//
+/useldt.h/1.26/Tue Nov 15 14:20:47 2005//
+/tls.h/1.38/Wed Nov 16 19:58:55 2005//
+/pspinlock.c/1.5/Fri Jan 20 14:26:17 2006//

+ 1 - 0
libpthread/linuxthreads/sysdeps/i386/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/i386

+ 1 - 0
libpthread/linuxthreads/sysdeps/i386/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 2 - 0
libpthread/linuxthreads/sysdeps/i386/i586/CVS/Entries

@@ -0,0 +1,2 @@
+/Versions/1.2/Tue Nov 15 14:20:47 2005//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/i386/i586/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/i386/i586

+ 1 - 0
libpthread/linuxthreads/sysdeps/i386/i586/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 3 - 0
libpthread/linuxthreads/sysdeps/i386/i686/CVS/Entries

@@ -0,0 +1,3 @@
+/Versions/1.2/Tue Nov 15 14:20:47 2005//
+/pt-machine.h/1.24/Tue Nov 15 14:20:47 2005//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/i386/i686/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/i386/i686

+ 1 - 0
libpthread/linuxthreads/sysdeps/i386/i686/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 79 - 0
libpthread/linuxthreads/sysdeps/i386/i686/pt-machine.h

@@ -0,0 +1,79 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   i686 version.
+   Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
+
+   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.  */
+
+#ifndef _PT_MACHINE_H
+#define _PT_MACHINE_H	1
+
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+#include "kernel-features.h"
+
+#ifndef __ASSEMBLER__
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.  */
+#define CURRENT_STACK_FRAME  __builtin_frame_address (0)
+
+
+/* Spinlock implementation; required.  */
+PT_EI long int
+testandset (int *spinlock)
+{
+  long int ret;
+
+  __asm__ __volatile__ (
+	"xchgl %0, %1"
+	: "=r" (ret), "=m" (*spinlock)
+	: "0" (1), "m" (*spinlock)
+	: "memory");
+
+  return ret;
+}
+
+
+/* Compare-and-swap for semaphores.  It's always available on i686.  */
+#define HAS_COMPARE_AND_SWAP
+
+PT_EI int
+__compare_and_swap (long int *p, long int oldval, long int newval)
+{
+  char ret;
+  long int readval;
+
+  __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
+			: "=q" (ret), "=m" (*p), "=a" (readval)
+			: "r" (newval), "m" (*p), "a" (oldval)
+			: "memory");
+  return ret;
+}
+#endif
+
+#if __ASSUME_LDT_WORKS > 0
+#include "../useldt.h"
+#endif
+
+/* The P4 and above really want some help to prevent overheating.  */
+#define BUSY_WAIT_NOP	__asm__ ("rep; nop")
+
+#endif /* pt-machine.h */

+ 103 - 0
libpthread/linuxthreads/sysdeps/i386/pspinlock.c

@@ -0,0 +1,103 @@
+/* POSIX spinlock implementation.  x86 version.
+   Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; 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 "internals.h"
+#include <kernel-features.h>
+
+
+/* This implementation is similar to the one used in the Linux kernel.
+   But the kernel is byte instructions for the memory access.  This is
+   faster but unusable here.  The problem is that only 128
+   threads/processes could use the spinlock at the same time.  If (by
+   a design error in the program) a thread/process would hold the
+   spinlock for a time long enough to accumulate 128 waiting
+   processes, the next one will find a positive value in the spinlock
+   and assume it is unlocked.  We cannot accept that.  */
+
+int
+__pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  asm volatile
+    ("\n"
+     "1:\n\t"
+     "lock; decl %0\n\t"
+     "js 2f\n\t"
+     ".section .text.spinlock,\"ax\"\n"
+     "2:\n\t"
+     "cmpl $0,%0\n\t"
+     "rep; nop\n\t"
+     "jle 2b\n\t"
+     "jmp 1b\n\t"
+     ".previous"
+     : "=m" (*lock));
+  return 0;
+}
+weak_alias (__pthread_spin_lock, pthread_spin_lock)
+
+
+int
+__pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  int oldval;
+
+  asm volatile
+    ("xchgl %0,%1"
+     : "=r" (oldval), "=m" (*lock)
+     : "0" (0));
+  return oldval > 0 ? 0 : EBUSY;
+}
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock)
+
+
+int
+__pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  asm volatile
+    ("movl $1,%0"
+     : "=m" (*lock));
+  return 0;
+}
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock)
+
+
+int
+__pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  /* We can ignore the `pshared' parameter.  Since we are busy-waiting
+     all processes which can access the memory location `lock' points
+     to can use the spinlock.  */
+  *lock = 1;
+  return 0;
+}
+weak_alias (__pthread_spin_init, pthread_spin_init)
+
+
+int
+__pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy)
+
+#ifndef __ASSUME_SET_THREAD_AREA_SYSCALL
+int __have_no_set_thread_area;
+#endif

+ 115 - 0
libpthread/linuxthreads/sysdeps/i386/pt-machine.h

@@ -0,0 +1,115 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   i386 version.
+   Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson <rth@tamu.edu>.
+
+   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.  */
+
+#if defined __pentiumpro__ || defined __pentium4__ || defined __athlon__ || \
+	defined __k8__
+# include "i686/pt-machine.h"
+#else
+
+#ifndef _PT_MACHINE_H
+#define _PT_MACHINE_H	1
+
+#ifndef __ASSEMBLER__
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.  */
+#define CURRENT_STACK_FRAME  __builtin_frame_address (0)
+
+
+/* Spinlock implementation; required.  */
+PT_EI long int
+testandset (int *spinlock)
+{
+  long int ret;
+
+  __asm__ __volatile__(
+       "xchgl %0, %1"
+       : "=r"(ret), "=m"(*spinlock)
+       : "0"(1), "m"(*spinlock)
+       : "memory");
+
+  return ret;
+}
+
+
+/* Compare-and-swap for semaphores.
+   Available on the 486 and above, but not on the 386.
+   We test dynamically whether it's available or not. */
+
+#define HAS_COMPARE_AND_SWAP
+#define TEST_FOR_COMPARE_AND_SWAP
+
+PT_EI int
+__compare_and_swap (long int *p, long int oldval, long int newval)
+{
+  char ret;
+  long int readval;
+
+  __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
+			: "=q" (ret), "=m" (*p), "=a" (readval)
+			: "r" (newval), "m" (*p), "a" (oldval)
+			: "memory");
+  return ret;
+}
+
+
+PT_EI int
+get_eflags (void)
+{
+  int res;
+  __asm__ __volatile__ ("pushfl; popl %0" : "=r" (res) : );
+  return res;
+}
+
+
+PT_EI void
+set_eflags (int newflags)
+{
+  __asm__ __volatile__ ("pushl %0; popfl" : : "r" (newflags) : "cc");
+}
+
+
+PT_EI int
+compare_and_swap_is_available (void)
+{
+  int oldflags = get_eflags ();
+  int changed;
+  /* Flip AC bit in EFLAGS.  */
+  set_eflags (oldflags ^ 0x40000);
+  /* See if bit changed.  */
+  changed = (get_eflags () ^ oldflags) & 0x40000;
+  /* Restore EFLAGS.  */
+  set_eflags (oldflags);
+  /* If the AC flag did not change, it's a 386 and it lacks cmpxchg.
+     Otherwise, it's a 486 or above and it has cmpxchg.  */
+  return changed != 0;
+}
+#endif /* __ASSEMBLER__ */
+
+#endif /* pt-machine.h */
+
+#endif

+ 7 - 0
libpthread/linuxthreads/sysdeps/i386/tcb-offsets.sym

@@ -0,0 +1,7 @@
+#include <sysdep.h>
+#include <tls.h>
+
+MULTIPLE_THREADS_OFFSET		offsetof (tcbhead_t, multiple_threads)
+#ifdef NEED_DL_SYSINFO
+SYSINFO_OFFSET			offsetof (tcbhead_t, sysinfo)
+#endif

+ 229 - 0
libpthread/linuxthreads/sysdeps/i386/tls.h

@@ -0,0 +1,229 @@
+/* Definition for thread-local data handling.  linuxthreads/i386 version.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+# include <pt-machine.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } 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.  */
+  int multiple_threads;
+#ifdef NEED_DL_SYSINFO
+  uintptr_t sysinfo;
+#endif
+} tcbhead_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif
+
+/* We can support TLS only if the floating-stack support is available.
+   However, we want to compile in the support and test at runtime whether
+   the running kernel can support it or not.  To avoid bothering with the
+   TLS support code at all, use configure --without-tls.
+
+   We need USE_TLS to be consistently defined, for ldsodefs.h conditionals.
+   But some of the code below can cause problems in building libpthread
+   (e.g. useldt.h will defined FLOATING_STACKS when it shouldn't).  */
+
+#if defined HAVE_TLS_SUPPORT \
+    && (defined FLOATING_STACKS || !defined IS_IN_libpthread)
+
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+# ifndef __ASSEMBLER__
+/* Get system call information.  */
+#  include <sysdep.h>
+
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/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_descr_struct)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+/* 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_descr_struct *__descr;				      \
+     THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); })
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+#  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
+
+#  if !defined IS_IN_linuxthreads && !defined DO_MODIFY_LDT
+#   include "useldt.h"		/* For the structure.  */
+#  endif
+#  if __ASSUME_LDT_WORKS > 0
+#   define TLS_DO_MODIFY_LDT_KERNEL_CHECK(doit) (doit) /* Nothing to check.  */
+#  else
+#   define TLS_DO_MODIFY_LDT_KERNEL_CHECK(doit)				      \
+  (__builtin_expect (GLRO(dl_osversion) < 131939, 0)			      \
+   ? "kernel too old for thread-local storage support\n"			      \
+   : (doit))
+#  endif
+
+#  define TLS_DO_MODIFY_LDT(descr, nr)					      \
+TLS_DO_MODIFY_LDT_KERNEL_CHECK(						      \
+({									      \
+  struct modify_ldt_ldt_s ldt_entry =					      \
+    { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */,	      \
+      1, 0, 0, 1, 0, 1, 0 };						      \
+  int result;								      \
+  asm volatile (TLS_LOAD_EBX						      \
+		"int $0x80\n\t"						      \
+		TLS_LOAD_EBX						      \
+		: "=a" (result)						      \
+		: "0" (__NR_modify_ldt),				      \
+		/* The extra argument with the "m" constraint is necessary    \
+		   to let the compiler know that we are accessing LDT_ENTRY   \
+		   here.  */						      \
+		"m" (ldt_entry), TLS_EBX_ARG (1), "c" (&ldt_entry),	      \
+		"d" (sizeof (ldt_entry)));				      \
+  __builtin_expect (result, 0) == 0					      \
+  ? ({ asm ("movw %w0, %%gs" : : "q" ((nr) * 8 + 7)); NULL; })		      \
+  : "cannot set up LDT for thread-local storage\n";			      \
+}))
+
+#  define TLS_DO_SET_THREAD_AREA(descr, secondcall)			      \
+({									      \
+  struct modify_ldt_ldt_s ldt_entry =					      \
+    { -1, (unsigned long int) (descr), 0xfffff /* 4GB in pages */,	      \
+      1, 0, 0, 1, 0, 1, 0 };						      \
+  int result;								      \
+  if (secondcall)							      \
+    ldt_entry.entry_number = ({ int _gs;				      \
+				asm ("movw %%gs, %w0" : "=q" (_gs));	      \
+				(_gs & 0xffff) >> 3; });		      \
+  asm volatile (TLS_LOAD_EBX						      \
+		"int $0x80\n\t"						      \
+		TLS_LOAD_EBX						      \
+		: "=a" (result), "=m" (ldt_entry.entry_number)		      \
+		: "0" (__NR_set_thread_area),				      \
+		/* The extra argument with the "m" constraint is necessary    \
+		   to let the compiler know that we are accessing LDT_ENTRY   \
+		   here.  */						      \
+		TLS_EBX_ARG (&ldt_entry), "m" (ldt_entry));		      \
+  if (__builtin_expect (result, 0) == 0)				      \
+    asm ("movw %w0, %%gs" : : "q" (ldt_entry.entry_number * 8 + 3));	      \
+  result;								      \
+})
+
+#  ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
+#   define TLS_SETUP_GS_SEGMENT(descr, secondcall)			      \
+  (TLS_DO_SET_THREAD_AREA (descr, secondcall)				      \
+   ? "set_thread_area failed when setting up thread-local storage\n" : NULL)
+#  elif defined __NR_set_thread_area
+#   define TLS_SETUP_GS_SEGMENT(descr, secondcall) \
+  (TLS_DO_SET_THREAD_AREA (descr, secondcall)				      \
+   ? TLS_DO_MODIFY_LDT (descr, 0) : NULL)
+#  else
+#   define TLS_SETUP_GS_SEGMENT(descr, secondcall) \
+  TLS_DO_MODIFY_LDT ((descr), 0)
+#  endif
+
+#if defined NEED_DL_SYSINFO
+# define INIT_SYSINFO \
+  head->sysinfo = GLRO(dl_sysinfo)
+#else
+# define INIT_SYSINFO
+#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.
+
+   The value of this macro is null if successful, or an error string.  */
+#  define TLS_INIT_TP(descr, secondcall)				      \
+  ({									      \
+    void *_descr = (descr);						      \
+    tcbhead_t *head = _descr;						      \
+									      \
+    head->tcb = _descr;							      \
+    /* For now the thread descriptor is at the same address.  */	      \
+    head->self = _descr;						      \
+									      \
+    INIT_SYSINFO;							      \
+    TLS_SETUP_GS_SEGMENT (_descr, secondcall);				      \
+  })
+
+/* Indicate that dynamic linker shouldn't try to initialize TLS even
+   when no PT_TLS segments are found in the program and libraries
+   it is linked against.  */
+#  define TLS_INIT_TP_EXPENSIVE 1
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  ({ struct _pthread_descr_struct *__descr;				      \
+     THREAD_GETMEM (__descr, p_header.data.dtvp); })
+
+# endif	/* HAVE_TLS_SUPPORT && (FLOATING_STACKS || !IS_IN_libpthread) */
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */

+ 314 - 0
libpthread/linuxthreads/sysdeps/i386/useldt.h

@@ -0,0 +1,314 @@
+/* Special definitions for ix86 machine using segment register based
+   thread descriptor.
+   Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>.
+
+   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.	*/
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>	/* For offsetof.  */
+#include <stdlib.h>	/* For abort().	 */
+#include <sysdep.h>
+
+
+/* We don't want to include the kernel header.	So duplicate the
+   information.	 */
+
+/* Structure passed on `modify_ldt' call.  */
+struct modify_ldt_ldt_s
+{
+  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;
+};
+
+/* System call to set LDT entry.  */
+extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
+
+
+/* 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 \
+({									      \
+  register pthread_descr __self;					      \
+  __asm__ ("movl %%gs:%c1,%0" : "=r" (__self)				      \
+	   : "i" (offsetof (struct _pthread_descr_struct,		      \
+			    p_header.data.self)));			      \
+  __self;								      \
+})
+
+
+/* Initialize the thread-unique value.	Two possible ways to do it.  */
+
+#define DO_MODIFY_LDT(descr, nr)					      \
+({									      \
+  struct modify_ldt_ldt_s ldt_entry =					      \
+    { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */,	      \
+      1, 0, 0, 1, 0, 1, 0 };						      \
+  if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0)		      \
+    abort ();								      \
+  asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7));				      \
+})
+
+#ifdef __PIC__
+# define USETLS_EBX_ARG "r"
+# define USETLS_LOAD_EBX "xchgl %1, %%ebx\n\t"
+#else
+# define USETLS_EBX_ARG "b"
+# define USETLS_LOAD_EBX
+#endif
+
+/* When using the new set_thread_area call, we don't need to change %gs
+   because we inherited the value set up in the main thread by TLS setup.
+   We need to extract that value and set up the same segment in this
+   thread.  */
+#if USE_TLS
+# define DO_SET_THREAD_AREA_REUSE(nr)	1
+#else
+/* Without TLS, we do the initialization of the main thread, where NR == 0.  */
+# define DO_SET_THREAD_AREA_REUSE(nr)	(!__builtin_constant_p (nr) || (nr))
+#endif
+#define DO_SET_THREAD_AREA(descr, nr) \
+({									      \
+  int __gs;								      \
+  if (DO_SET_THREAD_AREA_REUSE (nr))					      \
+    {									      \
+      asm ("movw %%gs, %w0" : "=q" (__gs));				      \
+      struct modify_ldt_ldt_s ldt_entry =				      \
+	{ (__gs & 0xffff) >> 3,						      \
+	  (unsigned long int) (descr), 0xfffff /* 4GB in pages */,	      \
+	  1, 0, 0, 1, 0, 1, 0 };					      \
+									      \
+      int __result;							      \
+      __asm (USETLS_LOAD_EBX						      \
+	     "movl %2, %%eax\n\t"					      \
+	     "int $0x80\n\t"						      \
+	     USETLS_LOAD_EBX						      \
+	     : "=&a" (__result)						      \
+	     : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area),	      \
+	       "m" (ldt_entry)						      \
+	     : "memory");						      \
+      if (__result == 0)						      \
+	asm ("movw %w0, %%gs" :: "q" (__gs));				      \
+      else								      \
+	__gs = -1;							      \
+    }									      \
+  else									      \
+    {									      \
+      struct modify_ldt_ldt_s ldt_entry =				      \
+	{ -1,								      \
+	  (unsigned long int) (descr), 0xfffff /* 4GB in pages */,	      \
+	  1, 0, 0, 1, 0, 1, 0 };					      \
+      int __result;							      \
+      __asm (USETLS_LOAD_EBX						      \
+	     "movl %2, %%eax\n\t"					      \
+	     "int $0x80\n\t"						      \
+	     USETLS_LOAD_EBX						      \
+	     : "=&a" (__result)						      \
+	     : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area),	      \
+	       "m" (ldt_entry)						      \
+	     : "memory");						      \
+      if (__result == 0)						      \
+	{								      \
+	  __gs = (ldt_entry.entry_number << 3) + 3;			      \
+	  asm ("movw %w0, %%gs" : : "q" (__gs));			      \
+	}								      \
+      else								      \
+	__gs = -1;							      \
+    }									      \
+  __gs;									      \
+})
+
+#if defined __ASSUME_SET_THREAD_AREA_SYSCALL
+# define INIT_THREAD_SELF(descr, nr)	DO_SET_THREAD_AREA (descr, nr)
+#elif defined __NR_set_thread_area
+# define INIT_THREAD_SELF(descr, nr)					      \
+({									      \
+  if (__builtin_expect (__have_no_set_thread_area, 0)			      \
+      || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1     \
+	  && (__have_no_set_thread_area = 1)))				      \
+    DO_MODIFY_LDT (descr, nr);						      \
+})
+/* Defined in pspinlock.c.  */
+extern int __have_no_set_thread_area;
+#else
+# define INIT_THREAD_SELF(descr, nr)	DO_MODIFY_LDT (descr, nr)
+#endif
+
+/* Free resources associated with thread descriptor.  */
+#ifdef __ASSUME_SET_THREAD_AREA_SYSCALL
+#define FREE_THREAD(descr, nr) do { } while (0)
+#elif defined __NR_set_thread_area
+#define FREE_THREAD(descr, nr) \
+{									      \
+  int __gs;								      \
+  __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs));		      \
+  if (__builtin_expect (__gs & 4, 0))					      \
+    {									      \
+      struct modify_ldt_ldt_s ldt_entry =				      \
+	{ nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };				      \
+      __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));			      \
+    }									      \
+}
+#else
+#define FREE_THREAD(descr, nr) \
+{									      \
+  struct modify_ldt_ldt_s ldt_entry =					      \
+    { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 };					      \
+  __modify_ldt (1, &ldt_entry, sizeof (ldt_entry));			      \
+}
+#endif
+
+/* Read member of the thread descriptor directly.  */
+#define THREAD_GETMEM(descr, member) \
+({									      \
+  __typeof__ (descr->member) __value;					      \
+  if (sizeof (__value) == 1)						      \
+    __asm__ __volatile__ ("movb %%gs:%P2,%b0"				      \
+			  : "=q" (__value)				      \
+			  : "0" (0),					      \
+			    "i" (offsetof (struct _pthread_descr_struct,      \
+					   member)));			      \
+  else if (sizeof (__value) == 4)					      \
+    __asm__ __volatile__ ("movl %%gs:%P1,%0"				      \
+			  : "=r" (__value)				      \
+			  : "i" (offsetof (struct _pthread_descr_struct,      \
+					   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 %%gs:%P1,%%eax\n\t"			      \
+			    "movl %%gs:%P2,%%edx"			      \
+			    : "=A" (__value)				      \
+			    : "i" (offsetof (struct _pthread_descr_struct,    \
+					     member)),			      \
+			      "i" (offsetof (struct _pthread_descr_struct,    \
+					     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__ __volatile__ ("movb %%gs:(%2),%b0"				      \
+			  : "=q" (__value)				      \
+			  : "0" (0),					      \
+			    "r" (offsetof (struct _pthread_descr_struct,      \
+					   member)));			      \
+  else if (sizeof (__value) == 4)					      \
+    __asm__ __volatile__ ("movl %%gs:(%1),%0"				      \
+			  : "=r" (__value)				      \
+			  : "r" (offsetof (struct _pthread_descr_struct,      \
+					   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 %%gs:(%1),%%eax\n\t"			      \
+			    "movl %%gs:4(%1),%%edx"			      \
+			    : "=&A" (__value)				      \
+			    : "r" (offsetof (struct _pthread_descr_struct,    \
+					     member)));			      \
+    }									      \
+  __value;								      \
+})
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant.  */
+#define THREAD_SETMEM(descr, member, value) \
+({									      \
+  __typeof__ (descr->member) __value = (value);				      \
+  if (sizeof (__value) == 1)						      \
+    __asm__ __volatile__ ("movb %0,%%gs:%P1" :				      \
+			  : "q" (__value),				      \
+			    "i" (offsetof (struct _pthread_descr_struct,      \
+					   member)));			      \
+  else if (sizeof (__value) == 4)					      \
+    __asm__ __volatile__ ("movl %0,%%gs:%P1" :				      \
+			  : "r" (__value),				      \
+			    "i" (offsetof (struct _pthread_descr_struct,      \
+					   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_descr_struct,    \
+					     member)),			      \
+			      "i" (offsetof (struct _pthread_descr_struct,    \
+					     member) + 4));		      \
+    }									      \
+})
+
+/* Set member of the thread descriptor directly.  */
+#define THREAD_SETMEM_NC(descr, member, value) \
+({									      \
+  __typeof__ (descr->member) __value = (value);				      \
+  if (sizeof (__value) == 1)						      \
+    __asm__ __volatile__ ("movb %0,%%gs:(%1)" :				      \
+			  : "q" (__value),				      \
+			    "r" (offsetof (struct _pthread_descr_struct,      \
+					   member)));			      \
+  else if (sizeof (__value) == 4)					      \
+    __asm__ __volatile__ ("movl %0,%%gs:(%1)" :				      \
+			  : "r" (__value),				      \
+			    "r" (offsetof (struct _pthread_descr_struct,      \
+					   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_descr_struct,    \
+					     member)));			      \
+    }									      \
+})
+#endif
+
+#if __ASSUME_LDT_WORKS > 0
+/* We want the OS to assign stack addresses.  */
+#define FLOATING_STACKS	1
+
+/* Maximum size of the stack if the rlimit is unlimited.  */
+#define ARCH_STACK_MAX_SIZE	8*1024*1024
+#endif

+ 7 - 0
libpthread/linuxthreads/sysdeps/ia64/CVS/Entries

@@ -0,0 +1,7 @@
+/Makefile/1.1/Tue Nov 15 14:20:47 2005//
+/Versions/1.2/Tue Nov 15 14:20:47 2005//
+/pspinlock.c/1.5/Tue Nov 15 14:20:47 2005//
+/pt-machine.h/1.15/Tue Nov 15 14:20:47 2005//
+/tcb-offsets.sym/1.6/Tue Nov 15 14:20:47 2005//
+/tls.h/1.10/Wed Nov 16 19:58:55 2005//
+D

+ 1 - 0
libpthread/linuxthreads/sysdeps/ia64/CVS/Repository

@@ -0,0 +1 @@
+ports/linuxthreads/sysdeps/ia64

+ 1 - 0
libpthread/linuxthreads/sysdeps/ia64/CVS/Root

@@ -0,0 +1 @@
+:pserver:anoncvs@sources.redhat.com:/cvs/glibc

+ 79 - 0
libpthread/linuxthreads/sysdeps/ia64/pspinlock.c

@@ -0,0 +1,79 @@
+/* POSIX spinlock implementation.  ia64 version.
+   Copyright (C) 2000, 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jes Sorensen <jes@linuxcare.com>
+
+   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 "internals.h"
+#include <ia64intrin.h>
+
+/* This implementation is inspired by the implementation used in the
+   Linux kernel. */
+
+int
+__pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  int *p = (int *) lock;
+  
+  while (__builtin_expect (__sync_val_compare_and_swap (p, 0, 1), 0))
+    {
+      /* Spin without using the atomic instruction.  */
+      do
+        __asm __volatile ("" : : : "memory");
+      while (*p);
+    }
+  return 0;
+}
+weak_alias (__pthread_spin_lock, pthread_spin_lock)
+
+
+int
+__pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return __sync_val_compare_and_swap ((int *) lock, 0, 1) == 0 ? 0 : EBUSY;
+}
+weak_alias (__pthread_spin_trylock, pthread_spin_trylock)
+
+
+int
+__pthread_spin_unlock (pthread_spinlock_t *lock)
+{
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_unlock, pthread_spin_unlock)
+
+
+int
+__pthread_spin_init (pthread_spinlock_t *lock, int pshared)
+{
+  /* We can ignore the `pshared' parameter.  Since we are busy-waiting
+     all processes which can access the memory location `lock' points
+     to can use the spinlock.  */
+  return *lock = 0;
+}
+weak_alias (__pthread_spin_init, pthread_spin_init)
+
+
+int
+__pthread_spin_destroy (pthread_spinlock_t *lock)
+{
+  /* Nothing to do.  */
+  return 0;
+}
+weak_alias (__pthread_spin_destroy, pthread_spin_destroy)

+ 133 - 0
libpthread/linuxthreads/sysdeps/ia64/pt-machine.h

@@ -0,0 +1,133 @@
+/* Machine-dependent pthreads configuration and inline functions.
+   IA-64 version.
+   Copyright (C) 1999, 2000, 2002, 2003, 2004 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.  */
+
+#ifndef _PT_MACHINE_H
+#define _PT_MACHINE_H   1
+
+#include <ia64intrin.h>
+
+#ifndef PT_EI
+# define PT_EI extern inline __attribute__ ((always_inline))
+#endif
+
+extern long int testandset (int *spinlock);
+extern int __compare_and_swap (long int *p, long int oldval, long int newval);
+
+/* Make sure gcc doesn't try to be clever and move things around on
+   us. We need to use _exactly_ the address the user gave us, not some
+   alias that contains the same information.  */
+#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
+
+#ifndef ELF_MACHINE_NAME
+
+#define NEED_SEPARATE_REGISTER_STACK
+
+/* We want the OS to assign stack addresses.  */
+#define FLOATING_STACKS 1
+
+/* Maximum size of the stack if the rlimit is unlimited.  */
+#define ARCH_STACK_MAX_SIZE     32*1024*1024
+
+/* Get some notion of the current stack.  Need not be exactly the top
+   of the stack, just something somewhere in the current frame.
+   r12 (sp) is the stack pointer. */
+#define CURRENT_STACK_FRAME  stack_pointer
+register char *stack_pointer __asm__ ("sp");
+
+
+/* Register r13 (tp) is reserved by the ABI as "thread pointer". */
+struct _pthread_descr_struct;
+register struct _pthread_descr_struct *__thread_self __asm__("r13");
+
+/* Return the thread descriptor for the current thread.  */
+#define THREAD_SELF  __thread_self
+
+/* Initialize the thread-unique value.  */
+#define INIT_THREAD_SELF(descr, nr)  (__thread_self = (descr))
+
+
+/* Access to data in the thread descriptor is easy.  */
+#define THREAD_GETMEM(descr, member) \
+  ((void) sizeof (descr), THREAD_SELF->member)
+#define THREAD_GETMEM_NC(descr, member) \
+  ((void) sizeof (descr), THREAD_SELF->member)
+#define THREAD_SETMEM(descr, member, value) \
+  ((void) sizeof (descr), THREAD_SELF->member = (value))
+#define THREAD_SETMEM_NC(descr, member, value) \
+  ((void) sizeof (descr), THREAD_SELF->member = (value))
+
+
+/* Memory barrier */
+#define MEMORY_BARRIER() __sync_synchronize ()
+
+
+#define HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS
+
+PT_EI int
+__compare_and_swap (long int *p, long int oldval, long int newval)
+{
+  long int readval;
+
+  __asm__ __volatile__
+       ("mov ar.ccv=%4;;\n\t"
+	"cmpxchg8.acq %0=%1,%2,ar.ccv"
+	: "=r" (readval), "=m" (__atomic_fool_gcc (p))
+	: "r"(newval), "m" (__atomic_fool_gcc (p)), "r" (oldval)
+	: "memory");
+  return readval == oldval;
+}
+
+PT_EI int
+__compare_and_swap_with_release_semantics (long int *p,
+					   long int oldval,
+					   long int newval)
+{
+  long int readval;
+
+  __asm__ __volatile__
+       ("mov ar.ccv=%4;;\n\t"
+	"cmpxchg8.rel %0=%1,%2,ar.ccv"
+	: "=r" (readval), "=m" (__atomic_fool_gcc (p))
+	: "r"(newval), "m" (__atomic_fool_gcc (p)), "r" (oldval)
+	: "memory");
+  return readval == oldval;
+}
+
+#endif /* ELF_MACHINE_NAME */
+
+/* Spinlock implementation; required.  */
+PT_EI long int
+testandset (int *spinlock)
+{
+  long int ret;
+
+  __asm__ __volatile__(
+       "xchg4 %0=%1,%2"
+       : "=r"(ret), "=m"(__atomic_fool_gcc (spinlock))
+       : "r"(1), "m"(__atomic_fool_gcc (spinlock))
+       : "memory");
+
+  return ret;
+}
+
+/* Indicate that we are looping.  */
+#define BUSY_WAIT_NOP	__asm__ ("hint @pause")
+
+#endif /* pt-machine.h */

+ 9 - 0
libpthread/linuxthreads/sysdeps/ia64/tcb-offsets.sym

@@ -0,0 +1,9 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+#ifdef USE_TLS
+MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_multiple_threads) - sizeof (struct _pthread_descr_struct)
+#else
+MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads)
+#endif

+ 145 - 0
libpthread/linuxthreads/sysdeps/ia64/tls.h

@@ -0,0 +1,145 @@
+/* Definitions for thread-local data handling.  linuxthreads/IA-64 version.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <pt-machine.h>
+# include <stdbool.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+#ifdef HAVE_TLS_SUPPORT
+
+/* Signal that TLS support is available.  */
+# define USE_TLS        1
+
+# ifndef __ASSEMBLER__
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  */
+#  define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+#  define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+#  define TLS_TCB_SIZE sizeof (tcbhead_t)
+
+/* This is the size we need before TCB.  */
+#  define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+/* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
+#  define TLS_DTV_AT_TP 1
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))->dtv = (dtvp) + 1
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(DTV) \
+  (((tcbhead_t *)__thread_self)->dtv = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))->dtv)
+
+#if defined NEED_DL_SYSINFO
+# define INIT_SYSINFO \
+  (((tcbhead_t *) __thread_self)->private = (void *) GLRO(dl_sysinfo))
+#else
+# define INIT_SYSINFO 0
+#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(tcbp, secondcall) \
+  (__thread_self = (__typeof (__thread_self)) (tcbp), INIT_SYSINFO, NULL)
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  (((tcbhead_t *)__thread_self)->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#  undef THREAD_SELF
+#  define THREAD_SELF (__thread_self - 1)
+
+#  undef INIT_THREAD_SELF
+#  define INIT_THREAD_SELF(descr, nr) \
+  (__thread_self = (struct _pthread_descr_struct *)(descr) + 1)
+
+# define TLS_MULTIPLE_THREADS_IN_TCB 1
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+# endif
+
+#else
+
+# ifndef __ASSEMBLER__
+
+typedef struct
+{
+  void *tcb;
+  dtv_t *dtv;
+  void *self;
+  int multiple_threads;
+} tcbhead_t;
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+#  define NONTLS_INIT_TP \
+  do { 									\
+    static const tcbhead_t nontls_init_tp = { .multiple_threads = 0 };	\
+    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;		\
+  } while (0)
+
+#endif
+
+#endif /* USE_TLS */
+
+#endif	/* tls.h */

Some files were not shown because too many files changed in this diff