summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authormarcus <marcus>2005-01-23 21:30:40 +0000
committermarcus <marcus>2005-01-23 21:30:40 +0000
commitf4ee3163dc1cc58ce13cdef64541ffe66f5a06a9 (patch)
tree71e7d8fbe453312d4760659ae62d3bfd2dd42e1f /libc
parentb31c52a9116b976a6f919ec045462807851f5988 (diff)
2005-01-23 Marcus Brinkmann <marcus@gnu.org>
* configure.ac: Fall back to libc.a on GNU/Hurd. New option --with-libc. (WITH_LIBC): New automake conditional. * Makefile.am (LIBC_SUBDIRS): New variable. (SUBDIRS): Add $(LIBC_SUBDIRS). * libc: New directory. libc/ 2005-01-23 Marcus Brinkmann <marcus@gnu.org> * Initial check-in.
Diffstat (limited to 'libc')
-rw-r--r--libc/ChangeLog4
-rw-r--r--libc/Makefile.am102
-rw-r--r--libc/README55
-rw-r--r--libc/hurd-l4/Makeconfig41
-rw-r--r--libc/hurd-l4/Makefile41
-rw-r--r--libc/hurd-l4/configure18
-rw-r--r--libc/hurd-l4/configure.in18
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/Implies5
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/Makefile45
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/_G_config.h103
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/_exit.c36
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/errno.h264
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/fcntl.h210
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/local_lim.h46
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/mman.h96
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/posix_opt.h79
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/stat.h193
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/bits/typesizes.h66
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/closedir.c35
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/dirfd.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/dirstream.h44
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/execve.c44
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/exit-thread.c12
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fork.c36
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fstatfs.c34
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fstatfs64.c32
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fstatvfs.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fstatvfs64.c32
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fxstat.c50
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/fxstat64.c49
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/getdtsz.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/getegid.c32
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/geteuid.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/getpagesize.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/getppid.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/init-first.c124
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/lxstat.c27
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/lxstat64.c39
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/mremap.c36
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/opendir.c34
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/readdir.c33
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/readdir_r.c35
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/rewinddir.c35
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/sys/param.h131
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/syscall.c35
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/telldir.c41
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/uname.c34
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/xstat.c39
-rw-r--r--libc/hurd-l4/sysdeps/l4/hurd/xstat64.c38
-rwxr-xr-xlibc/patches/00-configure-touch.patch10
-rwxr-xr-xlibc/patches/01-configure.in-base-os.patch38
-rwxr-xr-xlibc/patches/02-configure.in-add-ons-generic.patch51
-rwxr-xr-xlibc/patches/03-sysdeps-generic-bits-socket-h.patch524
-rwxr-xr-xlibc/patches/04-sysdeps-generic-bits-sigcontext-h.patch23
-rwxr-xr-xlibc/patches/05-sysdeps-generic-getpeername.patch30
-rwxr-xr-xlibc/patches/06-sysdeps-generic-open.patch36
-rwxr-xr-xlibc/patches/07-sysdeps-generic-fcntl.patch36
-rwxr-xr-xlibc/patches/50-nptl-hurd-l4.patch11021
58 files changed, 14470 insertions, 0 deletions
diff --git a/libc/ChangeLog b/libc/ChangeLog
new file mode 100644
index 0000000..fffb9f3
--- /dev/null
+++ b/libc/ChangeLog
@@ -0,0 +1,4 @@
+2005-01-23 Marcus Brinkmann <marcus@gnu.org>
+
+ * Initial check-in.
+
diff --git a/libc/Makefile.am b/libc/Makefile.am
new file mode 100644
index 0000000..eda5bc9
--- /dev/null
+++ b/libc/Makefile.am
@@ -0,0 +1,102 @@
+# Makefile.am - Makefile template for libc
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+# Written by Marcus Brinkmann.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# The GNU Hurd 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+noinst_LIBRARIES = libc.a
+
+patch_files = 00-configure-touch.patch 01-configure.in-base-os.patch \
+ 02-configure.in-add-ons-generic.patch \
+ 03-sysdeps-generic-bits-socket-h.patch \
+ 04-sysdeps-generic-bits-sigcontext-h.patch \
+ 05-sysdeps-generic-getpeername.patch \
+ 06-sysdeps-generic-open.patch \
+ 07-sysdeps-generic-fcntl.patch \
+ 50-nptl-hurd-l4.patch
+patches = $(addprefix patches/, $(patch_files))
+
+hurd_l4_sysdeps_l4_hurd = bits/errno.h bits/fcntl.h bits/local_lim.h \
+ bits/mman.h bits/posix_opt.h bits/stat.h bits/typesizes.h \
+ closedir.c dirfd.c dirstream.h execve.c _exit.c exit-thread.c \
+ fork.c fstatfs64.c fstatfs.c fstatvfs64.c fstatvfs.c fxstat64.c \
+ fxstat.c _G_config.h getdtsz.c getegid.c geteuid.c getpagesize.c \
+ getppid.c Implies init-first.c lxstat64.c lxstat.c Makefile \
+ mremap.c opendir.c readdir.c readdir_r.c rewinddir.c \
+ sys/param.h syscall.c telldir.c uname.c xstat64.c xstat.c
+hurd_l4 = configure configure.in Makeconfig Makefile \
+ $(addprefix sysdeps/l4/hurd/,$(hurd_l4_sysdeps_l4_hurd))
+hurd_l4_add_on = $(addprefix hurd-l4/, $(hurd_l4))
+
+
+EXTRA_DIST = $(patches) $(hurd_l4_add_on)
+
+
+# The GNU C library version that we build against.
+glibc_repository = :pserver:anoncvs@sources.redhat.com:/cvs/glibc
+glibc_module = libc
+glibc_version = 2004-01-23
+
+libc-cvs:
+ test ! -e libc || (echo "GNU C library already checked out." && false)
+ cvs -z3 -d $(glibc_repository) \
+ co -D $(glibc_version) -d libc $(glibc_module)
+
+libc-checkout-stamp:
+ test -e libc || (echo "You must setup the libc source (see README)." \
+ && false)
+ touch libc-checkout-stamp
+
+libc-patch-stamp: libc-checkout-stamp
+ for p in $(patches) ; do \
+ (cd libc; sh ../$(srcdir)/$${p}) || exit 1 ; \
+ done
+ touch libc-patch-stamp
+
+# FIXME: Order should be reversed.
+rpatch:
+ for p in $(patches) ; do \
+ (cd libc; sh ../$(srcdir)/$${p} -R) || exit 1 ; \
+ done
+ rm libc-patch-stamp
+
+libc-add-on-stamp: libc-checkout-stamp
+ for f in $(hurd_l4_add_on) ; do \
+ install -D $(srcdir)/$${f} libc/$${f} ; \
+ done
+ touch libc-add-on-stamp
+
+libc-configure-stamp: libc-patch-stamp libc-add-on-stamp
+ test ! -e libc-build || (echo "Build dir already exists." && false)
+ mkdir libc-build
+ (cd libc-build && ../libc/configure --disable-shared \
+ --disable-profile --without-cvs --enable-add-ons=nptl,hurd-l4 \
+ --prefix=$(prefix) --build=$(build_alias) --host=$(host_alias))
+ touch libc-configure-stamp
+
+libc-build-stamp: libc-configure-stamp
+ (cd libc-build; make)
+ touch libc-build-stamp
+
+libc.a: libc-build-stamp
+ ln -sf libc-build/libc.a libc.a
+
+# clean:
+# rm -fR libc.a libc-build
+#
+# distclean:
+# rm -fR libc \ No newline at end of file
diff --git a/libc/README b/libc/README
new file mode 100644
index 0000000..2112c78
--- /dev/null
+++ b/libc/README
@@ -0,0 +1,55 @@
+The GNU C library
+=================
+
+This will be a port of the GNU C library to the Hurd system running on
+L4.
+
+Configuring and Building
+------------------------
+
+This directory is only built if you specify "--enable-libc" at
+configure time.
+
+Because the GNU C library is huge, it is not shipped with this source
+package. You have to retrieve it manually. This can be done
+semi-automatically by entering in the BUILD directory (after
+configuring this source tree):
+
+$ mkdir hurd-l4-build
+$ cd hurd-l4-build
+$ configure ../hurd-l4/configure --prefix=/l4 --enable-maintainer-mode \
+ --build=i686-linux --host=i686-gnu
+$ make -C libc libc-cvs
+
+This will check out the right glibc version via CVS. It is
+recommended that you save a copy of this version and copy it to the
+libc directory instead downloading it the next time around, to save
+bandwidth and reduced the stress on the CVS server.
+
+$ cp -a libc ~/libc-for-hurd-l4
+
+(next time around:)
+
+$ configure ../hurd-l4/configure --prefix=/l4 --enable-maintainer-mode \
+ --build=i686-linux --host=i686-gnu
+$ cp -a ~/libc-for-hurd-l4 libc/libc
+
+The Makefile will always download a tested, working version of the C
+library. But you can copy any version to the libc directory and try
+your luck.
+
+The downloaded or installed version of the GNU C library source _will_
+be modified when you build the package! So, please, make a copy
+before running "make". The Makefile rules are a bit simple and
+reverting the modifications is not fully supported. So, if the
+patches or add-ons are modified, you will probably need to rebuild
+from scratch. The clean rules are not tested.
+
+
+Hacking
+-------
+
+If you want to hack this, have fun! Without fun, it is a daunting task.
+
+
+- Marcus
diff --git a/libc/hurd-l4/Makeconfig b/libc/hurd-l4/Makeconfig
new file mode 100644
index 0000000..92158be
--- /dev/null
+++ b/libc/hurd-l4/Makeconfig
@@ -0,0 +1,41 @@
+# Makeconfig fragment for glibc ports add-on.
+
+# These rules make sure that sysdeps/CPU/preconfigure changes are noticed.
+# preconfigure fragments can be written by hand, or they can be generated
+# from preconfigure.in by autoconf like sysdeps/.../configure.in files.
+
+# Figure out the name of this add-on. The ports add-on infrastructure
+# scripts can be copied into separate add-on packages by any name.
+ports-sysdeps = $(..)$(Makeconfig-add-on)/sysdeps
+
+$(common-objpfx)config.status: $(wildcard $(ports-sysdeps)/*/preconfigure)
+
+ifneq ($(AUTOCONF),no)
+
+ifeq ($(with-cvs),yes)
+define autoconf-it-cvs
+test ! -d CVS || cvs $(CVSOPTS) commit -m'Regenerated: autoconf $(ACFLAGS) $<' $@
+endef
+else
+autoconf-it-cvs =
+endif
+
+define autoconf-it
+@-rm -f $@.new
+$(AUTOCONF) $(ACFLAGS) $< > $@.new
+chmod a-w,a+x $@.new
+mv -f $@.new $@
+$(autoconf-it-cvs)
+endef
+
+$(..)ports/sysdeps/%/preconfigure: $(..)ports/sysdeps/%/preconfigure.in \
+ aclocal.m4
+ $(autoconf-it)
+
+endif # $(AUTOCONF) = no
+
+# This allows e.g. `make ports/dist' from a build directory.
+ifndef subdir
+ports/%:
+ $(MAKE) $(PARALLELMFLAGS) -C $(@D) $(@F)
+endif
diff --git a/libc/hurd-l4/Makefile b/libc/hurd-l4/Makefile
new file mode 100644
index 0000000..b372ec7
--- /dev/null
+++ b/libc/hurd-l4/Makefile
@@ -0,0 +1,41 @@
+# This boilerplate is necessary just because any add-on directory
+# gets added as a normal subdirectory for the glibc build process.
+
+subdir = hurd-l4
+
+include ../Rules
+
+.PHONY: dist dist-ports
+dist: dist-ports
+
+# Do `make dist dist-version=X.Y.Z' to make tar files of an older version.
+dist-version = $(version)
+# Also try 'dist-tag=some="-r TAG"' (or -D DATE) to get some tag rather
+# than the release tag for X.Y.Z.
+dist-tag = -r glibc-$(subst .,_,$(dist-version))
+
+distname = glibc-ports-$(dist-version)
+
+do-export = cvs $(CVSOPTS) -Q export -d $(basename $@) $(dist-tag)
+
+dist-ports: $(foreach Z,.bz2 .gz,$(distname).tar$Z)
+ md5sum $^
+$(distname).tar:
+ @rm -fr $(basename $@)
+ $(do-export) ports
+ tar cf $@ $(basename $@)
+ rm -fr $(basename $@)
+
+.PRECIOUS: %.gz %.bz2 # Don't delete output as intermediate files.
+dist-port-%: $(foreach Z,.bz2 .gz,glibc-port-%-$(dist-version).tar$Z)
+ md5sum $^
+glibc-port-%-$(dist-version).tar: configure ChangeLog
+ @rm -fr $(basename $@)
+ $(do-export) -l ports
+ rm -f $(basename $@)/ChangeLog.[a-z]*
+ $(do-export) ports/ChangeLog.$* \
+ ports/sysdeps/$* ports/sysdeps/unix/sysv/linux/$*
+ mv $(basename $@)/ports/* $(basename $@)/
+ rmdir $(basename $@)/ports
+ tar cf $@ $(basename $@)
+ rm -fr $(basename $@)
diff --git a/libc/hurd-l4/configure b/libc/hurd-l4/configure
new file mode 100644
index 0000000..77d4ea4
--- /dev/null
+++ b/libc/hurd-l4/configure
@@ -0,0 +1,18 @@
+# This file is generated from configure.in by Autoconf. DO NOT EDIT!
+
+# The configure fragment in this file provides infrastructure for a glibc
+# add-on containing one or more glibc ports. Only these few script files
+# need exist in the top-level source directory of the add-on. The ports
+# themselves are contained entirely within their new sysdeps/ directories.
+# This makes it easy to take these few top-level files plus a new port's
+# additions to the sysdeps tree, and package a small add-on for that port.
+# The same infrastructure scripts work for any number of such glibc ports
+# collected together into a single shared add-on package.
+
+cpu_frags=`(cd $srcdir/$libc_add_on; echo sysdeps/*/preconfigure)`
+test x"$cpu_frags" = x'sysdeps/*/preconfigure' ||
+for frag in $cpu_frags; do
+ echo "$as_me:$LINENO: result: ports add-on running preconfigure fragment $frag" >&5
+echo "${ECHO_T}ports add-on running preconfigure fragment $frag" >&6
+ . $srcdir/$libc_add_on/$frag
+done
diff --git a/libc/hurd-l4/configure.in b/libc/hurd-l4/configure.in
new file mode 100644
index 0000000..93b987a
--- /dev/null
+++ b/libc/hurd-l4/configure.in
@@ -0,0 +1,18 @@
+dnl glibc add-on configure.in fragment for a ports add-on.
+GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
+
+# The configure fragment in this file provides infrastructure for a glibc
+# add-on containing one or more glibc ports. Only these few script files
+# need exist in the top-level source directory of the add-on. The ports
+# themselves are contained entirely within their new sysdeps/ directories.
+# This makes it easy to take these few top-level files plus a new port's
+# additions to the sysdeps tree, and package a small add-on for that port.
+# The same infrastructure scripts work for any number of such glibc ports
+# collected together into a single shared add-on package.
+
+cpu_frags=`(cd $srcdir/$libc_add_on; echo sysdeps/*/preconfigure)`
+test x"$cpu_frags" = x'sysdeps/*/preconfigure' ||
+for frag in $cpu_frags; do
+ AC_MSG_RESULT(ports add-on running preconfigure fragment $frag)
+ . $srcdir/$libc_add_on/$frag
+done
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/Implies b/libc/hurd-l4/sysdeps/l4/hurd/Implies
new file mode 100644
index 0000000..b606346
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/Implies
@@ -0,0 +1,5 @@
+# The gnu subdirectory exists for things common to both Linux-based and
+# Hurd-based GNU systems.
+gnu
+# The Hurd provides a rough superset of the functionality of 4.4 BSD.
+unix/bsd/bsd4.4
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/Makefile b/libc/hurd-l4/sysdeps/l4/hurd/Makefile
new file mode 100644
index 0000000..04d95ac
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/Makefile
@@ -0,0 +1,45 @@
+# Copyright (C) 1993,94,95,96,97,98,99,2000,2001,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; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+sysdep_routines += errno-loc mremap
+endif
+
+ifeq ($(subdir),posix)
+sysdep_routines += exit-thread
+endif
+
+ifdef in-Makerules
+
+# We use the style `if (err = call(...))' a lot in the Hurd code,
+# where we have a lot of functions that return zero or an errno code.
++cflags += -Wno-parentheses
+
+# Do not use any assembly code from sysdeps/unix (and subdirectories).
+# This bypasses all the system call stubs and uses any existing posix or
+# generic C files instead.
+inhibit-sysdep-asm += unix*
+inhibit-unix-syscalls = yes
+
+# Don't try to generate anything from the installed Unix system and its
+# libraries. That is only of use when building for a Unix system, so as to
+# be compatible with some existing binaries for that system.
+inhibit-glue = yes
+
+endif # in-Makerules
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/_G_config.h b/libc/hurd-l4/sysdeps/l4/hurd/_G_config.h
new file mode 100644
index 0000000..83c78f0
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/_G_config.h
@@ -0,0 +1,103 @@
+/* This file is needed by libio to define various configuration parameters.
+ These are always the same in the GNU C library. */
+
+#ifndef _G_config_h
+#define _G_config_h 1
+
+/* Define types for libio in terms of the standard internal type names. */
+
+#include <bits/types.h>
+#define __need_size_t
+#define __need_wchar_t
+#define __need_wint_t
+#define __need_NULL
+#include <stddef.h>
+#ifndef _WINT_T
+/* Integral type unchanged by default argument promotions that can
+ hold any value corresponding to members of the extended character
+ set, as well as at least one value that does not correspond to any
+ member of the extended character set. */
+# define _WINT_T
+typedef unsigned int wint_t;
+#endif
+#define __need_mbstate_t
+#include <wchar.h>
+#define _G_size_t size_t
+typedef struct
+{
+ __off_t __pos;
+ __mbstate_t __state;
+} _G_fpos_t;
+typedef struct
+{
+ __off64_t __pos;
+ __mbstate_t __state;
+} _G_fpos64_t;
+#define _G_ssize_t __ssize_t
+#define _G_off_t __off_t
+#define _G_off64_t __off64_t
+#define _G_pid_t __pid_t
+#define _G_uid_t __uid_t
+#define _G_wchar_t wchar_t
+#define _G_wint_t wint_t
+#define _G_stat64 stat64
+#include <gconv.h>
+typedef union
+{
+ struct __gconv_info __cd;
+ struct
+ {
+ struct __gconv_info __cd;
+ struct __gconv_step_data __data;
+ } __combined;
+} _G_iconv_t;
+
+typedef int _G_int16_t __attribute__ ((__mode__ (__HI__)));
+typedef int _G_int32_t __attribute__ ((__mode__ (__SI__)));
+typedef unsigned int _G_uint16_t __attribute__ ((__mode__ (__HI__)));
+typedef unsigned int _G_uint32_t __attribute__ ((__mode__ (__SI__)));
+
+#define _G_HAVE_BOOL 1
+
+
+/* These library features are always available in the GNU C library. */
+#define _G_HAVE_ATEXIT 1
+#define _G_HAVE_SYS_CDEFS 1
+#define _G_HAVE_SYS_WAIT 1
+#define _G_NEED_STDARG_H 1
+#define _G_va_list __gnuc_va_list
+
+#define _G_HAVE_PRINTF_FP 1
+#define _G_HAVE_MMAP 1
+#define _G_HAVE_MREMAP 1
+#define _G_HAVE_LONG_DOUBLE_IO 1
+#define _G_HAVE_IO_FILE_OPEN 1
+#define _G_HAVE_IO_GETLINE_INFO 1
+
+#define _G_IO_IO_FILE_VERSION 0x20001
+
+#define _G_OPEN64 __open64
+#define _G_LSEEK64 __lseek64
+#define _G_MMAP64 __mmap64
+#define _G_FSTAT64(fd,buf) __fxstat64 (_STAT_VER, fd, buf)
+
+/* This is defined by <bits/stat.h> if `st_blksize' exists. */
+#define _G_HAVE_ST_BLKSIZE defined (_STATBUF_ST_BLKSIZE)
+
+#define _G_BUFSIZ 8192
+
+/* These are the vtbl details for ELF. */
+#define _G_NAMES_HAVE_UNDERSCORE 0
+#define _G_VTABLE_LABEL_HAS_LENGTH 1
+#define _G_USING_THUNKS 1
+#define _G_VTABLE_LABEL_PREFIX "__vt_"
+#define _G_VTABLE_LABEL_PREFIX_ID __vt_
+
+
+#if defined __cplusplus || defined __STDC__
+# define _G_ARGS(ARGLIST) ARGLIST
+#else
+# define _G_ARGS(ARGLIST) ()
+#endif
+
+#endif /* _G_config.h */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/_exit.c b/libc/hurd-l4/sysdeps/l4/hurd/_exit.c
new file mode 100644
index 0000000..673667d
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/_exit.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1991,94,95,96,97,99,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <unistd.h>
+#include <stdlib.h>
+
+/* The function `_exit' should take a status argument and simply
+ terminate program execution, using the low-order 8 bits of the
+ given integer as status. */
+void
+_exit (status)
+ int status;
+{
+ status &= 0xff;
+ abort ();
+}
+libc_hidden_def (_exit)
+weak_alias (_exit, _Exit)
+
+stub_warning (_exit)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/errno.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/errno.h
new file mode 100644
index 0000000..dffe7c8
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/errno.h
@@ -0,0 +1,264 @@
+/* FIXME: Make this file generated by errnos.awk. */
+
+/* FIXME: I suggest the following scheme:
+ system (8) | subsystem (8) | code (16).
+
+ 0: The Hurd
+ 0-0: The POSIX personality of the Hurd.
+ 0-1: The Hurd capability system (including RPC stub generator).
+ 0-2: Fabrica (Device Driver Framework exported through DEVA)
+ 1: L4
+*/
+
+/* The POSIX personality of the Hurd uses error system 0, subsystem 0. */
+#ifndef _HURD_ERRNO
+#define _HURD_ERRNO(n) ((n) & 0xffff)
+#endif
+
+#ifdef _ERRNO_H
+
+enum __error_t_codes
+{
+#undef EDOM
+#undef ERANGE
+ EPERM = _HURD_ERRNO (1),
+#define EPERM _HURD_ERRNO (1) /* Operation not permitted */
+ ENOENT = _HURD_ERRNO (2),
+#define ENOENT _HURD_ERRNO (2) /* No such file or directory */
+ ESRCH = _HURD_ERRNO (3),
+#define ESRCH _HURD_ERRNO (3) /* No such process */
+ EINTR = _HURD_ERRNO (4),
+#define EINTR _HURD_ERRNO (4) /* Interrupted system call */
+ EIO = _HURD_ERRNO (5),
+#define EIO _HURD_ERRNO (5) /* Input/output error */
+ ENXIO = _HURD_ERRNO (6),
+#define ENXIO _HURD_ERRNO (6) /* No such device or address */
+ E2BIG = _HURD_ERRNO (7),
+#define E2BIG _HURD_ERRNO (7) /* Argument list too long */
+ ENOEXEC = _HURD_ERRNO (8),
+#define ENOEXEC _HURD_ERRNO (8) /* Exec format error */
+ EBADF = _HURD_ERRNO (9),
+#define EBADF _HURD_ERRNO (9) /* Bad file descriptor */
+ ECHILD = _HURD_ERRNO (10),
+#define ECHILD _HURD_ERRNO (10)/* No child processes */
+ EDEADLK = _HURD_ERRNO (11),
+#define EDEADLK _HURD_ERRNO (11)/* Resource deadlock avoided */
+ ENOMEM = _HURD_ERRNO (12),
+#define ENOMEM _HURD_ERRNO (12)/* Cannot allocate memory */
+ EACCES = _HURD_ERRNO (13),
+#define EACCES _HURD_ERRNO (13)/* Permission denied */
+ EFAULT = _HURD_ERRNO (14),
+#define EFAULT _HURD_ERRNO (14)/* Bad address */
+ ENOTBLK = _HURD_ERRNO (15),
+#define ENOTBLK _HURD_ERRNO (15)/* Block device required */
+ EBUSY = _HURD_ERRNO (16),
+#define EBUSY _HURD_ERRNO (16)/* Device or resource busy */
+ EEXIST = _HURD_ERRNO (17),
+#define EEXIST _HURD_ERRNO (17)/* File exists */
+ EXDEV = _HURD_ERRNO (18),
+#define EXDEV _HURD_ERRNO (18)/* Invalid cross-device link */
+ ENODEV = _HURD_ERRNO (19),
+#define ENODEV _HURD_ERRNO (19)/* No such device */
+ ENOTDIR = _HURD_ERRNO (20),
+#define ENOTDIR _HURD_ERRNO (20)/* Not a directory */
+ EISDIR = _HURD_ERRNO (21),
+#define EISDIR _HURD_ERRNO (21)/* Is a directory */
+ EINVAL = _HURD_ERRNO (22),
+#define EINVAL _HURD_ERRNO (22)/* Invalid argument */
+ EMFILE = _HURD_ERRNO (24),
+#define EMFILE _HURD_ERRNO (24)/* Too many open files */
+ ENFILE = _HURD_ERRNO (23),
+#define ENFILE _HURD_ERRNO (23)/* Too many open files in system */
+ ENOTTY = _HURD_ERRNO (25),
+#define ENOTTY _HURD_ERRNO (25)/* Inappropriate ioctl for device */
+ ETXTBSY = _HURD_ERRNO (26),
+#define ETXTBSY _HURD_ERRNO (26)/* Text file busy */
+ EFBIG = _HURD_ERRNO (27),
+#define EFBIG _HURD_ERRNO (27)/* File too large */
+ ENOSPC = _HURD_ERRNO (28),
+#define ENOSPC _HURD_ERRNO (28)/* No space left on device */
+ ESPIPE = _HURD_ERRNO (29),
+#define ESPIPE _HURD_ERRNO (29)/* Illegal seek */
+ EROFS = _HURD_ERRNO (30),
+#define EROFS _HURD_ERRNO (30)/* Read-only file system */
+ EMLINK = _HURD_ERRNO (31),
+#define EMLINK _HURD_ERRNO (31)/* Too many links */
+ EPIPE = _HURD_ERRNO (32),
+#define EPIPE _HURD_ERRNO (32)/* Broken pipe */
+ EDOM = _HURD_ERRNO (33),
+#define EDOM _HURD_ERRNO (33)/* Numerical argument out of domain */
+ ERANGE = _HURD_ERRNO (34),
+#define ERANGE _HURD_ERRNO (34)/* Numerical result out of range */
+ EAGAIN = _HURD_ERRNO (35),
+#define EAGAIN _HURD_ERRNO (35)/* Resource temporarily unavailable */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+ EINPROGRESS = _HURD_ERRNO (36),
+#define EINPROGRESS _HURD_ERRNO (36)/* Operation now in progress */
+ EALREADY = _HURD_ERRNO (37),
+#define EALREADY _HURD_ERRNO (37)/* Operation already in progress */
+ ENOTSOCK = _HURD_ERRNO (38),
+#define ENOTSOCK _HURD_ERRNO (38)/* Socket operation on non-socket */
+ EMSGSIZE = _HURD_ERRNO (40),
+#define EMSGSIZE _HURD_ERRNO (40)/* Message too long */
+ EPROTOTYPE = _HURD_ERRNO (41),
+#define EPROTOTYPE _HURD_ERRNO (41)/* Protocol wrong type for socket */
+ ENOPROTOOPT = _HURD_ERRNO (42),
+#define ENOPROTOOPT _HURD_ERRNO (42)/* Protocol not available */
+ EPROTONOSUPPORT = _HURD_ERRNO (43),
+#define EPROTONOSUPPORT _HURD_ERRNO (43)/* Protocol not supported */
+ ESOCKTNOSUPPORT = _HURD_ERRNO (44),
+#define ESOCKTNOSUPPORT _HURD_ERRNO (44)/* Socket type not supported */
+ EOPNOTSUPP = _HURD_ERRNO (45),
+#define EOPNOTSUPP _HURD_ERRNO (45)/* Operation not supported */
+ EPFNOSUPPORT = _HURD_ERRNO (46),
+#define EPFNOSUPPORT _HURD_ERRNO (46)/* Protocol family not supported */
+ EAFNOSUPPORT = _HURD_ERRNO (47),
+#define EAFNOSUPPORT _HURD_ERRNO (47)/* Address family not supported by protocol */
+ EADDRINUSE = _HURD_ERRNO (48),
+#define EADDRINUSE _HURD_ERRNO (48)/* Address already in use */
+ EADDRNOTAVAIL = _HURD_ERRNO (49),
+#define EADDRNOTAVAIL _HURD_ERRNO (49)/* Cannot assign requested address */
+ ENETDOWN = _HURD_ERRNO (50),
+#define ENETDOWN _HURD_ERRNO (50)/* Network is down */
+ ENETUNREACH = _HURD_ERRNO (51),
+#define ENETUNREACH _HURD_ERRNO (51)/* Network is unreachable */
+ ENETRESET = _HURD_ERRNO (52),
+#define ENETRESET _HURD_ERRNO (52)/* Network dropped connection on reset */
+ ECONNABORTED = _HURD_ERRNO (53),
+#define ECONNABORTED _HURD_ERRNO (53)/* Software caused connection abort */
+ ECONNRESET = _HURD_ERRNO (54),
+#define ECONNRESET _HURD_ERRNO (54)/* Connection reset by peer */
+ ENOBUFS = _HURD_ERRNO (55),
+#define ENOBUFS _HURD_ERRNO (55)/* No buffer space available */
+ EISCONN = _HURD_ERRNO (56),
+#define EISCONN _HURD_ERRNO (56)/* Transport endpoint is already connected */
+ ENOTCONN = _HURD_ERRNO (57),
+#define ENOTCONN _HURD_ERRNO (57)/* Transport endpoint is not connected */
+ EDESTADDRREQ = _HURD_ERRNO (39),
+#define EDESTADDRREQ _HURD_ERRNO (39)/* Destination address required */
+ ESHUTDOWN = _HURD_ERRNO (58),
+#define ESHUTDOWN _HURD_ERRNO (58)/* Cannot send after transport endpoint shutdown */
+ ETOOMANYREFS = _HURD_ERRNO (59),
+#define ETOOMANYREFS _HURD_ERRNO (59)/* Too many references: cannot splice */
+ ETIMEDOUT = _HURD_ERRNO (60),
+#define ETIMEDOUT _HURD_ERRNO (60)/* Connection timed out */
+ ECONNREFUSED = _HURD_ERRNO (61),
+#define ECONNREFUSED _HURD_ERRNO (61)/* Connection refused */
+ ELOOP = _HURD_ERRNO (62),
+#define ELOOP _HURD_ERRNO (62)/* Too many levels of symbolic links */
+ ENAMETOOLONG = _HURD_ERRNO (63),
+#define ENAMETOOLONG _HURD_ERRNO (63)/* File name too long */
+ EHOSTDOWN = _HURD_ERRNO (64),
+#define EHOSTDOWN _HURD_ERRNO (64)/* Host is down */
+ EHOSTUNREACH = _HURD_ERRNO (65),
+#define EHOSTUNREACH _HURD_ERRNO (65)/* No route to host */
+ ENOTEMPTY = _HURD_ERRNO (66),
+#define ENOTEMPTY _HURD_ERRNO (66)/* Directory not empty */
+ EPROCLIM = _HURD_ERRNO (67),
+#define EPROCLIM _HURD_ERRNO (67)/* Too many processes */
+ EUSERS = _HURD_ERRNO (68),
+#define EUSERS _HURD_ERRNO (68)/* Too many users */
+ EDQUOT = _HURD_ERRNO (69),
+#define EDQUOT _HURD_ERRNO (69)/* Disk quota exceeded */
+ ESTALE = _HURD_ERRNO (70),
+#define ESTALE _HURD_ERRNO (70)/* Stale NFS file handle */
+ EREMOTE = _HURD_ERRNO (71),
+#define EREMOTE _HURD_ERRNO (71)/* Object is remote */
+ EBADRPC = _HURD_ERRNO (72),
+#define EBADRPC _HURD_ERRNO (72)/* RPC struct is bad */
+ ERPCMISMATCH = _HURD_ERRNO (73),
+#define ERPCMISMATCH _HURD_ERRNO (73)/* RPC version wrong */
+ EPROGUNAVAIL = _HURD_ERRNO (74),
+#define EPROGUNAVAIL _HURD_ERRNO (74)/* RPC program not available */
+ EPROGMISMATCH = _HURD_ERRNO (75),
+#define EPROGMISMATCH _HURD_ERRNO (75)/* RPC program version wrong */
+ EPROCUNAVAIL = _HURD_ERRNO (76),
+#define EPROCUNAVAIL _HURD_ERRNO (76)/* RPC bad procedure for program */
+ ENOLCK = _HURD_ERRNO (77),
+#define ENOLCK _HURD_ERRNO (77)/* No locks available */
+ EFTYPE = _HURD_ERRNO (79),
+#define EFTYPE _HURD_ERRNO (79)/* Inappropriate file type or format */
+ EAUTH = _HURD_ERRNO (80),
+#define EAUTH _HURD_ERRNO (80)/* Authentication error */
+ ENEEDAUTH = _HURD_ERRNO (81),
+#define ENEEDAUTH _HURD_ERRNO (81)/* Need authenticator */
+ ENOSYS = _HURD_ERRNO (78),
+#define ENOSYS _HURD_ERRNO (78)/* Function not implemented */
+ ENOTSUP = _HURD_ERRNO (118),
+#define ENOTSUP _HURD_ERRNO (118)/* Not supported */
+ EILSEQ = _HURD_ERRNO (106),
+#define EILSEQ _HURD_ERRNO (106)/* Invalid or incomplete multibyte or wide character */
+ EBACKGROUND = _HURD_ERRNO (100),
+#define EBACKGROUND _HURD_ERRNO (100)/* Inappropriate operation for background process */
+ EDIED = _HURD_ERRNO (101),
+#define EDIED _HURD_ERRNO (101)/* Translator died */
+ ED = _HURD_ERRNO (102),
+#define ED _HURD_ERRNO (102)/* ? */
+ EGREGIOUS = _HURD_ERRNO (103),
+#define EGREGIOUS _HURD_ERRNO (103)/* You really blew it this time */
+ EIEIO = _HURD_ERRNO (104),
+#define EIEIO _HURD_ERRNO (104)/* Computer bought the farm */
+ EGRATUITOUS = _HURD_ERRNO (105),
+#define EGRATUITOUS _HURD_ERRNO (105)/* Gratuitous error */
+ EBADMSG = _HURD_ERRNO (107),
+#define EBADMSG _HURD_ERRNO (107)/* Bad message */
+ EIDRM = _HURD_ERRNO (108),
+#define EIDRM _HURD_ERRNO (108)/* Identifier removed */
+ EMULTIHOP = _HURD_ERRNO (109),
+#define EMULTIHOP _HURD_ERRNO (109)/* Multihop attempted */
+ ENODATA = _HURD_ERRNO (110),
+#define ENODATA _HURD_ERRNO (110)/* No data available */
+ ENOLINK = _HURD_ERRNO (111),
+#define ENOLINK _HURD_ERRNO (111)/* Link has been severed */
+ ENOMSG = _HURD_ERRNO (112),
+#define ENOMSG _HURD_ERRNO (112)/* No message of desired type */
+ ENOSR = _HURD_ERRNO (113),
+#define ENOSR _HURD_ERRNO (113)/* Out of streams resources */
+ ENOSTR = _HURD_ERRNO (114),
+#define ENOSTR _HURD_ERRNO (114)/* Device not a stream */
+ EOVERFLOW = _HURD_ERRNO (115),
+#define EOVERFLOW _HURD_ERRNO (115)/* Value too large for defined data type */
+ EPROTO = _HURD_ERRNO (116),
+#define EPROTO _HURD_ERRNO (116)/* Protocol error */
+ ETIME = _HURD_ERRNO (117),
+#define ETIME _HURD_ERRNO (117)/* Timer expired */
+ ECANCELED = _HURD_ERRNO (118),
+#define ECANCELED _HURD_ERRNO (118)/* Operation canceled */
+
+ /* Errors from <l4/mach/message.h>. */
+
+#ifndef _HURD_L4_ERRNO
+#define _HURD_L4_ERRNO(n) ((1 << 24) | ((n) & 0xffff))
+#endif
+
+ EL4_NO_PRIVILEGE = _HURD_L4_ERRNO(1),
+ EL4_INV_THREAD = _HURD_L4_ERRNO(2),
+ EL4_INV_SPACE = _HURD_L4_ERRNO(3),
+ EL4_INV_SCHEDULER = _HURD_L4_ERRNO(4),
+ EL4_INV_PARAM = _HURD_L4_ERRNO(5),
+ EL4_UTCB_AREA = _HURD_L4_ERRNO(6),
+ EL4_KIP_AREA = _HURD_L4_ERRNO(7),
+ EL4_NO_MEM = _HURD_L4_ERRNO(8)
+};
+
+#define _HURD_ERRNOS 119
+
+/* User-visible type of error codes. It is ok to use `int' for these,
+ but with `error_t' the debugger prints symbolic values. */
+#ifdef __USE_GNU
+typedef enum __error_t_codes error_t;
+#define __error_t_defined 1
+#endif
+
+/* Return the current thread's location for `errno'.
+ The syntax of this function allows redeclarations like `int errno'. */
+extern int *__errno_location (void) __THROW __attribute__ ((__const__));
+
+#define errno (*__errno_location ())
+
+#endif /* <errno.h> included. */
+
+#if !defined (_ERRNO_H) && defined (__need_Emath)
+#define EDOM _HURD_ERRNO (33)/* Numerical argument out of domain */
+#define ERANGE _HURD_ERRNO (34)/* Numerical result out of range */
+#endif /* <errno.h> not included and need math error codes. */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/fcntl.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/fcntl.h
new file mode 100644
index 0000000..e709cc6
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/fcntl.h
@@ -0,0 +1,210 @@
+/* O_*, F_*, FD_* bit values for GNU.
+ Copyright (C) 1993,94,96,97,98,99,2000,01,04 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 _FCNTL_H
+# error "Never use <bits/fcntl.h> directly; include <fcntl.h> instead."
+#endif
+
+/* File access modes. These are understood by io servers; they can be
+ passed in `dir_lookup', and are returned by `io_get_openmodes'.
+ Consequently they can be passed to `open', `hurd_file_name_lookup', and
+ `file_name_lookup'; and are returned by `fcntl' with the F_GETFL
+ command. */
+
+/* In GNU, read and write are bits (unlike BSD). */
+#ifdef __USE_GNU
+# define O_READ O_RDONLY /* Open for reading. */
+# define O_WRITE O_WRONLY /* Open for writing. */
+# define O_EXEC 0x0004 /* Open for execution. */
+# define O_NORW 0 /* Open without R/W access. */
+#endif
+/* POSIX.1 standard names. */
+#define O_RDONLY 0x0001 /* Open read-only. */
+#define O_WRONLY 0x0002 /* Open write-only. */
+#define O_RDWR (O_RDONLY|O_WRONLY) /* Open for reading and writing. */
+#define O_ACCMODE O_RDWR /* Mask for file access modes. */
+
+#define O_LARGEFILE 0
+
+
+/* File name translation flags. These are understood by io servers;
+ they can be passed in `dir_lookup', and consequently to `open',
+ `hurd_file_name_lookup', and `file_name_lookup'. */
+
+#define O_CREAT 0x0010 /* Create file if it doesn't exist. */
+#define O_EXCL 0x0020 /* Fail if file already exists. */
+#ifdef __USE_GNU
+# define O_NOLINK 0x0040 /* No name mappings on final component. */
+# define O_NOTRANS 0x0080 /* No translator on final component. */
+
+# define O_NOFOLLOW 0x00100000 /* Produce ENOENT if file is a symlink. */
+# define O_DIRECTORY 0x00200000 /* Produce ENOTDIR if not a directory. */
+#endif
+
+
+/* I/O operating modes. These are understood by io servers; they can be
+ passed in `dir_lookup' and set or fetched with `io_*_openmodes'.
+ Consequently they can be passed to `open', `hurd_file_name_lookup',
+ `file_name_lookup', and `fcntl' with the F_SETFL command; and are
+ returned by `fcntl' with the F_GETFL command. */
+
+#define O_APPEND 0x0100 /* Writes always append to the file. */
+#define O_ASYNC 0x0200 /* Send SIGIO to owner when data is ready. */
+#define O_FSYNC 0x0400 /* Synchronous writes. */
+#define O_SYNC O_FSYNC
+#ifdef __USE_GNU
+# define O_NOATIME 0x0800 /* Don't set access time on read (owner). */
+#endif
+#ifdef __USE_MISC
+# define O_SHLOCK 0x00020000 /* Open with shared file lock. */
+# define O_EXLOCK 0x00040000 /* Open with exclusive file lock. */
+#endif
+
+/* These are lesser flavors of partial synchronization that are
+ implied by our one flag (O_FSYNC). */
+#if defined __USE_POSIX199309 || defined __USE_UNIX98
+# define O_DSYNC O_SYNC /* Synchronize data. */
+# define O_RSYNC O_SYNC /* Synchronize read operations. */
+#endif
+
+
+/* The name O_NONBLOCK is unfortunately overloaded; it is both a file name
+ translation flag and an I/O operating mode. O_NDELAY is the deprecated
+ BSD name for the same flag, overloaded in the same way.
+
+ When used in `dir_lookup' (and consequently `open', `hurd_file_name_lookup',
+ or `file_name_lookup'), O_NONBLOCK says the open should return immediately
+ instead of blocking for any significant length of time (e.g., to wait
+ for carrier detect on a serial line). It is also saved as an I/O
+ operating mode, and after open has the following meaning.
+
+ When used in `io_*_openmodes' (and consequently `fcntl' with the F_SETFL
+ command), the O_NONBLOCK flag means to do nonblocking i/o: any i/o
+ operation that would block for any significant length of time will instead
+ fail with EAGAIN. */
+
+#define O_NONBLOCK 0x0008 /* Non-blocking open or non-blocking I/O. */
+#ifdef __USE_BSD
+# define O_NDELAY O_NONBLOCK /* Deprecated. */
+#endif
+
+
+#ifdef __USE_GNU
+/* Mask of bits which are understood by io servers. */
+# define O_HURD (0xffff | O_EXLOCK | O_SHLOCK)
+#endif
+
+
+/* Open-time action flags. These are understood by `hurd_file_name_lookup'
+ and consequently by `open' and `file_name_lookup'. They are not preserved
+ once the file has been opened. */
+
+#define O_TRUNC 0x00010000 /* Truncate file to zero length. */
+
+
+/* Controlling terminal flags. These are understood only by `open',
+ and are not preserved once the file has been opened. */
+
+#ifdef __USE_GNU
+# define O_IGNORE_CTTY 0x00080000 /* Don't do any ctty magic at all. */
+#endif
+/* `open' never assigns a controlling terminal in GNU. */
+#define O_NOCTTY 0 /* Don't assign a controlling terminal. */
+
+
+#ifdef __USE_BSD
+/* Bits in the file status flags returned by F_GETFL. */
+# define FREAD O_RDONLY
+# define FWRITE O_WRONLY
+
+/* Traditional BSD names the O_* bits. */
+# define FASYNC O_ASYNC
+# define FCREAT O_CREAT
+# define FEXCL O_EXCL
+# define FTRUNC O_TRUNC
+# define FNOCTTY O_NOCTTY
+# define FFSYNC O_FSYNC
+# define FSYNC O_SYNC
+# define FAPPEND O_APPEND
+# define FNONBLOCK O_NONBLOCK
+# define FNDELAY O_NDELAY
+#endif
+
+
+/* Values for the second argument to `fcntl'. */
+#define F_DUPFD 0 /* Duplicate file descriptor. */
+#define F_GETFD 1 /* Get file descriptor flags. */
+#define F_SETFD 2 /* Set file descriptor flags. */
+#define F_GETFL 3 /* Get file status flags. */
+#define F_SETFL 4 /* Set file status flags. */
+#if defined __USE_BSD || defined __USE_UNIX98
+# define F_GETOWN 5 /* Get owner (receiver of SIGIO). */
+# define F_SETOWN 6 /* Set owner (receiver of SIGIO). */
+#endif
+#define F_GETLK 7 /* Get record locking info. */
+#define F_SETLK 8 /* Set record locking info (non-blocking). */
+#define F_SETLKW 9 /* Set record locking info (blocking). */
+
+/* File descriptor flags used with F_GETFD and F_SETFD. */
+#define FD_CLOEXEC 1 /* Close on exec. */
+
+
+#include <bits/types.h>
+
+/* The structure describing an advisory lock. This is the type of the third
+ argument to `fcntl' for the F_GETLK, F_SETLK, and F_SETLKW requests. */
+struct flock
+ {
+ int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
+ int l_whence; /* Where `l_start' is relative to (like `lseek'). */
+#ifndef __USE_FILE_OFFSET64
+ __off_t l_start; /* Offset where the lock begins. */
+ __off_t l_len; /* Size of the locked area; zero means until EOF. */
+#else
+ __off64_t l_start; /* Offset where the lock begins. */
+ __off64_t l_len; /* Size of the locked area; zero means until EOF. */
+#endif
+ __pid_t l_pid; /* Process holding the lock. */
+ };
+
+#ifdef __USE_LARGEFILE64
+struct flock64
+ {
+ int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
+ int l_whence; /* Where `l_start' is relative to (like `lseek'). */
+ __off64_t l_start; /* Offset where the lock begins. */
+ __off64_t l_len; /* Size of the locked area; zero means until EOF. */
+ __pid_t l_pid; /* Process holding the lock. */
+ };
+#endif
+
+/* Values for the `l_type' field of a `struct flock'. */
+#define F_RDLCK 1 /* Read lock. */
+#define F_WRLCK 2 /* Write lock. */
+#define F_UNLCK 3 /* Remove lock. */
+
+/* Advise to `posix_fadvise'. */
+#ifdef __USE_XOPEN2K
+# define POSIX_FADV_NORMAL 0 /* No further special treatment. */
+# define POSIX_FADV_RANDOM 1 /* Expect random page references. */
+# define POSIX_FADV_SEQUENTIAL 2 /* Expect sequential page references. */
+# define POSIX_FADV_WILLNEED 3 /* Will need these pages. */
+# define POSIX_FADV_DONTNEED 4 /* Don't need these pages. */
+# define POSIX_FADV_NOREUSE 5 /* Data will be accessed once. */
+#endif
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/local_lim.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/local_lim.h
new file mode 100644
index 0000000..51a2791
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/local_lim.h
@@ -0,0 +1,46 @@
+/* Minimum guaranteed maximum values for system limits. Hurd version.
+ Copyright (C) 1993,94,96,98,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* GNU has no arbitrary fixed limits on most of these things, so we
+ don't define the macros. Some things are unlimited. Some are in
+ fact limited but the limit is run-time dependent and fetched with
+ `sysconf' or `pathconf'. */
+
+/* This one value is actually constrained by the `struct dirent'
+ layout, in which the `d_namlen' member is only 8 bits wide. */
+
+#define NAME_MAX 255
+
+/* POSIX.1 requires that we define NGROUPS_MAX (though none of the others
+ is required). GNU allows any number of supplementary groups,
+ dynamically allocated. So we pick a number which seems vaguely
+ suitable, and `sysconf' will return a number at least as large. */
+
+#define NGROUPS_MAX 256
+
+/* The maximum number of symbolic links that are allowed in a single file
+ name resolution. When a further link is encountered, the call returns
+ ELOOP. This name is a GNU extension; POSIX.1 has no such limit, and BSD
+ calls it MAXSYMLINKS in <sys/param.h>. (We define the name under
+ _BSD_SOURCE even without _GNU_SOURCE because our <sys/param.h> uses it
+ to define MAXSYMLINKS.) */
+
+#if defined __USE_GNU || defined __USE_BSD /* 1003.1a defines this */
+#define SYMLOOP_MAX 8
+#endif
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/mman.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/mman.h
new file mode 100644
index 0000000..ab42ca0
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/mman.h
@@ -0,0 +1,96 @@
+/* Definitions for BSD-style memory management.
+ Copyright (C) 1994-1998,2000,01,02 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. */
+
+/* These are the bits used by 4.4 BSD and its derivatives. On systems
+ (such as GNU) where these facilities are not system services but can be
+ emulated in the C library, these are the definitions we emulate. */
+
+#ifndef _SYS_MMAN_H
+# error "Never use <bits/mman.h> directly; include <sys/mman.h> instead."
+#endif
+
+/* Protections are chosen from these bits, OR'd together. The
+ implementation does not necessarily support PROT_EXEC or PROT_WRITE
+ without PROT_READ. The only guarantees are that no writing will be
+ allowed without PROT_WRITE and no access will be allowed for PROT_NONE. */
+
+#define PROT_NONE 0x00 /* No access. */
+#define PROT_READ 0x04 /* Pages can be read. */
+#define PROT_WRITE 0x02 /* Pages can be written. */
+#define PROT_EXEC 0x01 /* Pages can be executed. */
+
+/* Flags contain mapping type, sharing type and options. */
+
+/* Mapping type (must choose one and only one of these). */
+#ifdef __USE_BSD
+# define MAP_FILE 0x0001 /* Mapped from a file or device. */
+# define MAP_ANON 0x0002 /* Allocated from anonymous virtual memory. */
+# define MAP_TYPE 0x000f /* Mask for type field. */
+# ifdef __USE_MISC
+# define MAP_ANONYMOUS MAP_ANON /* Linux name. */
+# endif
+#endif
+
+/* Sharing types (must choose one and only one of these). */
+#ifdef __USE_BSD
+# define MAP_COPY 0x0020 /* Virtual copy of region at mapping time. */
+#endif
+#define MAP_SHARED 0x0010 /* Share changes. */
+#define MAP_PRIVATE 0x0000 /* Changes private; copy pages on write. */
+
+/* Other flags. */
+#define MAP_FIXED 0x0100 /* Map address must be exactly as requested. */
+#ifdef __USE_BSD
+# define MAP_NOEXTEND 0x0200 /* For MAP_FILE, don't change file size. */
+# define MAP_HASSEMPHORE 0x0400 /* Region may contain semaphores. */
+# define MAP_INHERIT 0x0800 /* Region is retained after exec. */
+#endif
+
+/* Flags for `mremap'. */
+#ifdef __USE_GNU
+# define MREMAP_MAYMOVE 1
+#endif
+
+/* Advice to `madvise'. */
+#ifdef __USE_BSD
+# define MADV_NORMAL 0 /* No further special treatment. */
+# define MADV_RANDOM 1 /* Expect random page references. */
+# define MADV_SEQUENTIAL 2 /* Expect sequential page references. */
+# define MADV_WILLNEED 3 /* Will need these pages. */
+# define MADV_DONTNEED 4 /* Don't need these pages. */
+#endif
+
+/* The POSIX people had to invent similar names for the same things. */
+#ifdef __USE_XOPEN2K
+# define POSIX_MADV_NORMAL 0 /* No further special treatment. */
+# define POSIX_MADV_RANDOM 1 /* Expect random page references. */
+# define POSIX_MADV_SEQUENTIAL 2 /* Expect sequential page references. */
+# define POSIX_MADV_WILLNEED 3 /* Will need these pages. */
+# define POSIX_MADV_DONTNEED 4 /* Don't need these pages. */
+#endif
+
+/* Flags to `msync'. */
+#define MS_ASYNC 1 /* Sync memory asynchronously. */
+#define MS_SYNC 0 /* Synchronous memory sync. */
+#define MS_INVALIDATE 2 /* Invalidate the caches. */
+
+/* Flags for `mlockall' (can be OR'd together). */
+#define MCL_CURRENT 1 /* Lock all currently mapped pages. */
+#define MCL_FUTURE 2 /* Lock all additions to address
+ space. */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/posix_opt.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/posix_opt.h
new file mode 100644
index 0000000..326bebf
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/posix_opt.h
@@ -0,0 +1,79 @@
+/* Define POSIX options for GNU/Hurd.
+ Copyright (C) 1998,2000,2001,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _UNISTD_H
+#error "Never include this file directly; use <unistd.h> instead."
+#endif
+
+#ifndef _BITS_POSIX_OPT_H
+#define _BITS_POSIX_OPT_H 1
+
+
+/* Job control is supported. */
+#define _POSIX_JOB_CONTROL 1
+
+/* Processes have a saved set-user-ID and a saved set-group-ID. */
+#define _POSIX_SAVED_IDS 1
+
+#if 0 /* XXX implement aio_* */
+/* Asynchronous I/O is supported. */
+#define _POSIX_ASYNCHRONOUS_IO 1
+/* Alternative name for Unix98. */
+#define _LFS_ASYNCHRONOUS_IO _POSIX_ASYNCHRONOUS_IO
+#endif
+
+/* Synchronizing file data is supported, but msync is missing. */
+#undef _POSIX_SYNCHRONIZED_IO
+
+/* The fsync function is present. */
+#define _POSIX_FSYNC 200112L
+
+/* Mapping of files to memory is supported. */
+#define _POSIX_MAPPED_FILES 200112L
+
+/* Locking of ranges of memory is supported. */
+#define _POSIX_MEMLOCK_RANGE 200112L
+
+/* Setting of memory protections is supported. */
+#define _POSIX_MEMORY_PROTECTION 200112L
+
+/* POSIX.4 shared memory objects are supported (using regular files). */
+#define _POSIX_SHARED_MEMORY_OBJECTS _POSIX_MAPPED_FILES
+
+/* Elements of the `c_cc' member of `struct termios' structure
+ can be disabled by using the value _POSIX_VDISABLE. */
+#define _POSIX_VDISABLE ((unsigned char) -1)
+
+
+/* Different Hurd filesystems might do these differently.
+ You must query the particular file with `pathconf' or `fpathconf'. */
+#undef _POSIX_CHOWN_RESTRICTED /* Only root can change owner of file? */
+#undef _POSIX_NO_TRUNC /* Overlong file names get error? */
+#undef _POSIX_SYNC_IO /* File supports O_SYNC et al? */
+
+/* GNU libc provides regular expression handling. */
+#define _POSIX_REGEXP 1
+
+/* We have a POSIX shell. */
+#define _POSIX_SHELL 1
+
+/* The `spawn' function family is supported. */
+#define _POSIX_SPAWN 200112L
+
+#endif /* bits/posix_opt.h */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/stat.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/stat.h
new file mode 100644
index 0000000..172bc5e
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/stat.h
@@ -0,0 +1,193 @@
+/* Copyright (C) 1992, 93, 94, 96, 97, 99, 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; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _SYS_STAT_H
+# error "Never include <bits/stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#include <bits/types.h>
+
+/* NOTE: The size of this structure (32 ints) is known in
+ <hurd/hurd_types.defs>, since it is used in the `io_stat' RPC. MiG
+ does not cope at all well with the passed C structure not being of
+ the expected size. There are some filler words at the end to allow
+ for future expansion. To increase the size of the structure used
+ in the RPC and retain binary compatibility, we would need to assign
+ a new message number. */
+
+struct stat
+ {
+ int st_fstype; /* File system type. */
+ __fsid_t st_fsid; /* File system ID. */
+#define st_dev st_fsid
+
+#ifndef __USE_FILE_OFFSET64
+ __ino_t st_ino; /* File number. */
+#else
+ __ino64_t st_ino; /* File number. */
+#endif
+ unsigned int st_gen; /* To detect reuse of file numbers. */
+ __dev_t st_rdev; /* Device if special file. */
+ __mode_t st_mode; /* File mode. */
+ __nlink_t st_nlink; /* Number of links. */
+
+ __uid_t st_uid; /* Owner. */
+ __gid_t st_gid; /* Owning group. */
+
+#ifndef __USE_FILE_OFFSET64
+ __off_t st_size; /* Size in bytes. */
+#else
+ __off64_t st_size; /* Size in bytes. */
+#endif
+
+ __time_t st_atime; /* Access time, seconds */
+ unsigned long int st_atime_usec; /* and microseconds. */
+ __time_t st_mtime; /* Modification time, seconds */
+ unsigned long int st_mtime_usec; /* and microseconds. */
+ __time_t st_ctime; /* Status change time, seconds */
+ unsigned long int st_ctime_usec; /* and microseconds. */
+
+ __blksize_t st_blksize; /* Optimal size for I/O. */
+
+#ifndef __USE_FILE_OFFSET64
+ __blkcnt_t st_blocks; /* Number of 512-byte blocks allocated.
+ Not related to `st_blksize'. */
+#else
+ __blkcnt64_t st_blocks; /* Number of 512-byte blocks allocated.
+ Not related to `st_blksize'. */
+#endif
+
+ __uid_t st_author; /* File author. */
+
+ unsigned int st_flags; /* User-defined flags.
+ High 16 bits can be set only by root. */
+
+#ifndef __USE_FILE_OFFSET64
+# define _SPARE_SIZE ((sizeof (__fsid_t) == sizeof (int)) ? 12 : 11)
+#else
+# define _SPARE_SIZE ((sizeof (__fsid_t) == sizeof (int)) ? 9 : 8)
+#endif
+ int st_spare[_SPARE_SIZE]; /* Room for future expansion. */
+#undef _SPARE_SIZE
+ };
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+ {
+ int st_fstype; /* File system type. */
+ __fsid_t st_fsid; /* File system ID. */
+# define st_dev st_fsid
+
+ __ino64_t st_ino; /* File number. */
+ unsigned int st_gen; /* To detect reuse of file numbers. */
+ __dev_t st_rdev; /* Device if special file. */
+ __mode_t st_mode; /* File mode. */
+ __nlink_t st_nlink; /* Number of links. */
+
+ __uid_t st_uid; /* Owner. */
+ __gid_t st_gid; /* Owning group. */
+
+ __off64_t st_size; /* Size in bytes. */
+
+ __time_t st_atime; /* Access time, seconds */
+ unsigned long int st_atime_usec; /* and microseconds. */
+ __time_t st_mtime; /* Modification time, seconds */
+ unsigned long int st_mtime_usec; /* and microseconds. */
+ __time_t st_ctime; /* Status change time, seconds */
+ unsigned long int st_ctime_usec; /* and microseconds. */
+
+ __blksize_t st_blksize; /* Optimal size for I/O. */
+
+ __blkcnt64_t st_blocks; /* Number of 512-byte blocks allocated.
+ Not related to `st_blksize'. */
+
+ __uid_t st_author; /* File author. */
+
+ unsigned int st_flags; /* User-defined flags.
+ High 16 bits can be set only by root. */
+
+#define _SPARE_SIZE ((sizeof (__fsid_t) == sizeof (int)) ? 9 : 8)
+ int st_spare[_SPARE_SIZE]; /* Room for future expansion. */
+#undef _SPARE_SIZE
+ };
+#endif
+
+#define _STATBUF_ST_BLKSIZE /* Tell code we have this member. */
+
+/* Encoding of the file mode. */
+
+#define __S_IFMT 0170000 /* These bits determine file type. */
+
+/* File types. */
+#define __S_IFDIR 0040000 /* Directory. */
+#define __S_IFCHR 0020000 /* Character device. */
+#define __S_IFBLK 0060000 /* Block device. */
+#define __S_IFREG 0100000 /* Regular file. */
+#define __S_IFLNK 0120000 /* Symbolic link. */
+#define __S_IFSOCK 0140000 /* Socket. */
+#define __S_IFIFO 0010000 /* FIFO. */
+
+/* POSIX.1b objects. */
+#define __S_TYPEISMQ(buf) (0)
+#define __S_TYPEISSEM(buf) (0)
+#define __S_TYPEISSHM(buf) (0)
+
+/* Protection bits. */
+
+#define __S_ISUID 04000 /* Set user ID on execution. */
+#define __S_ISGID 02000 /* Set group ID on execution. */
+#define __S_ISVTX 01000 /* Save swapped text after use (sticky). */
+#define __S_IREAD 00400 /* Read by owner. */
+#define __S_IWRITE 00200 /* Write by owner. */
+#define __S_IEXEC 00100 /* Execute by owner. */
+
+
+#ifdef __USE_GNU
+/* If set, there is no benefit in caching the contents of this file. */
+#define S_INOCACHE 000000200000
+
+/* If the S_IUSEUNK bit is set, then the S_IUNKNOWN bits (see below)
+ control access for unknown users. If S_IUSEUNK is clear, then unknown
+ users are treated as "others" for purposes of access control. */
+#define S_IUSEUNK 000000400000
+/* Mask of protection bits for unknown users (no effective IDs at all). */
+#define S_IUNKNOWN 000007000000
+/* Shift S_IREAD, S_IWRITE, S_IEXEC left this many bits to produce the
+ protection bits for unknown users. */
+#define S_IUNKSHIFT 12
+
+/* Read only bits: */
+
+/* There is a passive translator set for this file */
+#define S_IPTRANS 000010000000
+/* There is an active translator running on this file */
+#define S_IATRANS 000020000000
+/* This is the root of a filesystem (or single node translator) */
+#define S_IROOT 000040000000
+/* All the bits relevant to translators */
+#define S_ITRANS 000070000000
+
+/* ALL the unused bits. */
+#define S_ISPARE (~(S_IFMT|S_ITRANS|S_INOCACHE| \
+ S_IUSEUNK|S_IUNKNOWN|07777))
+#endif
+
+/* Default file creation mask (umask). */
+#ifdef __USE_BSD
+#define CMASK 0022
+#endif
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/bits/typesizes.h b/libc/hurd-l4/sysdeps/l4/hurd/bits/typesizes.h
new file mode 100644
index 0000000..4322617
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/bits/typesizes.h
@@ -0,0 +1,66 @@
+/* bits/typesizes.h -- underlying types for *_t. Hurd 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. */
+
+#ifndef _BITS_TYPES_H
+# error "Never include <bits/typesizes.h> directly; use <sys/types.h> instead."
+#endif
+
+#ifndef _BITS_TYPESIZES_H
+#define _BITS_TYPESIZES_H 1
+
+/* See <bits/types.h> for the meaning of these macros. This file exists so
+ that <bits/types.h> need not vary across different GNU platforms. */
+
+#define __DEV_T_TYPE __U32_TYPE
+#define __UID_T_TYPE __U32_TYPE
+#define __GID_T_TYPE __U32_TYPE
+#define __INO_T_TYPE __ULONGWORD_TYPE
+#define __INO64_T_TYPE __UQUAD_TYPE
+#define __MODE_T_TYPE __U32_TYPE
+#define __NLINK_T_TYPE __UWORD_TYPE
+#define __OFF_T_TYPE __SLONGWORD_TYPE
+#define __OFF64_T_TYPE __SQUAD_TYPE
+#define __PID_T_TYPE __S32_TYPE
+#define __RLIM_T_TYPE __ULONGWORD_TYPE
+#define __RLIM64_T_TYPE __UQUAD_TYPE
+#define __BLKCNT_T_TYPE __SLONGWORD_TYPE
+#define __BLKCNT64_T_TYPE __SQUAD_TYPE
+#define __FSBLKCNT_T_TYPE __ULONGWORD_TYPE
+#define __FSBLKCNT64_T_TYPE __UQUAD_TYPE
+#define __FSFILCNT_T_TYPE __ULONGWORD_TYPE
+#define __FSFILCNT64_T_TYPE __UQUAD_TYPE
+#define __ID_T_TYPE __U32_TYPE
+#define __CLOCK_T_TYPE __SLONGWORD_TYPE
+#define __TIME_T_TYPE __SLONGWORD_TYPE
+#define __USECONDS_T_TYPE __U32_TYPE
+#define __SUSECONDS_T_TYPE __SLONGWORD_TYPE
+#define __DADDR_T_TYPE __S32_TYPE
+#define __SWBLK_T_TYPE __SLONGWORD_TYPE
+#define __KEY_T_TYPE __S32_TYPE
+#define __CLOCKID_T_TYPE __S32_TYPE
+#define __TIMER_T_TYPE __S32_TYPE
+#define __BLKSIZE_T_TYPE __SLONGWORD_TYPE
+#define __FSID_T_TYPE __UQUAD_TYPE
+#define __SSIZE_T_TYPE __SWORD_TYPE
+
+/* Number of descriptors that can fit in an `fd_set'. */
+#define __FD_SETSIZE 256
+
+
+#endif /* bits/typesizes.h */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/closedir.c b/libc/hurd-l4/sysdeps/l4/hurd/closedir.c
new file mode 100644
index 0000000..4410f02
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/closedir.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <dirent.h>
+
+
+/* Close the directory stream DIRP.
+ Return 0 if successful, -1 if not. */
+int
+__closedir (DIR *dirp)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+weak_alias (__closedir, closedir)
+
+stub_warning (closedir)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/dirfd.c b/libc/hurd-l4/sysdeps/l4/hurd/dirfd.c
new file mode 100644
index 0000000..06c0cde
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/dirfd.c
@@ -0,0 +1,33 @@
+/* Return the file descriptor used by a DIR stream. Stub version.
+ Copyright (C) 1995, 1996 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 <dirent.h>
+#include <dirstream.h>
+#include <errno.h>
+
+int
+dirfd (dirp)
+ DIR *dirp;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (dirfd)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/dirstream.h b/libc/hurd-l4/sysdeps/l4/hurd/dirstream.h
new file mode 100644
index 0000000..d3ff379
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/dirstream.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 1993,94,95,96,97,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _DIRSTREAM_H
+
+#define _DIRSTREAM_H 1
+
+#include <sys/types.h>
+
+#include <bits/libc-lock.h>
+
+/* Directory stream type.
+
+ The Hurd directory format is the same as `struct dirent', so `readdir'
+ returns a pointer into the buffer we read directory data into. */
+
+struct __dirstream
+ {
+ void *__fd; /* `struct hurd_fd' pointer for descriptor. */
+ char *__data; /* Directory block. */
+ int __entry_data; /* Entry number `__data' corresponds to. */
+ char *__ptr; /* Current pointer into the block. */
+ int __entry_ptr; /* Entry number `__ptr' corresponds to. */
+ size_t __allocation; /* Space allocated for the block. */
+ size_t __size; /* Total valid data in the block. */
+ __libc_lock_define (, __lock) /* Mutex lock for this structure. */
+ };
+
+#endif /* dirstream.h */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/execve.c b/libc/hurd-l4/sysdeps/l4/hurd/execve.c
new file mode 100644
index 0000000..2d75629
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/execve.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Replace the current process, executing PATH with arguments ARGV and
+ environment ENVP. ARGV and ENVP are terminated by NULL pointers. */
+int
+__execve (path, argv, envp)
+ const char *path;
+ char *const argv[];
+ char *const envp[];
+{
+ if (path == NULL || argv == NULL || envp == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (execve)
+
+weak_alias (__execve, execve)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/exit-thread.c b/libc/hurd-l4/sysdeps/l4/hurd/exit-thread.c
new file mode 100644
index 0000000..950fb8e
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/exit-thread.c
@@ -0,0 +1,12 @@
+#include <unistd.h>
+
+/* Special exit function which only terminates the current thread. */
+void
+__exit_thread (int val)
+{
+ /* FIXME: Terminate ourselves. */
+ while (1);
+}
+
+stub_warning (__exit_thread)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fork.c b/libc/hurd-l4/sysdeps/l4/hurd/fork.c
new file mode 100644
index 0000000..c19fa65
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fork.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Clone the calling process, creating an exact copy.
+ Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+int
+__fork ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+libc_hidden_def (__fork)
+stub_warning (fork)
+
+weak_alias (__fork, fork)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fstatfs.c b/libc/hurd-l4/sysdeps/l4/hurd/fstatfs.c
new file mode 100644
index 0000000..4a1a996
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fstatfs.c
@@ -0,0 +1,34 @@
+/* Return information about the filesystem on which FD resides.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/statfs.h>
+#include <stddef.h>
+
+/* Return information about the filesystem on which FD resides. */
+int
+__fstatfs (int fd, struct statfs *buf)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (fstatfs)
+
+weak_alias (__fstatfs, fstatfs)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fstatfs64.c b/libc/hurd-l4/sysdeps/l4/hurd/fstatfs64.c
new file mode 100644
index 0000000..249b97e
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fstatfs64.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 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; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/statfs.h>
+
+/* Return information about the filesystem on which FD resides. */
+int
+__fstatfs64 (int fd, struct statfs64 *buf)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+weak_alias (__fstatfs64, fstatfs64)
+
+stub_warning (fstatfs64)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fstatvfs.c b/libc/hurd-l4/sysdeps/l4/hurd/fstatvfs.c
new file mode 100644
index 0000000..c5f75a7
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fstatvfs.c
@@ -0,0 +1,33 @@
+/* Return information about the filesystem on which FD resides.
+ Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/statvfs.h>
+
+/* Return information about the filesystem on which FD resides. */
+int
+__fstatvfs (int fd, struct statvfs *buf)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (fstatvfs)
+weak_alias (__fstatvfs, fstatvfs)
+libc_hidden_weak (fstatvfs)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fstatvfs64.c b/libc/hurd-l4/sysdeps/l4/hurd/fstatvfs64.c
new file mode 100644
index 0000000..47d4e26
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fstatvfs64.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1998, 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; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/statvfs.h>
+
+/* Return information about the filesystem on which FD resides. */
+int
+__fstatvfs64 (int fd, struct statvfs64 *buf)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+weak_alias (__fstatvfs64, fstatvfs64)
+
+stub_warning (fstatvfs64)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fxstat.c b/libc/hurd-l4/sysdeps/l4/hurd/fxstat.c
new file mode 100644
index 0000000..b750dac
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fxstat.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+/* Get information about the file descriptor FD in BUF. */
+int
+__fxstat (int vers, int fd, struct stat *buf)
+{
+ if (vers != _STAT_VER)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+ else if (buf == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (fstat)
+hidden_def (__fxstat)
+weak_alias (__fxstat, _fxstat)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/fxstat64.c b/libc/hurd-l4/sysdeps/l4/hurd/fxstat64.c
new file mode 100644
index 0000000..865ba49
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/fxstat64.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+/* Get information about the file descriptor FD in BUF. */
+int
+__fxstat64 (int vers, int fd, struct stat64 *buf)
+{
+ if (vers != _STAT_VER)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ if (fd < 0)
+ {
+ __set_errno (EBADF);
+ return -1;
+ }
+ else if (buf == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+hidden_def (__fxstat64)
+stub_warning (fstat64)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/getdtsz.c b/libc/hurd-l4/sysdeps/l4/hurd/getdtsz.c
new file mode 100644
index 0000000..38b7577
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/getdtsz.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Return the maximum number of file descriptors
+ the current process could possibly have. */
+int
+__getdtablesize ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getdtablesize)
+
+weak_alias (__getdtablesize, getdtablesize)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/getegid.c b/libc/hurd-l4/sysdeps/l4/hurd/getegid.c
new file mode 100644
index 0000000..d939d6a
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/getegid.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Get the effective group ID of the calling process. */
+__gid_t
+__getegid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getegid)
+
+weak_alias (__getegid, getegid)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/geteuid.c b/libc/hurd-l4/sysdeps/l4/hurd/geteuid.c
new file mode 100644
index 0000000..c67dbfd
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/geteuid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Get the effective user ID of the calling process. */
+__uid_t
+__geteuid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (geteuid)
+
+weak_alias (__geteuid, geteuid)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/getpagesize.c b/libc/hurd-l4/sysdeps/l4/hurd/getpagesize.c
new file mode 100644
index 0000000..40ed1ee
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/getpagesize.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1993, 1995, 1996, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+/* Return the system page size. */
+int
+__getpagesize ()
+{
+ __set_errno (ENOSYS);
+ return 0;
+}
+libc_hidden_def (__getpagesize)
+stub_warning (getpagesize)
+
+weak_alias (__getpagesize, getpagesize)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/getppid.c b/libc/hurd-l4/sysdeps/l4/hurd/getppid.c
new file mode 100644
index 0000000..e00c237
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/getppid.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+
+
+/* Get the parent process ID of the calling process. */
+int
+__getppid ()
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+stub_warning (getppid)
+
+weak_alias (__getppid, getppid)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/init-first.c b/libc/hurd-l4/sysdeps/l4/hurd/init-first.c
new file mode 100644
index 0000000..f002712
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/init-first.c
@@ -0,0 +1,124 @@
+/* Initialization code run first thing by the ELF startup code. Linux version.
+ Copyright (C) 1995-1999,2000,01,02,03,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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sysdep.h>
+#include <fpu_control.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <libc-internal.h>
+
+#include <ldsodefs.h>
+
+/* The function is called from assembly stubs the compiler can't see. */
+static void init (int, char **, char **) __attribute__ ((used));
+
+/* Set nonzero if we have to be prepared for more then one libc being
+ used in the process. Safe assumption if initializer never runs. */
+int __libc_multiple_libcs attribute_hidden = 1;
+
+/* Remember the command line argument and enviroment contents for
+ later calls of initializers for dynamic libraries. */
+int __libc_argc attribute_hidden;
+char **__libc_argv attribute_hidden;
+
+
+static void
+init (int argc, char **argv, char **envp)
+{
+#ifdef USE_NONOPTION_FLAGS
+ extern void __getopt_clean_environment (char **);
+#endif
+
+ __libc_multiple_libcs = &_dl_starting_up && !_dl_starting_up;
+
+ /* Make sure we don't initialize twice. */
+ if (!__libc_multiple_libcs)
+ {
+ /* Set the FPU control word to the proper default value if the
+ kernel would use a different value. (In a static program we
+ don't have this information.) */
+#ifdef SHARED
+ if (__fpu_control != GLRO(dl_fpu_control))
+#endif
+ __setfpucw (__fpu_control);
+ }
+
+ /* Save the command-line arguments. */
+ __libc_argc = argc;
+ __libc_argv = argv;
+ __environ = envp;
+
+#ifndef SHARED
+ __libc_init_secure ();
+
+ /* First the initialization which normally would be done by the
+ dynamic linker. */
+ _dl_non_dynamic_init ();
+#endif
+
+ __init_misc (argc, argv, envp);
+
+#ifdef USE_NONOPTION_FLAGS
+ /* This is a hack to make the special getopt in GNU libc working. */
+ __getopt_clean_environment (envp);
+#endif
+
+#ifdef SHARED
+ __libc_global_ctors ();
+#endif
+}
+
+#ifdef SHARED
+
+strong_alias (init, _init);
+
+extern void __libc_init_first (void);
+
+void
+__libc_init_first (void)
+{
+}
+
+#else
+extern void __libc_init_first (int argc, char **argv, char **envp);
+
+void
+__libc_init_first (int argc, char **argv, char **envp)
+{
+ init (argc, argv, envp);
+}
+#endif
+
+
+/* This function is defined here so that if this file ever gets into
+ ld.so we will get a link error. Having this file silently included
+ in ld.so causes disaster, because the _init definition above will
+ cause ld.so to gain an init function, which is not a cool thing. */
+
+extern void _dl_start (void) __attribute__ ((noreturn));
+
+void
+_dl_start (void)
+{
+ abort ();
+}
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/lxstat.c b/libc/hurd-l4/sysdeps/l4/hurd/lxstat.c
new file mode 100644
index 0000000..23d4442
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/lxstat.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 1991,1992,1995,1996,1997,2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sys/stat.h>
+
+int
+__lxstat (int version, const char *file, struct stat *buf)
+{
+ return __xstat (version, file, buf);
+}
+hidden_def (__lxstat)
+weak_alias (__lxstat, _lxstat)
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/lxstat64.c b/libc/hurd-l4/sysdeps/l4/hurd/lxstat64.c
new file mode 100644
index 0000000..596ecd2
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/lxstat64.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+
+/* Get file information about FILE in BUF.
+ If FILE is a symbolic link, do not follow it. */
+int
+__lxstat64 (int vers, const char *file, struct stat64 *buf)
+{
+ if (vers != _STAT_VER || file == NULL || buf == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+hidden_def (__lxstat64)
+stub_warning (__lxstat64)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/mremap.c b/libc/hurd-l4/sysdeps/l4/hurd/mremap.c
new file mode 100644
index 0000000..3cc31cc
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/mremap.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+/* Remap pages mapped by the range [ADDR,ADDR+OLD_LEN) to new length
+ NEW_LEN. If MAY_MOVE is MREMAP_MAYMOVE the returned address may
+ differ from ADDR. */
+void *__mremap (void *__addr, size_t __old_len, size_t __new_len,
+ int __may_move)
+{
+ __set_errno (ENOSYS);
+ return NULL;
+}
+libc_hidden_def (__mremap)
+stub_warning (mremap)
+
+weak_alias (__mremap, mremap)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/opendir.c b/libc/hurd-l4/sysdeps/l4/hurd/opendir.c
new file mode 100644
index 0000000..771013f
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/opendir.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <dirent.h>
+
+
+/* Open a directory stream on NAME. */
+DIR *
+__opendir (const char *name)
+{
+ __set_errno (ENOSYS);
+ return NULL;
+}
+weak_alias (__opendir, opendir)
+
+stub_warning (opendir)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/readdir.c b/libc/hurd-l4/sysdeps/l4/hurd/readdir.c
new file mode 100644
index 0000000..893b246
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/readdir.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <dirent.h>
+
+/* Read a directory entry from DIRP. */
+struct dirent *
+__readdir (DIR *dirp)
+{
+ __set_errno (ENOSYS);
+ return NULL;
+}
+weak_alias (__readdir, readdir)
+
+stub_warning (readdir)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/readdir_r.c b/libc/hurd-l4/sysdeps/l4/hurd/readdir_r.c
new file mode 100644
index 0000000..ad45dfa
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/readdir_r.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <dirent.h>
+
+/* Read a directory entry from DIRP, store result in ENTRY and return
+ pointer to result in *RESULT. */
+int
+__readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result)
+{
+ __set_errno (ENOSYS);
+ *result = NULL;
+ return ENOSYS;
+}
+weak_alias (__readdir_r, readdir_r)
+
+stub_warning (readdir_r)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/rewinddir.c b/libc/hurd-l4/sysdeps/l4/hurd/rewinddir.c
new file mode 100644
index 0000000..e78d316
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/rewinddir.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <stddef.h>
+#include <dirent.h>
+
+
+/* Rewind DIRP to the beginning of the directory. */
+void
+rewinddir (dirp)
+ DIR *dirp;
+{
+ __set_errno (ENOSYS);
+ /* No way to indicate failure. */
+}
+
+
+stub_warning (rewinddir)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/sys/param.h b/libc/hurd-l4/sysdeps/l4/hurd/sys/param.h
new file mode 100644
index 0000000..ec1ad3c
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/sys/param.h
@@ -0,0 +1,131 @@
+/* Copyright (C) 1993, 1994, 1995, 1997, 1999 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 deprecated and is provided only for compatibility with
+ Unix systems. It is unwise to include this file on programs which
+ are intended only for GNU systems.
+
+ Parts from:
+
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)param.h 7.23 (Berkeley) 5/6/91
+ */
+
+
+#ifndef _SYS_PARAM_H
+
+#define _SYS_PARAM_H 1
+#include <features.h>
+
+#define __need_NULL
+#include <stddef.h>
+
+#include <sys/types.h>
+#include <signal.h>
+#include <endian.h>
+#include <limits.h>
+#ifdef notyet
+# include <ufs/param.h>
+#endif
+
+
+/* What versions of BSD we are compatible with. */
+#define BSD 199306 /* System version (year & month). */
+#define BSD4_3 1
+#define BSD4_4 1
+
+#define GNU 1994100 /* GNU version (year, month, and release). */
+
+
+/* BSD names for some <limits.h> values. We do not define the BSD names
+ for the values which are not statically limited, such as NOFILE. */
+
+#define NBBY CHAR_BIT
+#define NGROUPS NGROUPS_MAX
+#define MAXSYMLINKS SYMLOOP_MAX
+#define CANBSIZ MAX_CANON /* XXX ? */
+
+/* ARG_MAX is unlimited, but we define NCARGS for BSD programs that want to
+ compare against some fixed limit. */
+#define NCARGS INT_MAX
+
+/* There is nothing quite equivalent in GNU to Unix "mounts", but there is
+ no limit on the number of simultaneously attached filesystems. */
+#define NMOUNT INT_MAX
+
+
+/* Magical constants. */
+#define NOGROUP 65535 /* Marker for empty group set member. */
+#define NODEV ((dev_t) -1) /* Non-existent device. */
+
+
+/* Bit map related macros. */
+#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
+#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+
+/* Macros for counting and rounding. */
+#ifndef howmany
+# define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#define powerof2(x) ((((x)-1)&(x))==0)
+
+/* Macros for min/max. */
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+
+/* Scale factor for scaled integers used to count %cpu time and load avgs.
+
+ The number of CPU `tick's that map to a unique `%age' can be expressed
+ by the formula (1 / (2 ^ (FSHIFT - 11))). The maximum load average that
+ can be calculated (assuming 32 bits) can be closely approximated using
+ the formula (2 ^ (2 * (16 - FSHIFT))) for (FSHIFT < 15). */
+
+#define FSHIFT 11 /* Bits to right of fixed binary point. */
+#define FSCALE (1<<FSHIFT)
+
+#endif /* sys/param.h */
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/syscall.c b/libc/hurd-l4/sysdeps/l4/hurd/syscall.c
new file mode 100644
index 0000000..ad78a06
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/syscall.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* Do system call CALLNO, passing it the remaining arguments.
+ This only makes sense in certain operating systems. */
+
+long int
+syscall (callno)
+ long int callno;
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+
+stub_warning (syscall)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/telldir.c b/libc/hurd-l4/sysdeps/l4/hurd/telldir.c
new file mode 100644
index 0000000..7b14452
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/telldir.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <dirent.h>
+
+/* Return the current position of DIRP. */
+long int
+telldir (dirp)
+ DIR *dirp;
+{
+ if (dirp == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1l;
+ }
+
+ __set_errno (ENOSYS);
+ return -1l;
+}
+
+
+stub_warning (telldir)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/uname.c b/libc/hurd-l4/sysdeps/l4/hurd/uname.c
new file mode 100644
index 0000000..2e46f6b
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/uname.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1992,93,94,96,97,2000,02 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 <unistd.h>
+#include <sys/utsname.h>
+#include <errno.h>
+
+int
+__uname (struct utsname *uname)
+{
+ __set_errno (ENOSYS);
+ return -1;
+}
+weak_alias (__uname, uname)
+libc_hidden_def (__uname)
+libc_hidden_def (uname)
+
+stub_warning (uname)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/xstat.c b/libc/hurd-l4/sysdeps/l4/hurd/xstat.c
new file mode 100644
index 0000000..e7328cc
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/xstat.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+/* Get file information about FILE in BUF. */
+int
+__xstat (int vers, const char *file, struct stat *buf)
+{
+ if (vers != _STAT_VER || file == NULL || buf == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+hidden_def (__xstat)
+stub_warning (stat)
+weak_alias (__xstat, _xstat)
+#include <stub-tag.h>
diff --git a/libc/hurd-l4/sysdeps/l4/hurd/xstat64.c b/libc/hurd-l4/sysdeps/l4/hurd/xstat64.c
new file mode 100644
index 0000000..2fb94cf
--- /dev/null
+++ b/libc/hurd-l4/sysdeps/l4/hurd/xstat64.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 1991, 1995, 1996, 1997, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+/* Get file information about FILE in BUF. */
+int
+__xstat64 (int vers, const char *file, struct stat64 *buf)
+{
+ if (vers != _STAT_VER || file == NULL || buf == NULL)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ __set_errno (ENOSYS);
+ return -1;
+}
+hidden_def (__xstat64)
+stub_warning (stat64)
+#include <stub-tag.h>
diff --git a/libc/patches/00-configure-touch.patch b/libc/patches/00-configure-touch.patch
new file mode 100755
index 0000000..ff4679a
--- /dev/null
+++ b/libc/patches/00-configure-touch.patch
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# We need to touch some generated files so they are not regenerated
+# accidentially.
+
+touch sysdeps/i386/configure
+touch sysdeps/i386/elf/configure
+touch nptl/sysdeps/pthread/configure
+
+exit $?
diff --git a/libc/patches/01-configure.in-base-os.patch b/libc/patches/01-configure.in-base-os.patch
new file mode 100755
index 0000000..e39d935
--- /dev/null
+++ b/libc/patches/01-configure.in-base-os.patch
@@ -0,0 +1,38 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+This patch is needed because the GNU system ID string does not differ
+between Mach or L4.
+
+The second part of the patch applies to configure script (but instead
+configure should be regenerated).
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * configure.in (base_os): Set to l4/hurd for GNU.
+
+--- libc/configure.in 2004-11-03 21:57:29.000000000 +0100
++++ libc/configure.in 2004-10-27 15:50:54.000000000 +0200
+@@ -500,7 +500,7 @@
+
+ case "$os" in
+ gnu*)
+- base_os=mach/hurd ;;
++ base_os=l4/hurd ;;
+ netbsd* | 386bsd* | freebsd* | bsdi*)
+ base_os=unix/bsd/bsd4.4 ;;
+ osf* | sunos* | ultrix* | newsos* | dynix* | *bsd*)
+
+
+--- libc/configure 2004-10-27 15:50:54.000000000 +0200
++++ libc/configure 2004-11-19 02:05:52.000000000 +0100
+@@ -2002,7 +2002,7 @@ os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\
+
+ case "$os" in
+ gnu*)
+- base_os=mach/hurd ;;
++ base_os=l4/hurd ;;
+ netbsd* | 386bsd* | freebsd* | bsdi*)
+ base_os=unix/bsd/bsd4.4 ;;
+ osf* | sunos* | ultrix* | newsos* | dynix* | *bsd*)
diff --git a/libc/patches/02-configure.in-add-ons-generic.patch b/libc/patches/02-configure.in-add-ons-generic.patch
new file mode 100755
index 0000000..a2df40b
--- /dev/null
+++ b/libc/patches/02-configure.in-add-ons-generic.patch
@@ -0,0 +1,51 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+This patch adds the ${add-on}/sysdeps/generic directory for all
+configured add-ons.
+
+The second part of the patch applies to configure script (but instead
+configure should be regenerated).
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * configure.in (sysnames): Add sysdeps/generic in all
+ add-ons.
+
+--- libc/configure.in 2004-11-03 21:57:29.000000000 +0100
++++ libc/configure.in 2004-10-27 15:50:54.000000000 +0200
+@@ -593,6 +593,14 @@
+ done
+ done
+ done
++ if test -n "$d"; then
++ try="${d}sysdeps/generic"
++ test -n "$enable_debug_configure" &&
++ echo "$0 DEBUG: try $try" >&2
++ if test -d $srcdir/$try; then
++ sysnames="$sysnames $try"
++ fi
++ fi
+ done
+ IFS="$ac_save_ifs"
+
+
+
+--- libc/configure 2004-10-27 15:50:54.000000000 +0200
++++ libc/configure 2004-11-19 02:05:52.000000000 +0100
+@@ -2093,6 +2093,14 @@ for d in $add_ons_pfx ''; do
+ done
+ done
+ done
++ if test -n "$d"; then
++ try="${d}sysdeps/generic"
++ test -n "$enable_debug_configure" &&
++ echo "$0 DEBUG: try $try" >&2
++ if test -d $srcdir/$try; then
++ sysnames="$sysnames $try"
++ fi
++ fi
+ done
+ IFS="$ac_save_ifs"
+
diff --git a/libc/patches/03-sysdeps-generic-bits-socket-h.patch b/libc/patches/03-sysdeps-generic-bits-socket-h.patch
new file mode 100755
index 0000000..6442bcc
--- /dev/null
+++ b/libc/patches/03-sysdeps-generic-bits-socket-h.patch
@@ -0,0 +1,524 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+The generic socket.h doesn't suffice anymore because other parts of glibc
+depend on struct cmsghdr. This patch updates the generic file with the
+BSD 4.4 version.
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * sysdeps/unix/bsd/bsd4.4/bits/socket.h: Move to ...
+ * sysdeps/generic/bits/socket.h: ... here.
+
+--- libc/sysdeps/generic/bits/socket.h 2001-07-06 06:55:50.000000000 +0200
++++ libc/sysdeps/generic/bits/socket.h 2004-10-10 12:41:30.000000000 +0200
+@@ -1,11 +1,11 @@
+-/* System-specific socket constants and types. Generic/4.3 BSD version.
+- Copyright (C) 1991,92,1994-1999,2000,2001 Free Software Foundation, Inc.
++/* System-specific socket constants and types. 4.4 BSD version.
++ Copyright (C) 1991,92,1994-2002,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.
++ 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
+@@ -13,9 +13,9 @@
+ 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. */
++ License along with the GNU C Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA. */
+
+ #ifndef __BITS_SOCKET_H
+ #define __BITS_SOCKET_H 1
+@@ -24,12 +24,13 @@
+ # error "Never include <bits/socket.h> directly; use <sys/socket.h> instead."
+ #endif
+
+-#include <limits.h>
+-#include <bits/types.h>
+-
+ #define __need_size_t
++#define __need_NULL
+ #include <stddef.h>
+
++#include <limits.h> /* XXX Is this allowed? */
++#include <bits/types.h>
++
+ /* Type for length arguments in socket calls. */
+ #ifndef __socklen_t_defined
+ typedef __socklen_t socklen_t;
+@@ -121,6 +122,8 @@ enum __socket_type
+ #define AF_INET6 PF_INET6
+ #define AF_MAX PF_MAX
+
++/* Maximum queue length specifiable by listen. */
++#define SOMAXCONN 128 /* 5 on the origional 4.4 BSD. */
+
+ /* Get the definition of the macro to define the common sockaddr members. */
+ #include <bits/sockaddr.h>
+@@ -177,18 +180,105 @@ enum
+ `sendmsg' and received by `recvmsg'. */
+ struct msghdr
+ {
+- __ptr_t msg_name; /* Address to send to/receive from. */
++ void *msg_name; /* Address to send to/receive from. */
+ socklen_t msg_namelen; /* Length of address data. */
+
+ struct iovec *msg_iov; /* Vector of data to send/receive into. */
+ int msg_iovlen; /* Number of elements in the vector. */
+
+- __ptr_t msg_accrights; /* Access rights information. */
+- socklen_t msg_accrightslen; /* Length of access rights information. */
++ void *msg_control; /* Ancillary data (eg BSD filedesc passing). */
++ socklen_t msg_controllen; /* Ancillary data buffer length. */
+
+ int msg_flags; /* Flags in received message. */
+ };
+
++/* Structure used for storage of ancillary data object information. */
++struct cmsghdr
++ {
++ socklen_t cmsg_len; /* Length of data in cmsg_data plus length
++ of cmsghdr structure. */
++ int cmsg_level; /* Originating protocol. */
++ int cmsg_type; /* Protocol specific type. */
++#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
++ __extension__ unsigned char __cmsg_data __flexarr; /* Ancillary data. */
++#endif
++ };
++
++/* Ancillary data object manipulation macros. */
++#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
++# define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data)
++#else
++# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1))
++#endif
++
++#define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg)
++
++#define CMSG_FIRSTHDR(mhdr) \
++ ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) \
++ ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL)
++
++#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
++ & (size_t) ~(sizeof (size_t) - 1))
++#define CMSG_SPACE(len) (CMSG_ALIGN (len) \
++ + CMSG_ALIGN (sizeof (struct cmsghdr)))
++#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
++
++extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
++ struct cmsghdr *__cmsg) __THROW;
++#ifdef __USE_EXTERN_INLINES
++# ifndef _EXTERN_INLINE
++# define _EXTERN_INLINE extern __inline
++# endif
++_EXTERN_INLINE struct cmsghdr *
++__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
++{
++ if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
++ /* The kernel header does this so there may be a reason. */
++ return 0;
++
++ __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
++ + CMSG_ALIGN (__cmsg->cmsg_len));
++ if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
++ + __mhdr->msg_controllen)
++ || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
++ > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
++ /* No more entries. */
++ return 0;
++ return __cmsg;
++}
++#endif /* Use `extern inline'. */
++
++/* Socket level message types. */
++enum
++ {
++ SCM_RIGHTS = 0x01, /* Access rights (array of int). */
++#define SCM_RIGHTS SCM_RIGHTS
++ SCM_TIMESTAMP = 0x02, /* Timestamp (struct timeval). */
++#define SCM_TIMESTAMP SCM_TIMESTAMP
++ SCM_CREDS = 0x03 /* Process creds (struct cmsgcred). */
++#define SCM_CREDS SCM_CREDS
++ };
++
++/* Unfortunately, BSD practice dictates this structure be of fixed size.
++ If there are more than CMGROUP_MAX groups, the list is truncated.
++ (On GNU systems, the `cmcred_euid' field is just the first in the
++ list of effective UIDs.) */
++#define CMGROUP_MAX 16
++
++/* Structure delivered by SCM_CREDS. This describes the identity of the
++ sender of the data simultaneously received on the socket. By BSD
++ convention, this is included only when a sender on a AF_LOCAL socket
++ sends cmsg data of this type and size; the sender's structure is
++ ignored, and the system fills in the various IDs of the sender process. */
++struct cmsgcred
++ {
++ __pid_t cmcred_pid;
++ __uid_t cmcred_uid;
++ __uid_t cmcred_euid;
++ __gid_t cmcred_gid;
++ int cmcred_ngroups;
++ __gid_t cmcred_groups[CMGROUP_MAX];
++ };
+
+ /* Protocol number used to manipulate socket-level options
+ with `getsockopt' and `setsockopt'. */
+--- libc/sysdeps/unix/bsd/bsd4.4/bits/socket.h 2004-10-10 12:41:30.000000000 +0200
++++ libc/sysdeps/unix/bsd/bsd4.4/bits/socket.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,341 +0,0 @@
+-/* System-specific socket constants and types. 4.4 BSD version.
+- Copyright (C) 1991,92,1994-2002,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 __BITS_SOCKET_H
+-#define __BITS_SOCKET_H 1
+-
+-#if !defined _SYS_SOCKET_H && !defined _NETINET_IN_H
+-# error "Never include <bits/socket.h> directly; use <sys/socket.h> instead."
+-#endif
+-
+-#define __need_size_t
+-#define __need_NULL
+-#include <stddef.h>
+-
+-#include <limits.h> /* XXX Is this allowed? */
+-#include <bits/types.h>
+-
+-/* Type for length arguments in socket calls. */
+-#ifndef __socklen_t_defined
+-typedef __socklen_t socklen_t;
+-# define __socklen_t_defined
+-#endif
+-
+-
+-/* Types of sockets. */
+-enum __socket_type
+-{
+- SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
+- byte streams. */
+-#define SOCK_STREAM SOCK_STREAM
+- SOCK_DGRAM = 2, /* Connectionless, unreliable datagrams
+- of fixed maximum length. */
+-#define SOCK_DGRAM SOCK_DGRAM
+- SOCK_RAW = 3, /* Raw protocol interface. */
+-#define SOCK_RAW SOCK_RAW
+- SOCK_RDM = 4, /* Reliably-delivered messages. */
+-#define SOCK_RDM SOCK_RDM
+- SOCK_SEQPACKET = 5 /* Sequenced, reliable, connection-based,
+- datagrams of fixed maximum length. */
+-#define SOCK_SEQPACKET SOCK_SEQPACKET
+-};
+-
+-/* Protocol families. */
+-#define PF_UNSPEC 0 /* Unspecified. */
+-#define PF_LOCAL 1 /* Local to host (pipes and file-domain). */
+-#define PF_UNIX PF_LOCAL /* Old BSD name for PF_LOCAL. */
+-#define PF_FILE PF_LOCAL /* POSIX name for PF_LOCAL. */
+-#define PF_INET 2 /* IP protocol family. */
+-#define PF_IMPLINK 3 /* ARPAnet IMP protocol. */
+-#define PF_PUP 4 /* PUP protocols. */
+-#define PF_CHAOS 5 /* MIT Chaos protocols. */
+-#define PF_NS 6 /* Xerox NS protocols. */
+-#define PF_ISO 7 /* ISO protocols. */
+-#define PF_OSI PF_ISO
+-#define PF_ECMA 8 /* ECMA protocols. */
+-#define PF_DATAKIT 9 /* AT&T Datakit protocols. */
+-#define PF_CCITT 10 /* CCITT protocols (X.25 et al). */
+-#define PF_SNA 11 /* IBM SNA protocol. */
+-#define PF_DECnet 12 /* DECnet protocols. */
+-#define PF_DLI 13 /* Direct data link interface. */
+-#define PF_LAT 14 /* DEC Local Area Transport protocol. */
+-#define PF_HYLINK 15 /* NSC Hyperchannel protocol. */
+-#define PF_APPLETALK 16 /* Don't use this. */
+-#define PF_ROUTE 17 /* Internal Routing Protocol. */
+-#define PF_LINK 18 /* Link layer interface. */
+-#define PF_XTP 19 /* eXpress Transfer Protocol (no AF). */
+-#define PF_COIP 20 /* Connection-oriented IP, aka ST II. */
+-#define PF_CNT 21 /* Computer Network Technology. */
+-#define PF_RTIP 22 /* Help Identify RTIP packets. **/
+-#define PF_IPX 23 /* Novell Internet Protocol. */
+-#define PF_SIP 24 /* Simple Internet Protocol. */
+-#define PF_PIP 25 /* Help Identify PIP packets. */
+-#define PF_INET6 26 /* IP version 6. */
+-#define PF_MAX 27
+-
+-/* Address families. */
+-#define AF_UNSPEC PF_UNSPEC
+-#define AF_LOCAL PF_LOCAL
+-#define AF_UNIX PF_UNIX
+-#define AF_FILE PF_FILE
+-#define AF_INET PF_INET
+-#define AF_IMPLINK PF_IMPLINK
+-#define AF_PUP PF_PUP
+-#define AF_CHAOS PF_CHAOS
+-#define AF_NS PF_NS
+-#define AF_ISO PF_ISO
+-#define AF_OSI PF_OSI
+-#define AF_ECMA PF_ECMA
+-#define AF_DATAKIT PF_DATAKIT
+-#define AF_CCITT PF_CCITT
+-#define AF_SNA PF_SNA
+-#define AF_DECnet PF_DECnet
+-#define AF_DLI PF_DLI
+-#define AF_LAT PF_LAT
+-#define AF_HYLINK PF_HYLINK
+-#define AF_APPLETALK PF_APPLETALK
+-#define AF_ROUTE PF_ROUTE
+-#define AF_LINK PF_LINK
+-#define pseudo_AF_XTP PF_XTP
+-#define AF_COIP PF_COIP
+-#define AF_CNT PF_CNT
+-#define pseudo_AF_RTIP PF_RTIP
+-#define AF_IPX PF_IPX
+-#define AF_SIP PF_SIP
+-#define pseudo_AF_PIP PF_PIP
+-#define AF_INET6 PF_INET6
+-#define AF_MAX PF_MAX
+-
+-/* Maximum queue length specifiable by listen. */
+-#define SOMAXCONN 128 /* 5 on the origional 4.4 BSD. */
+-
+-/* Get the definition of the macro to define the common sockaddr members. */
+-#include <bits/sockaddr.h>
+-
+-/* Structure describing a generic socket address. */
+-struct sockaddr
+- {
+- __SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
+- char sa_data[14]; /* Address data. */
+- };
+-
+-
+-/* Structure large enough to hold any socket address (with the historical
+- exception of AF_UNIX). We reserve 128 bytes. */
+-#if ULONG_MAX > 0xffffffff
+-# define __ss_aligntype __uint64_t
+-#else
+-# define __ss_aligntype __uint32_t
+-#endif
+-#define _SS_SIZE 128
+-#define _SS_PADSIZE (_SS_SIZE - (2 * sizeof (__ss_aligntype)))
+-
+-struct sockaddr_storage
+- {
+- __SOCKADDR_COMMON (ss_); /* Address family, etc. */
+- __ss_aligntype __ss_align; /* Force desired alignment. */
+- char __ss_padding[_SS_PADSIZE];
+- };
+-
+-
+-/* Bits in the FLAGS argument to `send', `recv', et al. */
+-enum
+- {
+- MSG_OOB = 0x01, /* Process out-of-band data. */
+-#define MSG_OOB MSG_OOB
+- MSG_PEEK = 0x02, /* Peek at incoming messages. */
+-#define MSG_PEEK MSG_PEEK
+- MSG_DONTROUTE = 0x04, /* Don't use local routing. */
+-#define MSG_DONTROUTE MSG_DONTROUTE
+- MSG_EOR = 0x08, /* Data completes record. */
+-#define MSG_EOR MSG_EOR
+- MSG_TRUNC = 0x10, /* Data discarded before delivery. */
+-#define MSG_TRUNC MSG_TRUNC
+- MSG_CTRUNC = 0x20, /* Control data lost before delivery. */
+-#define MSG_CTRUNC MSG_CTRUNC
+- MSG_WAITALL = 0x40, /* Wait for full request or error. */
+-#define MSG_WAITALL MSG_WAITALL
+- MSG_DONTWAIT = 0x80 /* This message should be nonblocking. */
+-#define MSG_DONTWAIT MSG_DONTWAIT
+- };
+-
+-
+-/* Structure describing messages sent by
+- `sendmsg' and received by `recvmsg'. */
+-struct msghdr
+- {
+- void *msg_name; /* Address to send to/receive from. */
+- socklen_t msg_namelen; /* Length of address data. */
+-
+- struct iovec *msg_iov; /* Vector of data to send/receive into. */
+- int msg_iovlen; /* Number of elements in the vector. */
+-
+- void *msg_control; /* Ancillary data (eg BSD filedesc passing). */
+- socklen_t msg_controllen; /* Ancillary data buffer length. */
+-
+- int msg_flags; /* Flags in received message. */
+- };
+-
+-/* Structure used for storage of ancillary data object information. */
+-struct cmsghdr
+- {
+- socklen_t cmsg_len; /* Length of data in cmsg_data plus length
+- of cmsghdr structure. */
+- int cmsg_level; /* Originating protocol. */
+- int cmsg_type; /* Protocol specific type. */
+-#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
+- __extension__ unsigned char __cmsg_data __flexarr; /* Ancillary data. */
+-#endif
+- };
+-
+-/* Ancillary data object manipulation macros. */
+-#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
+-# define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data)
+-#else
+-# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1))
+-#endif
+-
+-#define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg)
+-
+-#define CMSG_FIRSTHDR(mhdr) \
+- ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) \
+- ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL)
+-
+-#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
+- & (size_t) ~(sizeof (size_t) - 1))
+-#define CMSG_SPACE(len) (CMSG_ALIGN (len) \
+- + CMSG_ALIGN (sizeof (struct cmsghdr)))
+-#define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+-
+-extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr,
+- struct cmsghdr *__cmsg) __THROW;
+-#ifdef __USE_EXTERN_INLINES
+-# ifndef _EXTERN_INLINE
+-# define _EXTERN_INLINE extern __inline
+-# endif
+-_EXTERN_INLINE struct cmsghdr *
+-__NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg))
+-{
+- if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr))
+- /* The kernel header does this so there may be a reason. */
+- return 0;
+-
+- __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg
+- + CMSG_ALIGN (__cmsg->cmsg_len));
+- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control
+- + __mhdr->msg_controllen)
+- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len)
+- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen)))
+- /* No more entries. */
+- return 0;
+- return __cmsg;
+-}
+-#endif /* Use `extern inline'. */
+-
+-/* Socket level message types. */
+-enum
+- {
+- SCM_RIGHTS = 0x01, /* Access rights (array of int). */
+-#define SCM_RIGHTS SCM_RIGHTS
+- SCM_TIMESTAMP = 0x02, /* Timestamp (struct timeval). */
+-#define SCM_TIMESTAMP SCM_TIMESTAMP
+- SCM_CREDS = 0x03 /* Process creds (struct cmsgcred). */
+-#define SCM_CREDS SCM_CREDS
+- };
+-
+-/* Unfortunately, BSD practice dictates this structure be of fixed size.
+- If there are more than CMGROUP_MAX groups, the list is truncated.
+- (On GNU systems, the `cmcred_euid' field is just the first in the
+- list of effective UIDs.) */
+-#define CMGROUP_MAX 16
+-
+-/* Structure delivered by SCM_CREDS. This describes the identity of the
+- sender of the data simultaneously received on the socket. By BSD
+- convention, this is included only when a sender on a AF_LOCAL socket
+- sends cmsg data of this type and size; the sender's structure is
+- ignored, and the system fills in the various IDs of the sender process. */
+-struct cmsgcred
+- {
+- __pid_t cmcred_pid;
+- __uid_t cmcred_uid;
+- __uid_t cmcred_euid;
+- __gid_t cmcred_gid;
+- int cmcred_ngroups;
+- __gid_t cmcred_groups[CMGROUP_MAX];
+- };
+-
+-/* Protocol number used to manipulate socket-level options
+- with `getsockopt' and `setsockopt'. */
+-#define SOL_SOCKET 0xffff
+-
+-/* Socket-level options for `getsockopt' and `setsockopt'. */
+-enum
+- {
+- SO_DEBUG = 0x0001, /* Record debugging information. */
+-#define SO_DEBUG SO_DEBUG
+- SO_ACCEPTCONN = 0x0002, /* Accept connections on socket. */
+-#define SO_ACCEPTCONN SO_ACCEPTCONN
+- SO_REUSEADDR = 0x0004, /* Allow reuse of local addresses. */
+-#define SO_REUSEADDR SO_REUSEADDR
+- SO_KEEPALIVE = 0x0008, /* Keep connections alive and send
+- SIGPIPE when they die. */
+-#define SO_KEEPALIVE SO_KEEPALIVE
+- SO_DONTROUTE = 0x0010, /* Don't do local routing. */
+-#define SO_DONTROUTE SO_DONTROUTE
+- SO_BROADCAST = 0x0020, /* Allow transmission of
+- broadcast messages. */
+-#define SO_BROADCAST SO_BROADCAST
+- SO_USELOOPBACK = 0x0040, /* Use the software loopback to avoid
+- hardware use when possible. */
+-#define SO_USELOOPBACK SO_USELOOPBACK
+- SO_LINGER = 0x0080, /* Block on close of a reliable
+- socket to transmit pending data. */
+-#define SO_LINGER SO_LINGER
+- SO_OOBINLINE = 0x0100, /* Receive out-of-band data in-band. */
+-#define SO_OOBINLINE SO_OOBINLINE
+- SO_REUSEPORT = 0x0200, /* Allow local address and port reuse. */
+-#define SO_REUSEPORT SO_REUSEPORT
+- SO_SNDBUF = 0x1001, /* Send buffer size. */
+-#define SO_SNDBUF SO_SNDBUF
+- SO_RCVBUF = 0x1002, /* Receive buffer. */
+-#define SO_RCVBUF SO_RCVBUF
+- SO_SNDLOWAT = 0x1003, /* Send low-water mark. */
+-#define SO_SNDLOWAT SO_SNDLOWAT
+- SO_RCVLOWAT = 0x1004, /* Receive low-water mark. */
+-#define SO_RCVLOWAT SO_RCVLOWAT
+- SO_SNDTIMEO = 0x1005, /* Send timeout. */
+-#define SO_SNDTIMEO SO_SNDTIMEO
+- SO_RCVTIMEO = 0x1006, /* Receive timeout. */
+-#define SO_RCVTIMEO SO_RCVTIMEO
+- SO_ERROR = 0x1007, /* Get and clear error status. */
+-#define SO_ERROR SO_ERROR
+- SO_STYLE = 0x1008, /* Get socket connection style. */
+-#define SO_STYLE SO_STYLE
+- SO_TYPE = SO_STYLE /* Compatible name for SO_STYLE. */
+-#define SO_TYPE SO_TYPE
+- };
+-
+-/* Structure used to manipulate the SO_LINGER option. */
+-struct linger
+- {
+- int l_onoff; /* Nonzero to linger on close. */
+- int l_linger; /* Time to linger. */
+- };
+-
+-#endif /* bits/socket.h */
diff --git a/libc/patches/04-sysdeps-generic-bits-sigcontext-h.patch b/libc/patches/04-sysdeps-generic-bits-sigcontext-h.patch
new file mode 100755
index 0000000..8b6726b
--- /dev/null
+++ b/libc/patches/04-sysdeps-generic-bits-sigcontext-h.patch
@@ -0,0 +1,23 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+This change makes sysdeps/generic/profil-counter.h compile on a
+generic target. Other parts of glibc depend on sc_pc nowadays.
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * sysdeps/generic/bits/sigcontext.h (struct sigcontext):
+ New member sc_pc.
+
+
+--- ../cvs/libc/sysdeps/generic/bits/sigcontext.h 2001-07-06 06:55:50.000000000 +0200
++++ libc/sysdeps/generic/bits/sigcontext.h 2004-11-19 03:51:05.000000000 +0100
+@@ -28,6 +28,7 @@ struct sigcontext
+ __sigset_t sc_mask;
+
+ /* Registers and such. */
++ void *sc_pc;
+ };
+
+ /* Signal subcodes should be defined here. */
diff --git a/libc/patches/05-sysdeps-generic-getpeername.patch b/libc/patches/05-sysdeps-generic-getpeername.patch
new file mode 100755
index 0000000..a252c33
--- /dev/null
+++ b/libc/patches/05-sysdeps-generic-getpeername.patch
@@ -0,0 +1,30 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * sysdeps/generic/getpeername.c (getpeername): Rename and make
+ it a weak alias to ...
+ (__getpeername): ... this.
+
+--- libc/sysdeps/generic/getpeername.c 2001-07-06 06:55:49.000000000 +0200
++++ libc/sysdeps/generic/getpeername.c 2004-11-22 06:24:30.000000000 +0100
+@@ -22,7 +22,7 @@
+ /* Put the address of the peer connected to socket FD into *ADDR
+ (which is *LEN bytes long), and its actual length into *LEN. */
+ int
+-getpeername (fd, addr, len)
++__getpeername (fd, addr, len)
+ int fd;
+ __SOCKADDR_ARG addr;
+ socklen_t *len;
+@@ -30,7 +30,7 @@ getpeername (fd, addr, len)
+ __set_errno (ENOSYS);
+ return -1;
+ }
+-
++weak_alias (__getpeername, getpeername)
+
+ stub_warning (getpeername)
+ #include <stub-tag.h>
diff --git a/libc/patches/06-sysdeps-generic-open.patch b/libc/patches/06-sysdeps-generic-open.patch
new file mode 100755
index 0000000..8452fd0
--- /dev/null
+++ b/libc/patches/06-sysdeps-generic-open.patch
@@ -0,0 +1,36 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * sysdeps/generic/open.c (__open): Rename to ...
+ (__libc_open): ... this.
+ (__open): Make it weak hidden alias to __libc_open.
+ (open): Make it a weak alias to __libc_open.
+
+--- libc/sysdeps/generic/open.c 2002-08-03 08:37:37.000000000 +0200
++++ libc/sysdeps/generic/open.c 2004-11-22 20:50:41.000000000 +0100
+@@ -24,7 +24,7 @@
+ /* Open FILE with access OFLAG. If OFLAG includes O_CREAT,
+ a third argument is the file protection. */
+ int
+-__open (file, oflag)
++__libc_open (file, oflag)
+ const char *file;
+ int oflag;
+ {
+@@ -47,8 +47,11 @@ __open (file, oflag)
+ __set_errno (ENOSYS);
+ return -1;
+ }
+-libc_hidden_def (__open)
++libc_hidden_def (__libc_open)
+ stub_warning (open)
+
+-weak_alias (__open, open)
++weak_alias (__libc_open, __open)
++libc_hidden_weak (__open)
++weak_alias (__libc_open, open)
++
+ #include <stub-tag.h>
diff --git a/libc/patches/07-sysdeps-generic-fcntl.patch b/libc/patches/07-sysdeps-generic-fcntl.patch
new file mode 100755
index 0000000..2f98297
--- /dev/null
+++ b/libc/patches/07-sysdeps-generic-fcntl.patch
@@ -0,0 +1,36 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+2004-11-19 Marcus Brinkmann <marcus@gnu.org>
+
+ * sysdeps/generic/fcntl.c (__fcntl): Rename to ...
+ (__libc_fcntl): ... this.
+ (__fcntl): Make it weak hidden alias to __libc_fcntl.
+ (fcntl): Make it a weak alias to __libc_fcntl.
+
+--- libc/sysdeps/generic/fcntl.c 2002-08-03 08:35:52.000000000 +0200
++++ libc/sysdeps/generic/fcntl.c 2004-11-22 21:08:42.000000000 +0100
+@@ -21,7 +21,7 @@
+
+ /* Perform file control operations on FD. */
+ int
+-__fcntl (fd, cmd)
++__libc_fcntl (fd, cmd)
+ int fd;
+ int cmd;
+ {
+@@ -34,8 +34,11 @@ __fcntl (fd, cmd)
+ __set_errno (ENOSYS);
+ return -1;
+ }
+-libc_hidden_def (__fcntl)
++libc_hidden_def (__libc_fcntl)
+ stub_warning (fcntl)
+
+-weak_alias (__fcntl, fcntl)
++weak_alias (__libc_fcntl, __fcntl)
++libc_hidden_weak (__fcntl)
++weak_alias (__libc_fcntl, fcntl)
++
+ #include <stub-tag.h>
diff --git a/libc/patches/50-nptl-hurd-l4.patch b/libc/patches/50-nptl-hurd-l4.patch
new file mode 100755
index 0000000..a71688e
--- /dev/null
+++ b/libc/patches/50-nptl-hurd-l4.patch
@@ -0,0 +1,11021 @@
+#! /bin/sh
+patch -p1 -f $* < $0
+exit $?
+
+This frobs nptl.
+
+diff -x CVS -rupN libc/nptl/allocatestack.c libc/nptl/allocatestack.c
+--- libc/nptl/allocatestack.c 2005-01-23 18:39:28.000000000 +0100
++++ libc/nptl/allocatestack.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,947 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 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 <assert.h>
+-#include <errno.h>
+-#include <signal.h>
+-#include <stdint.h>
+-#include <string.h>
+-#include <unistd.h>
+-#include <sys/mman.h>
+-#include <sys/param.h>
+-#include <dl-sysdep.h>
+-#include <tls.h>
+-#include <lowlevellock.h>
+-
+-
+-#ifndef NEED_SEPARATE_REGISTER_STACK
+-
+-/* Most architectures have exactly one stack pointer. Some have more. */
+-# define STACK_VARIABLES void *stackaddr
+-
+-/* How to pass the values to the 'create_thread' function. */
+-# define STACK_VARIABLES_ARGS stackaddr
+-
+-/* How to declare function which gets there parameters. */
+-# define STACK_VARIABLES_PARMS void *stackaddr
+-
+-/* How to declare allocate_stack. */
+-# define ALLOCATE_STACK_PARMS void **stack
+-
+-/* This is how the function is called. We do it this way to allow
+- other variants of the function to have more parameters. */
+-# define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
+-
+-#else
+-
+-/* We need two stacks. The kernel will place them but we have to tell
+- the kernel about the size of the reserved address space. */
+-# define STACK_VARIABLES void *stackaddr; size_t stacksize
+-
+-/* How to pass the values to the 'create_thread' function. */
+-# define STACK_VARIABLES_ARGS stackaddr, stacksize
+-
+-/* How to declare function which gets there parameters. */
+-# define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize
+-
+-/* How to declare allocate_stack. */
+-# define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize
+-
+-/* This is how the function is called. We do it this way to allow
+- other variants of the function to have more parameters. */
+-# define ALLOCATE_STACK(attr, pd) \
+- allocate_stack (attr, pd, &stackaddr, &stacksize)
+-
+-#endif
+-
+-
+-/* Default alignment of stack. */
+-#ifndef STACK_ALIGN
+-# define STACK_ALIGN __alignof__ (long double)
+-#endif
+-
+-/* Default value for minimal stack size after allocating thread
+- descriptor and guard. */
+-#ifndef MINIMAL_REST_STACK
+-# define MINIMAL_REST_STACK 4096
+-#endif
+-
+-
+-/* Let the architecture add some flags to the mmap() call used to
+- allocate stacks. */
+-#ifndef ARCH_MAP_FLAGS
+-# define ARCH_MAP_FLAGS 0
+-#endif
+-
+-/* This yields the pointer that TLS support code calls the thread pointer. */
+-#if TLS_TCB_AT_TP
+-# define TLS_TPADJ(pd) (pd)
+-#elif TLS_DTV_AT_TP
+-# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE))
+-#endif
+-
+-/* Cache handling for not-yet free stacks. */
+-
+-/* Maximum size in kB of cache. */
+-static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */
+-static size_t stack_cache_actsize;
+-
+-/* Mutex protecting this variable. */
+-static lll_lock_t stack_cache_lock = LLL_LOCK_INITIALIZER;
+-
+-/* List of queued stack frames. */
+-static LIST_HEAD (stack_cache);
+-
+-/* List of the stacks in use. */
+-static LIST_HEAD (stack_used);
+-
+-/* List of the threads with user provided stacks in use. No need to
+- initialize this, since it's done in __pthread_initialize_minimal. */
+-list_t __stack_user __attribute__ ((nocommon));
+-hidden_data_def (__stack_user)
+-
+-#if COLORING_INCREMENT != 0
+-/* Number of threads created. */
+-static unsigned int nptl_ncreated;
+-#endif
+-
+-
+-/* Check whether the stack is still used or not. */
+-#define FREE_P(descr) ((descr)->tid <= 0)
+-
+-
+-/* We create a double linked list of all cache entries. Double linked
+- because this allows removing entries from the end. */
+-
+-
+-/* Get a stack frame from the cache. We have to match by size since
+- some blocks might be too small or far too large. */
+-static struct pthread *
+-get_cached_stack (size_t *sizep, void **memp)
+-{
+- size_t size = *sizep;
+- struct pthread *result = NULL;
+- list_t *entry;
+-
+- lll_lock (stack_cache_lock);
+-
+- /* Search the cache for a matching entry. We search for the
+- smallest stack which has at least the required size. Note that
+- in normal situations the size of all allocated stacks is the
+- same. As the very least there are only a few different sizes.
+- Therefore this loop will exit early most of the time with an
+- exact match. */
+- list_for_each (entry, &stack_cache)
+- {
+- struct pthread *curr;
+-
+- curr = list_entry (entry, struct pthread, list);
+- if (FREE_P (curr) && curr->stackblock_size >= size)
+- {
+- if (curr->stackblock_size == size)
+- {
+- result = curr;
+- break;
+- }
+-
+- if (result == NULL
+- || result->stackblock_size > curr->stackblock_size)
+- result = curr;
+- }
+- }
+-
+- if (__builtin_expect (result == NULL, 0)
+- /* Make sure the size difference is not too excessive. In that
+- case we do not use the block. */
+- || __builtin_expect (result->stackblock_size > 4 * size, 0))
+- {
+- /* Release the lock. */
+- lll_unlock (stack_cache_lock);
+-
+- return NULL;
+- }
+-
+- /* Dequeue the entry. */
+- list_del (&result->list);
+-
+- /* And add to the list of stacks in use. */
+- list_add (&result->list, &stack_used);
+-
+- /* And decrease the cache size. */
+- stack_cache_actsize -= result->stackblock_size;
+-
+- /* Release the lock early. */
+- lll_unlock (stack_cache_lock);
+-
+- /* Report size and location of the stack to the caller. */
+- *sizep = result->stackblock_size;
+- *memp = result->stackblock;
+-
+- /* Cancellation handling is back to the default. */
+- result->cancelhandling = 0;
+- result->cleanup = NULL;
+-
+- /* No pending event. */
+- result->nextevent = NULL;
+-
+- /* Clear the DTV. */
+- dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
+- memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+-
+- /* Re-initialize the TLS. */
+- _dl_allocate_tls_init (TLS_TPADJ (result));
+-
+- return result;
+-}
+-
+-
+-/* Add a stack frame which is not used anymore to the stack. Must be
+- called with the cache lock held. */
+-static inline void
+-__attribute ((always_inline))
+-queue_stack (struct pthread *stack)
+-{
+- /* We unconditionally add the stack to the list. The memory may
+- still be in use but it will not be reused until the kernel marks
+- the stack as not used anymore. */
+- list_add (&stack->list, &stack_cache);
+-
+- stack_cache_actsize += stack->stackblock_size;
+- if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0))
+- {
+- /* We reduce the size of the cache. Remove the last entries
+- until the size is below the limit. */
+- list_t *entry;
+- list_t *prev;
+-
+- /* Search from the end of the list. */
+- list_for_each_prev_safe (entry, prev, &stack_cache)
+- {
+- struct pthread *curr;
+-
+- curr = list_entry (entry, struct pthread, list);
+- if (FREE_P (curr))
+- {
+- /* Unlink the block. */
+- list_del (entry);
+-
+- /* Account for the freed memory. */
+- stack_cache_actsize -= curr->stackblock_size;
+-
+- /* Free the memory associated with the ELF TLS. */
+- _dl_deallocate_tls (TLS_TPADJ (curr), false);
+-
+- /* Remove this block. This should never fail. If it
+- does something is really wrong. */
+- if (munmap (curr->stackblock, curr->stackblock_size) != 0)
+- abort ();
+-
+- /* Maybe we have freed enough. */
+- if (stack_cache_actsize <= stack_cache_maxsize)
+- break;
+- }
+- }
+- }
+-}
+-
+-
+-static int
+-internal_function
+-change_stack_perm (struct pthread *pd
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- , size_t pagemask
+-#endif
+- )
+-{
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- void *stack = (pd->stackblock
+- + (((((pd->stackblock_size - pd->guardsize) / 2)
+- & pagemask) + pd->guardsize) & pagemask));
+- size_t len = pd->stackblock + pd->stackblock_size - stack;
+-#else
+- void *stack = pd->stackblock + pd->guardsize;
+- size_t len = pd->stackblock_size - pd->guardsize;
+-#endif
+- if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+- return errno;
+-
+- return 0;
+-}
+-
+-
+-static int
+-allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
+- ALLOCATE_STACK_PARMS)
+-{
+- struct pthread *pd;
+- size_t size;
+- size_t pagesize_m1 = __getpagesize () - 1;
+- void *stacktop;
+-
+- assert (attr != NULL);
+- assert (powerof2 (pagesize_m1 + 1));
+- assert (TCB_ALIGNMENT >= STACK_ALIGN);
+-
+- /* Get the stack size from the attribute if it is set. Otherwise we
+- use the default we determined at start time. */
+- size = attr->stacksize ?: __default_stacksize;
+-
+- /* Get memory for the stack. */
+- if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
+- {
+- uintptr_t adj;
+-
+- /* If the user also specified the size of the stack make sure it
+- is large enough. */
+- if (attr->stacksize != 0
+- && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK))
+- return EINVAL;
+-
+- /* Adjust stack size for alignment of the TLS block. */
+-#if TLS_TCB_AT_TP
+- adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE)
+- & __static_tls_align_m1;
+- assert (size > adj + TLS_TCB_SIZE);
+-#elif TLS_DTV_AT_TP
+- adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
+- & __static_tls_align_m1;
+- assert (size > adj);
+-#endif
+-
+- /* The user provided some memory. Let's hope it matches the
+- size... We do not allocate guard pages if the user provided
+- the stack. It is the user's responsibility to do this if it
+- is wanted. */
+-#if TLS_TCB_AT_TP
+- pd = (struct pthread *) ((uintptr_t) attr->stackaddr
+- - TLS_TCB_SIZE - adj);
+-#elif TLS_DTV_AT_TP
+- pd = (struct pthread *) (((uintptr_t) attr->stackaddr
+- - __static_tls_size - adj)
+- - TLS_PRE_TCB_SIZE);
+-#endif
+-
+- /* The user provided stack memory needs to be cleared. */
+- memset (pd, '\0', sizeof (struct pthread));
+-
+- /* The first TSD block is included in the TCB. */
+- pd->specific[0] = pd->specific_1stblock;
+-
+- /* Remember the stack-related values. */
+- pd->stackblock = (char *) attr->stackaddr - size;
+- pd->stackblock_size = size;
+-
+- /* This is a user-provided stack. It will not be queued in the
+- stack cache nor will the memory (except the TLS memory) be freed. */
+- pd->user_stack = true;
+-
+- /* This is at least the second thread. */
+- pd->header.multiple_threads = 1;
+-#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+- __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
+-#endif
+-
+-#ifdef NEED_DL_SYSINFO
+- /* Copy the sysinfo value from the parent. */
+- THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
+-#endif
+-
+- /* The process ID is also the same as that of the caller. */
+- pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
+-
+- /* Allocate the DTV for this thread. */
+- if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
+- {
+- /* Something went wrong. */
+- assert (errno == ENOMEM);
+- return EAGAIN;
+- }
+-
+-
+- /* Prepare to modify global data. */
+- lll_lock (stack_cache_lock);
+-
+- /* And add to the list of stacks in use. */
+- list_add (&pd->list, &__stack_user);
+-
+- lll_unlock (stack_cache_lock);
+- }
+- else
+- {
+- /* Allocate some anonymous memory. If possible use the cache. */
+- size_t guardsize;
+- size_t reqsize;
+- void *mem;
+- const int prot = (PROT_READ | PROT_WRITE
+- | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
+-
+-#if COLORING_INCREMENT != 0
+- /* Add one more page for stack coloring. Don't do it for stacks
+- with 16 times pagesize or larger. This might just cause
+- unnecessary misalignment. */
+- if (size <= 16 * pagesize_m1)
+- size += pagesize_m1 + 1;
+-#endif
+-
+- /* Adjust the stack size for alignment. */
+- size &= ~__static_tls_align_m1;
+- assert (size != 0);
+-
+- /* Make sure the size of the stack is enough for the guard and
+- eventually the thread descriptor. */
+- guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1;
+- if (__builtin_expect (size < (guardsize + __static_tls_size
+- + MINIMAL_REST_STACK + pagesize_m1 + 1),
+- 0))
+- /* The stack is too small (or the guard too large). */
+- return EINVAL;
+-
+- /* Try to get a stack from the cache. */
+- reqsize = size;
+- pd = get_cached_stack (&size, &mem);
+- if (pd == NULL)
+- {
+- /* To avoid aliasing effects on a larger scale than pages we
+- adjust the allocated stack size if necessary. This way
+- allocations directly following each other will not have
+- aliasing problems. */
+-#if MULTI_PAGE_ALIASING != 0
+- if ((size % MULTI_PAGE_ALIASING) == 0)
+- size += pagesize_m1 + 1;
+-#endif
+-
+- mem = mmap (NULL, size, prot,
+- MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0);
+-
+- if (__builtin_expect (mem == MAP_FAILED, 0))
+- {
+-#ifdef ARCH_RETRY_MMAP
+- mem = ARCH_RETRY_MMAP (size);
+- if (__builtin_expect (mem == MAP_FAILED, 0))
+-#endif
+- return errno;
+- }
+-
+- /* SIZE is guaranteed to be greater than zero.
+- So we can never get a null pointer back from mmap. */
+- assert (mem != NULL);
+-
+-#if COLORING_INCREMENT != 0
+- /* Atomically increment NCREATED. */
+- unsigned int ncreated = atomic_increment_val (&nptl_ncreated);
+-
+- /* We chose the offset for coloring by incrementing it for
+- every new thread by a fixed amount. The offset used
+- module the page size. Even if coloring would be better
+- relative to higher alignment values it makes no sense to
+- do it since the mmap() interface does not allow us to
+- specify any alignment for the returned memory block. */
+- size_t coloring = (ncreated * COLORING_INCREMENT) & pagesize_m1;
+-
+- /* Make sure the coloring offsets does not disturb the alignment
+- of the TCB and static TLS block. */
+- if (__builtin_expect ((coloring & __static_tls_align_m1) != 0, 0))
+- coloring = (((coloring + __static_tls_align_m1)
+- & ~(__static_tls_align_m1))
+- & ~pagesize_m1);
+-#else
+- /* Unless specified we do not make any adjustments. */
+-# define coloring 0
+-#endif
+-
+- /* Place the thread descriptor at the end of the stack. */
+-#if TLS_TCB_AT_TP
+- pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
+-#elif TLS_DTV_AT_TP
+- pd = (struct pthread *) ((((uintptr_t) mem + size - coloring
+- - __static_tls_size)
+- & ~__static_tls_align_m1)
+- - TLS_PRE_TCB_SIZE);
+-#endif
+-
+- /* Remember the stack-related values. */
+- pd->stackblock = mem;
+- pd->stackblock_size = size;
+-
+- /* We allocated the first block thread-specific data array.
+- This address will not change for the lifetime of this
+- descriptor. */
+- pd->specific[0] = pd->specific_1stblock;
+-
+- /* This is at least the second thread. */
+- pd->header.multiple_threads = 1;
+-#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+- __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
+-#endif
+-
+-#ifdef NEED_DL_SYSINFO
+- /* Copy the sysinfo value from the parent. */
+- THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
+-#endif
+-
+- /* The process ID is also the same as that of the caller. */
+- pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
+-
+- /* Allocate the DTV for this thread. */
+- if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
+- {
+- /* Something went wrong. */
+- assert (errno == ENOMEM);
+-
+- /* Free the stack memory we just allocated. */
+- (void) munmap (mem, size);
+-
+- return EAGAIN;
+- }
+-
+-
+- /* Prepare to modify global data. */
+- lll_lock (stack_cache_lock);
+-
+- /* And add to the list of stacks in use. */
+- list_add (&pd->list, &stack_used);
+-
+- lll_unlock (stack_cache_lock);
+-
+-
+- /* There might have been a race. Another thread might have
+- caused the stacks to get exec permission while this new
+- stack was prepared. Detect if this was possible and
+- change the permission if necessary. */
+- if (__builtin_expect ((GL(dl_stack_flags) & PF_X) != 0
+- && (prot & PROT_EXEC) == 0, 0))
+- {
+- int err = change_stack_perm (pd
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- , ~pagesize_m1
+-#endif
+- );
+- if (err != 0)
+- {
+- /* Free the stack memory we just allocated. */
+- (void) munmap (mem, size);
+-
+- return err;
+- }
+- }
+-
+-
+- /* Note that all of the stack and the thread descriptor is
+- zeroed. This means we do not have to initialize fields
+- with initial value zero. This is specifically true for
+- the 'tid' field which is always set back to zero once the
+- stack is not used anymore and for the 'guardsize' field
+- which will be read next. */
+- }
+-
+- /* Create or resize the guard area if necessary. */
+- if (__builtin_expect (guardsize > pd->guardsize, 0))
+- {
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
+-#else
+- char *guard = mem;
+-#endif
+- if (mprotect (guard, guardsize, PROT_NONE) != 0)
+- {
+- int err;
+- mprot_error:
+- err = errno;
+-
+- lll_lock (stack_cache_lock);
+-
+- /* Remove the thread from the list. */
+- list_del (&pd->list);
+-
+- lll_unlock (stack_cache_lock);
+-
+- /* Get rid of the TLS block we allocated. */
+- _dl_deallocate_tls (TLS_TPADJ (pd), false);
+-
+- /* Free the stack memory regardless of whether the size
+- of the cache is over the limit or not. If this piece
+- of memory caused problems we better do not use it
+- anymore. Uh, and we ignore possible errors. There
+- is nothing we could do. */
+- (void) munmap (mem, size);
+-
+- return err;
+- }
+-
+- pd->guardsize = guardsize;
+- }
+- else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize,
+- 0))
+- {
+- /* The old guard area is too large. */
+-
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
+- char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1);
+-
+- if (oldguard < guard
+- && mprotect (oldguard, guard - oldguard, prot) != 0)
+- goto mprot_error;
+-
+- if (mprotect (guard + guardsize,
+- oldguard + pd->guardsize - guard - guardsize,
+- prot) != 0)
+- goto mprot_error;
+-#else
+- if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
+- prot) != 0)
+- goto mprot_error;
+-#endif
+-
+- pd->guardsize = guardsize;
+- }
+- /* The pthread_getattr_np() calls need to get passed the size
+- requested in the attribute, regardless of how large the
+- actually used guardsize is. */
+- pd->reported_guardsize = guardsize;
+- }
+-
+- /* Initialize the lock. We have to do this unconditionally since the
+- stillborn thread could be canceled while the lock is taken. */
+- pd->lock = LLL_LOCK_INITIALIZER;
+-
+- /* We place the thread descriptor at the end of the stack. */
+- *pdp = pd;
+-
+-#if TLS_TCB_AT_TP
+- /* The stack begins before the TCB and the static TLS block. */
+- stacktop = ((char *) (pd + 1) - __static_tls_size);
+-#elif TLS_DTV_AT_TP
+- stacktop = (char *) (pd - 1);
+-#endif
+-
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- *stack = pd->stackblock;
+- *stacksize = stacktop - *stack;
+-#else
+- *stack = stacktop;
+-#endif
+-
+- return 0;
+-}
+-
+-
+-void
+-internal_function
+-__deallocate_stack (struct pthread *pd)
+-{
+- lll_lock (stack_cache_lock);
+-
+- /* Remove the thread from the list of threads with user defined
+- stacks. */
+- list_del (&pd->list);
+-
+- /* Not much to do. Just free the mmap()ed memory. Note that we do
+- not reset the 'used' flag in the 'tid' field. This is done by
+- the kernel. If no thread has been created yet this field is
+- still zero. */
+- if (__builtin_expect (! pd->user_stack, 1))
+- (void) queue_stack (pd);
+- else
+- /* Free the memory associated with the ELF TLS. */
+- _dl_deallocate_tls (TLS_TPADJ (pd), false);
+-
+- lll_unlock (stack_cache_lock);
+-}
+-
+-
+-int
+-internal_function
+-__make_stacks_executable (void **stack_endp)
+-{
+- /* First the main thread's stack. */
+- int err = _dl_make_stack_executable (stack_endp);
+- if (err != 0)
+- return err;
+-
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- const size_t pagemask = ~(__getpagesize () - 1);
+-#endif
+-
+- lll_lock (stack_cache_lock);
+-
+- list_t *runp;
+- list_for_each (runp, &stack_used)
+- {
+- err = change_stack_perm (list_entry (runp, struct pthread, list)
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- , pagemask
+-#endif
+- );
+- if (err != 0)
+- break;
+- }
+-
+- /* Also change the permission for the currently unused stacks. This
+- might be wasted time but better spend it here than adding a check
+- in the fast path. */
+- if (err == 0)
+- list_for_each (runp, &stack_cache)
+- {
+- err = change_stack_perm (list_entry (runp, struct pthread, list)
+-#ifdef NEED_SEPARATE_REGISTER_STACK
+- , pagemask
+-#endif
+- );
+- if (err != 0)
+- break;
+- }
+-
+- lll_unlock (stack_cache_lock);
+-
+- return err;
+-}
+-
+-
+-/* In case of a fork() call the memory allocation in the child will be
+- the same but only one thread is running. All stacks except that of
+- the one running thread are not used anymore. We have to recycle
+- them. */
+-void
+-__reclaim_stacks (void)
+-{
+- struct pthread *self = (struct pthread *) THREAD_SELF;
+-
+- /* No locking necessary. The caller is the only stack in use. */
+-
+- /* Mark all stacks except the still running one as free. */
+- list_t *runp;
+- list_for_each (runp, &stack_used)
+- {
+- struct pthread *curp;
+-
+- curp = list_entry (runp, struct pthread, list);
+- if (curp != self)
+- {
+- /* This marks the stack as free. */
+- curp->tid = 0;
+-
+- /* The PID field must be initialized for the new process. */
+- curp->pid = self->pid;
+-
+- /* Account for the size of the stack. */
+- stack_cache_actsize += curp->stackblock_size;
+- }
+- }
+-
+- /* Add the stack of all running threads to the cache. */
+- list_splice (&stack_used, &stack_cache);
+-
+- /* Remove the entry for the current thread to from the cache list
+- and add it to the list of running threads. Which of the two
+- lists is decided by the user_stack flag. */
+- list_del (&self->list);
+-
+- /* Re-initialize the lists for all the threads. */
+- INIT_LIST_HEAD (&stack_used);
+- INIT_LIST_HEAD (&__stack_user);
+-
+- if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0))
+- list_add (&self->list, &__stack_user);
+- else
+- list_add (&self->list, &stack_used);
+-
+- /* There is one thread running. */
+- __nptl_nthreads = 1;
+-
+- /* Initialize the lock. */
+- stack_cache_lock = LLL_LOCK_INITIALIZER;
+-}
+-
+-
+-#if HP_TIMING_AVAIL
+-# undef __find_thread_by_id
+-/* Find a thread given the thread ID. */
+-attribute_hidden
+-struct pthread *
+-__find_thread_by_id (pid_t tid)
+-{
+- struct pthread *result = NULL;
+-
+- lll_lock (stack_cache_lock);
+-
+- /* Iterate over the list with system-allocated threads first. */
+- list_t *runp;
+- list_for_each (runp, &stack_used)
+- {
+- struct pthread *curp;
+-
+- curp = list_entry (runp, struct pthread, list);
+-
+- if (curp->tid == tid)
+- {
+- result = curp;
+- goto out;
+- }
+- }
+-
+- /* Now the list with threads using user-allocated stacks. */
+- list_for_each (runp, &__stack_user)
+- {
+- struct pthread *curp;
+-
+- curp = list_entry (runp, struct pthread, list);
+-
+- if (curp->tid == tid)
+- {
+- result = curp;
+- goto out;
+- }
+- }
+-
+- out:
+- lll_unlock (stack_cache_lock);
+-
+- return result;
+-}
+-#endif
+-
+-int
+-attribute_hidden
+-__nptl_setxid (struct xid_command *cmdp)
+-{
+- int result;
+- lll_lock (stack_cache_lock);
+-
+- __xidcmd = cmdp;
+- cmdp->cntr = 0;
+-
+- INTERNAL_SYSCALL_DECL (err);
+-
+- struct pthread *self = THREAD_SELF;
+-
+- /* Iterate over the list with system-allocated threads first. */
+- list_t *runp;
+- list_for_each (runp, &stack_used)
+- {
+- struct pthread *t = list_entry (runp, struct pthread, list);
+- if (t != self)
+- {
+- int val;
+-#if __ASSUME_TGKILL
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+-#else
+-# ifdef __NR_tgkill
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+- if (INTERNAL_SYSCALL_ERROR_P (val, err)
+- && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+-# endif
+- val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
+-#endif
+-
+- if (!INTERNAL_SYSCALL_ERROR_P (val, err))
+- atomic_increment (&cmdp->cntr);
+- }
+- }
+-
+- /* Now the list with threads using user-allocated stacks. */
+- list_for_each (runp, &__stack_user)
+- {
+- struct pthread *t = list_entry (runp, struct pthread, list);
+- if (t != self)
+- {
+- int val;
+-#if __ASSUME_TGKILL
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+-#else
+-# ifdef __NR_tgkill
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+- if (INTERNAL_SYSCALL_ERROR_P (val, err)
+- && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+-# endif
+- val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
+-#endif
+-
+- if (!INTERNAL_SYSCALL_ERROR_P (val, err))
+- atomic_increment (&cmdp->cntr);
+- }
+- }
+-
+- int cur = cmdp->cntr;
+- while (cur != 0)
+- {
+- lll_futex_wait (&cmdp->cntr, cur);
+- cur = cmdp->cntr;
+- }
+-
+- /* This must be last, otherwise the current thread might not have
+- permissions to send SIGSETXID syscall to the other threads. */
+- result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3,
+- cmdp->id[0], cmdp->id[1], cmdp->id[2]);
+- if (INTERNAL_SYSCALL_ERROR_P (result, err))
+- {
+- __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
+- result = -1;
+- }
+-
+- lll_unlock (stack_cache_lock);
+- return result;
+-}
+-
+-static inline void __attribute__((always_inline))
+-init_one_static_tls (struct pthread *curp, struct link_map *map)
+-{
+- dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
+-# if TLS_TCB_AT_TP
+- void *dest = (char *) curp - map->l_tls_offset;
+-# elif TLS_DTV_AT_TP
+- void *dest = (char *) curp + 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);
+-}
+-
+-void
+-attribute_hidden
+-__pthread_init_static_tls (struct link_map *map)
+-{
+- lll_lock (stack_cache_lock);
+-
+- /* Iterate over the list with system-allocated threads first. */
+- list_t *runp;
+- list_for_each (runp, &stack_used)
+- init_one_static_tls (list_entry (runp, struct pthread, list), map);
+-
+- /* Now the list with threads using user-allocated stacks. */
+- list_for_each (runp, &__stack_user)
+- init_one_static_tls (list_entry (runp, struct pthread, list), map);
+-
+- lll_unlock (stack_cache_lock);
+-}
+diff -x CVS -rupN libc/nptl/init.c libc/nptl/init.c
+--- libc/nptl/init.c 2005-01-23 18:39:28.000000000 +0100
++++ libc/nptl/init.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,345 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 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 <assert.h>
+-#include <limits.h>
+-#include <signal.h>
+-#include <stdlib.h>
+-#include <unistd.h>
+-#include <sys/param.h>
+-#include <sys/resource.h>
+-#include <pthreadP.h>
+-#include <atomic.h>
+-#include <ldsodefs.h>
+-#include <tls.h>
+-#include <fork.h>
+-#include <version.h>
+-#include <shlib-compat.h>
+-#include <smp.h>
+-#include <lowlevellock.h>
+-
+-
+-#ifndef __NR_set_tid_address
+-/* XXX For the time being... Once we can rely on the kernel headers
+- having the definition remove these lines. */
+-#if defined __s390__
+-# define __NR_set_tid_address 252
+-#elif defined __ia64__
+-# define __NR_set_tid_address 1233
+-#elif defined __i386__
+-# define __NR_set_tid_address 258
+-#elif defined __x86_64__
+-# define __NR_set_tid_address 218
+-#elif defined __powerpc__
+-# define __NR_set_tid_address 232
+-#elif defined __sparc__
+-# define __NR_set_tid_address 166
+-#else
+-# error "define __NR_set_tid_address"
+-#endif
+-#endif
+-
+-
+-/* Size and alignment of static TLS block. */
+-size_t __static_tls_size;
+-size_t __static_tls_align_m1;
+-
+-/* Version of the library, used in libthread_db to detect mismatches. */
+-static const char nptl_version[] __attribute_used__ = VERSION;
+-
+-
+-#if defined USE_TLS && !defined SHARED
+-extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
+-#endif
+-
+-
+-#ifdef SHARED
+-static const struct pthread_functions pthread_functions =
+- {
+- .ptr_pthread_attr_destroy = __pthread_attr_destroy,
+-# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+- .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0,
+-# endif
+- .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
+- .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,
+-# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
+- .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
+- .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
+- .ptr___pthread_cond_init_2_0 = __pthread_cond_init_2_0,
+- .ptr___pthread_cond_signal_2_0 = __pthread_cond_signal_2_0,
+- .ptr___pthread_cond_wait_2_0 = __pthread_cond_wait_2_0,
+- .ptr___pthread_cond_timedwait_2_0 = __pthread_cond_timedwait_2_0,
+-# endif
+- .ptr_pthread_equal = __pthread_equal,
+- .ptr___pthread_exit = __pthread_exit,
+- .ptr_pthread_getschedparam = __pthread_getschedparam,
+- .ptr_pthread_setschedparam = __pthread_setschedparam,
+- .ptr_pthread_mutex_destroy = INTUSE(__pthread_mutex_destroy),
+- .ptr_pthread_mutex_init = INTUSE(__pthread_mutex_init),
+- .ptr_pthread_mutex_lock = INTUSE(__pthread_mutex_lock),
+- .ptr_pthread_mutex_unlock = INTUSE(__pthread_mutex_unlock),
+- .ptr_pthread_self = __pthread_self,
+- .ptr_pthread_setcancelstate = __pthread_setcancelstate,
+- .ptr_pthread_setcanceltype = __pthread_setcanceltype,
+- .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
+- .ptr___pthread_once = __pthread_once_internal,
+- .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock_internal,
+- .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock_internal,
+- .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock_internal,
+- .ptr___pthread_key_create = __pthread_key_create_internal,
+- .ptr___pthread_getspecific = __pthread_getspecific_internal,
+- .ptr___pthread_setspecific = __pthread_setspecific_internal,
+- .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer,
+- .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore,
+- .ptr_nthreads = &__nptl_nthreads,
+- .ptr___pthread_unwind = &__pthread_unwind,
+- .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
+- .ptr__nptl_setxid = __nptl_setxid
+- };
+-# define ptr_pthread_functions &pthread_functions
+-#else
+-# define ptr_pthread_functions NULL
+-#endif
+-
+-
+-/* For asynchronous cancellation we use a signal. This is the handler. */
+-static void
+-sigcancel_handler (int sig, siginfo_t *si, void *ctx)
+-{
+- /* Safety check. It would be possible to call this function for
+- other signals and send a signal from another process. This is not
+- correct and might even be a security problem. Try to catch as
+- many incorrect invocations as possible. */
+- if (sig != SIGCANCEL
+-#ifdef __ASSUME_CORRECT_SI_PID
+- /* Kernels before 2.5.75 stored the thread ID and not the process
+- ID in si_pid so we skip this test. */
+- || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
+-#endif
+- || si->si_code != SI_TKILL)
+- return;
+-
+- struct pthread *self = THREAD_SELF;
+-
+- int oldval = THREAD_GETMEM (self, cancelhandling);
+- while (1)
+- {
+- /* We are canceled now. When canceled by another thread this flag
+- is already set but if the signal is directly send (internally or
+- from another process) is has to be done here. */
+- int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
+-
+- if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
+- /* Already canceled or exiting. */
+- break;
+-
+- int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
+- oldval);
+- if (curval == oldval)
+- {
+- /* Set the return value. */
+- THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+-
+- /* Make sure asynchronous cancellation is still enabled. */
+- if ((newval & CANCELTYPE_BITMASK) != 0)
+- /* Run the registered destructors and terminate the thread. */
+- __do_cancel ();
+-
+- break;
+- }
+-
+- oldval = curval;
+- }
+-}
+-
+-
+-struct xid_command *__xidcmd attribute_hidden;
+-
+-/* For asynchronous cancellation we use a signal. This is the handler. */
+-static void
+-sighandler_setxid (int sig, siginfo_t *si, void *ctx)
+-{
+- /* Safety check. It would be possible to call this function for
+- other signals and send a signal from another process. This is not
+- correct and might even be a security problem. Try to catch as
+- many incorrect invocations as possible. */
+- if (sig != SIGSETXID
+-#ifdef __ASSUME_CORRECT_SI_PID
+- /* Kernels before 2.5.75 stored the thread ID and not the process
+- ID in si_pid so we skip this test. */
+- || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
+-#endif
+- || si->si_code != SI_TKILL)
+- return;
+-
+- INTERNAL_SYSCALL_DECL (err);
+- INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
+- __xidcmd->id[1], __xidcmd->id[2]);
+-
+- if (atomic_decrement_val (&__xidcmd->cntr) == 0)
+- lll_futex_wake (&__xidcmd->cntr, 1);
+-}
+-
+-
+-/* 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));
+-
+-
+-void
+-__pthread_initialize_minimal_internal (void)
+-{
+-#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);
+-
+- /* We must prevent gcc from being clever and move any of the
+- following code ahead of the __libc_setup_tls call. This function
+- will initialize the thread register which is subsequently
+- used. */
+- __asm __volatile ("");
+-#endif
+-
+- /* Minimal initialization of the thread descriptor. */
+- struct pthread *pd = THREAD_SELF;
+- INTERNAL_SYSCALL_DECL (err);
+- pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
+- THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
+- THREAD_SETMEM (pd, user_stack, true);
+- if (LLL_LOCK_INITIALIZER != 0)
+- THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
+-#if HP_TIMING_AVAIL
+- THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
+-#endif
+-
+- /* Set initial thread's stack block from 0 up to __libc_stack_end.
+- It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
+- purposes this is good enough. */
+- THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
+-
+- /* Initialize the list of all running threads with the main thread. */
+- INIT_LIST_HEAD (&__stack_user);
+- list_add (&pd->list, &__stack_user);
+-
+-
+- /* Install the cancellation signal handler. If for some reason we
+- cannot install the handler we do not abort. Maybe we should, but
+- it is only asynchronous cancellation which is affected. */
+- struct sigaction sa;
+- sa.sa_sigaction = sigcancel_handler;
+- sa.sa_flags = SA_SIGINFO;
+- __sigemptyset (&sa.sa_mask);
+-
+- (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
+-
+- /* Install the handle to change the threads' uid/gid. */
+- sa.sa_sigaction = sighandler_setxid;
+- sa.sa_flags = SA_SIGINFO | SA_RESTART;
+-
+- (void) __libc_sigaction (SIGSETXID, &sa, NULL);
+-
+- /* The parent process might have left the signals blocked. Just in
+- case, unblock it. We reuse the signal mask in the sigaction
+- structure. It is already cleared. */
+- __sigaddset (&sa.sa_mask, SIGCANCEL);
+- __sigaddset (&sa.sa_mask, SIGSETXID);
+- (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
+- NULL, _NSIG / 8);
+-
+-
+- /* Determine the default allowed stack size. This is the size used
+- in case the user does not specify one. */
+- struct rlimit limit;
+- if (getrlimit (RLIMIT_STACK, &limit) != 0
+- || limit.rlim_cur == RLIM_INFINITY)
+- /* The system limit is not usable. Use an architecture-specific
+- default. */
+- __default_stacksize = ARCH_STACK_DEFAULT_SIZE;
+- else if (limit.rlim_cur < PTHREAD_STACK_MIN)
+- /* The system limit is unusably small.
+- Use the minimal size acceptable. */
+- __default_stacksize = PTHREAD_STACK_MIN;
+- else
+- {
+- /* Round the resource limit up to page size. */
+- const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
+- __default_stacksize = (limit.rlim_cur + pagesz - 1) & -pagesz;
+- }
+-
+- /* Get the size of the static and alignment requirements for the TLS
+- block. */
+- size_t static_tls_align;
+- _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);
+-
+- /* Make sure the size takes all the alignments into account. */
+- if (STACK_ALIGN > static_tls_align)
+- static_tls_align = STACK_ALIGN;
+- __static_tls_align_m1 = static_tls_align - 1;
+-
+- __static_tls_size = roundup (__static_tls_size, static_tls_align);
+-
+-#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 *) INTUSE (__pthread_mutex_lock);
+- GL(dl_rtld_unlock_recursive) = (void *) INTUSE (__pthread_mutex_unlock);
+- unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
+- GL(dl_load_lock).mutex.__data.__count = 0;
+- while (rtld_lock_count-- > 0)
+- INTUSE (__pthread_mutex_lock) (&GL(dl_load_lock).mutex);
+-
+- GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
+-#endif
+-
+- GL(dl_init_static_tls) = &__pthread_init_static_tls;
+-
+- /* Register the fork generation counter with the libc. */
+-#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+- __libc_multiple_threads_ptr =
+-#endif
+- __libc_pthread_init (&__fork_generation, __reclaim_stacks,
+- ptr_pthread_functions);
+-
+- /* Determine whether the machine is SMP or not. */
+- __is_smp = is_smp_system ();
+-}
+-strong_alias (__pthread_initialize_minimal_internal,
+- __pthread_initialize_minimal)
+diff -x CVS -rupN libc/nptl/Makefile libc/nptl/Makefile
+--- libc/nptl/Makefile 2005-01-23 18:39:28.000000000 +0100
++++ libc/nptl/Makefile 2005-01-23 19:35:29.000000000 +0100
+@@ -101,10 +101,9 @@ libpthread-routines = init vars events v
+ pt-longjmp pt-cleanup\
+ cancellation \
+ lowlevellock \
+- pt-vfork \
+ ptw-write ptw-read ptw-close ptw-fcntl ptw-accept \
+ ptw-connect ptw-recv ptw-recvfrom ptw-recvmsg ptw-send \
+- ptw-sendmsg ptw-sendto ptw-fsync ptw-lseek ptw-llseek \
++ ptw-sendmsg ptw-sendto ptw-fsync ptw-lseek \
+ ptw-msync ptw-nanosleep ptw-open ptw-open64 ptw-pause \
+ ptw-pread ptw-pread64 ptw-pwrite ptw-pwrite64 \
+ ptw-tcdrain ptw-wait ptw-waitpid ptw-msgrcv ptw-msgsnd \
+@@ -188,7 +187,6 @@ CFLAGS-pt-system.c = -fexceptions
+ # Don't generate deps for calls with no sources. See sysdeps/unix/Makefile.
+ omit-deps = $(unix-syscalls:%=ptw-%)
+
+-
+ tests = tst-attr1 tst-attr2 tst-attr3 \
+ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
+ tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
+@@ -341,7 +339,7 @@ tests-static += tst-locale1 tst-locale2
+ xtests-static += tst-setuid1-static
+ endif
+ # These tests are linked with libc before libpthread
+-tests-reverse += tst-cancel5 tst-cancel23 tst-vfork1x tst-vfork2x
++tests-reverse += tst-cancel5 tst-cancel23
+
+ include ../Rules
+
+diff -x CVS -rupN libc/nptl/pthread_cancel.c libc/nptl/pthread_cancel.c
+--- libc/nptl/pthread_cancel.c 2005-01-23 18:39:28.000000000 +0100
++++ libc/nptl/pthread_cancel.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,104 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <errno.h>
+-#include <signal.h>
+-#include "pthreadP.h"
+-#include "atomic.h"
+-#include <sysdep.h>
+-#include <kernel-features.h>
+-
+-
+-int
+-pthread_cancel (th)
+- pthread_t th;
+-{
+- volatile struct pthread *pd = (volatile struct pthread *) th;
+-
+- /* Make sure the descriptor is valid. */
+- if (INVALID_TD_P (pd))
+- /* Not a valid thread handle. */
+- return ESRCH;
+-
+-#ifdef SHARED
+- pthread_cancel_init ();
+-#endif
+- int result = 0;
+- int oldval;
+- int newval;
+- do
+- {
+- oldval = pd->cancelhandling;
+- newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
+-
+- /* Avoid doing unnecessary work. The atomic operation can
+- potentially be expensive if the bug has to be locked and
+- remote cache lines have to be invalidated. */
+- if (oldval == newval)
+- break;
+-
+- /* If the cancellation is handled asynchronously just send a
+- signal. We avoid this if possible since it's more
+- expensive. */
+- if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+- {
+- /* Mark the cancellation as "in progress". */
+- atomic_bit_set (&pd->cancelhandling, CANCELING_BIT);
+-
+- /* The cancellation handler will take care of marking the
+- thread as canceled. */
+- INTERNAL_SYSCALL_DECL (err);
+-
+- /* One comment: The PID field in the TCB can temporarily be
+- changed (in fork). But this must not affect this code
+- here. Since this function would have to be called while
+- the thread is executing fork, it would have to happen in
+- a signal handler. But this is no allowed, pthread_cancel
+- is not guaranteed to be async-safe. */
+- int val;
+-#if __ASSUME_TGKILL
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
+- SIGCANCEL);
+-#else
+-# ifdef __NR_tgkill
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
+- SIGCANCEL);
+- if (INTERNAL_SYSCALL_ERROR_P (val, err)
+- && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+-# endif
+- val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL);
+-#endif
+-
+- if (INTERNAL_SYSCALL_ERROR_P (val, err))
+- result = INTERNAL_SYSCALL_ERRNO (val, err);
+-
+- break;
+- }
+- }
+- /* Mark the thread as canceled. This has to be done
+- atomically since other bits could be modified as well. */
+- while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval,
+- oldval));
+-
+- return result;
+-}
+-
+-PTHREAD_STATIC_FN_REQUIRE (pthread_create)
+diff -x CVS -rupN libc/nptl/pthread_condattr_setclock.c libc/nptl/pthread_condattr_setclock.c
+--- libc/nptl/pthread_condattr_setclock.c 2004-10-10 12:41:04.000000000 +0200
++++ libc/nptl/pthread_condattr_setclock.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,72 +0,0 @@
+-/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <assert.h>
+-#include <errno.h>
+-#include <stdbool.h>
+-#include <time.h>
+-#include <sysdep.h>
+-#include "pthreadP.h"
+-#include <kernel-features.h>
+-
+-
+-int
+-pthread_condattr_setclock (attr, clock_id)
+- pthread_condattr_t *attr;
+- clockid_t clock_id;
+-{
+- /* Only a few clocks are allowed. CLOCK_REALTIME is always allowed.
+- CLOCK_MONOTONIC only if the kernel has the necessary support. */
+- if (clock_id == CLOCK_MONOTONIC)
+- {
+-#ifndef __ASSUME_POSIX_TIMERS
+-# ifdef __NR_clock_getres
+- /* Check whether the clock is available. */
+- static int avail;
+-
+- if (avail == 0)
+- {
+- struct timespec ts;
+-
+- INTERNAL_SYSCALL_DECL (err);
+- int val;
+- val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts);
+- avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1;
+- }
+-
+- if (avail < 0)
+-# endif
+- /* Not available. */
+- return EINVAL;
+-#endif
+- }
+- else if (clock_id != CLOCK_REALTIME)
+- /* If more clocks are allowed some day the storing of the clock ID
+- in the pthread_cond_t structure needs to be adjusted. */
+- return EINVAL;
+-
+- /* Make sure the value fits in the bits we reserved. */
+- assert (clock_id < (1 << COND_CLOCK_BITS));
+-
+- int *valuep = &((struct pthread_condattr *) attr)->value;
+-
+- *valuep = (*valuep & ~(1 << (COND_CLOCK_BITS + 1)) & ~1) | (clock_id << 1);
+-
+- return 0;
+-}
+diff -x CVS -rupN libc/nptl/pthread_cond_init.c libc/nptl/pthread_cond_init.c
+--- libc/nptl/pthread_cond_init.c 2004-10-10 12:41:04.000000000 +0200
++++ libc/nptl/pthread_cond_init.c 2005-01-23 19:35:29.000000000 +0100
+@@ -30,7 +30,7 @@ __pthread_cond_init (cond, cond_attr)
+ Conditional variables are always usable in multiple processes. */
+ struct pthread_condattr *icond_attr = (struct pthread_condattr *) cond_attr;
+
+- cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER;
++ cond->__data.__lock = LLL_LOCK_INITIALIZER;
+ cond->__data.__futex = 0;
+ cond->__data.__nwaiters = (icond_attr != NULL
+ && ((icond_attr->value & (COND_CLOCK_BITS << 1))
+diff -x CVS -rupN libc/nptl/pthread_create.c libc/nptl/pthread_create.c
+--- libc/nptl/pthread_create.c 2005-01-23 18:39:28.000000000 +0100
++++ libc/nptl/pthread_create.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,522 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <errno.h>
+-#include <stdbool.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include "pthreadP.h"
+-#include <hp-timing.h>
+-#include <ldsodefs.h>
+-#include <atomic.h>
+-#include <libc-internal.h>
+-#include <resolv.h>
+-
+-#include <shlib-compat.h>
+-
+-
+-/* Local function to start thread and handle cleanup. */
+-static int start_thread (void *arg);
+-
+-
+-/* Nozero if debugging mode is enabled. */
+-int __pthread_debug;
+-
+-/* Globally enabled events. */
+-static td_thr_events_t __nptl_threads_events;
+-
+-/* Pointer to descriptor with the last event. */
+-static struct pthread *__nptl_last_event;
+-
+-/* Number of threads running. */
+-unsigned int __nptl_nthreads = 1;
+-
+-
+-/* Code to allocate and deallocate a stack. */
+-#include "allocatestack.c"
+-
+-/* Code to create the thread. */
+-#include "createthread.c"
+-
+-
+-struct pthread *
+-internal_function
+-__find_in_stack_list (pd)
+- struct pthread *pd;
+-{
+- list_t *entry;
+- struct pthread *result = NULL;
+-
+- lll_lock (stack_cache_lock);
+-
+- list_for_each (entry, &stack_used)
+- {
+- struct pthread *curp;
+-
+- curp = list_entry (entry, struct pthread, list);
+- if (curp == pd)
+- {
+- result = curp;
+- break;
+- }
+- }
+-
+- if (result == NULL)
+- list_for_each (entry, &__stack_user)
+- {
+- struct pthread *curp;
+-
+- curp = list_entry (entry, struct pthread, list);
+- if (curp == pd)
+- {
+- result = curp;
+- break;
+- }
+- }
+-
+- lll_unlock (stack_cache_lock);
+-
+- return result;
+-}
+-
+-
+-/* Deallocate POSIX thread-local-storage. */
+-void
+-attribute_hidden
+-__nptl_deallocate_tsd (void)
+-{
+- struct pthread *self = THREAD_SELF;
+-
+- /* Maybe no data was ever allocated. This happens often so we have
+- a flag for this. */
+- if (THREAD_GETMEM (self, specific_used))
+- {
+- size_t round;
+- size_t cnt;
+-
+- round = 0;
+- do
+- {
+- size_t idx;
+-
+- /* So far no new nonzero data entry. */
+- THREAD_SETMEM (self, specific_used, false);
+-
+- for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+- {
+- struct pthread_key_data *level2;
+-
+- level2 = THREAD_GETMEM_NC (self, specific, cnt);
+-
+- if (level2 != NULL)
+- {
+- size_t inner;
+-
+- for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
+- ++inner, ++idx)
+- {
+- void *data = level2[inner].data;
+-
+- if (data != NULL)
+- {
+- /* Always clear the data. */
+- level2[inner].data = NULL;
+-
+- /* Make sure the data corresponds to a valid
+- key. This test fails if the key was
+- deallocated and also if it was
+- re-allocated. It is the user's
+- responsibility to free the memory in this
+- case. */
+- if (level2[inner].seq
+- == __pthread_keys[idx].seq
+- /* It is not necessary to register a destructor
+- function. */
+- && __pthread_keys[idx].destr != NULL)
+- /* Call the user-provided destructor. */
+- __pthread_keys[idx].destr (data);
+- }
+- }
+- }
+- else
+- idx += PTHREAD_KEY_1STLEVEL_SIZE;
+- }
+-
+- if (THREAD_GETMEM (self, specific_used) == 0)
+- /* No data has been modified. */
+- goto just_free;
+- }
+- /* We only repeat the process a fixed number of times. */
+- while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0));
+-
+- /* Just clear the memory of the first block for reuse. */
+- memset (&THREAD_SELF->specific_1stblock, '\0',
+- sizeof (self->specific_1stblock));
+-
+- just_free:
+- /* Free the memory for the other blocks. */
+- for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+- {
+- struct pthread_key_data *level2;
+-
+- level2 = THREAD_GETMEM_NC (self, specific, cnt);
+- if (level2 != NULL)
+- {
+- /* The first block is allocated as part of the thread
+- descriptor. */
+- free (level2);
+- THREAD_SETMEM_NC (self, specific, cnt, NULL);
+- }
+- }
+-
+- THREAD_SETMEM (self, specific_used, false);
+- }
+-}
+-
+-
+-/* Deallocate a thread's stack after optionally making sure the thread
+- descriptor is still valid. */
+-void
+-internal_function
+-__free_tcb (struct pthread *pd)
+-{
+- /* The thread is exiting now. */
+- if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling,
+- TERMINATED_BIT) == 0, 1))
+- {
+- /* Remove the descriptor from the list. */
+- if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+- /* Something is really wrong. The descriptor for a still
+- running thread is gone. */
+- abort ();
+-
+- /* Queue the stack memory block for reuse and exit the process. The
+- kernel will signal via writing to the address returned by
+- QUEUE-STACK when the stack is available. */
+- __deallocate_stack (pd);
+- }
+-}
+-
+-
+-static int
+-start_thread (void *arg)
+-{
+- struct pthread *pd = (struct pthread *) arg;
+-
+-#if HP_TIMING_AVAIL
+- /* Remember the time when the thread was started. */
+- hp_timing_t now;
+- HP_TIMING_NOW (now);
+- THREAD_SETMEM (pd, cpuclock_offset, now);
+-#endif
+-
+- /* Initialize resolver state pointer. */
+- __resp = &pd->res;
+-
+- /* This is where the try/finally block should be created. For
+- compilers without that support we do use setjmp. */
+- struct pthread_unwind_buf unwind_buf;
+-
+- /* No previous handlers. */
+- unwind_buf.priv.data.prev = NULL;
+- unwind_buf.priv.data.cleanup = NULL;
+-
+- int not_first_call;
+- not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
+- if (__builtin_expect (! not_first_call, 1))
+- {
+- /* Store the new cleanup handler info. */
+- THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
+-
+- if (__builtin_expect (pd->stopped_start, 0))
+- {
+- int oldtype = CANCEL_ASYNC ();
+-
+- /* Get the lock the parent locked to force synchronization. */
+- lll_lock (pd->lock);
+- /* And give it up right away. */
+- lll_unlock (pd->lock);
+-
+- CANCEL_RESET (oldtype);
+- }
+-
+- /* Run the code the user provided. */
+-#ifdef CALL_THREAD_FCT
+- THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd));
+-#else
+- THREAD_SETMEM (pd, result, pd->start_routine (pd->arg));
+-#endif
+- }
+-
+- /* Run the destructor for the thread-local data. */
+- __nptl_deallocate_tsd ();
+-
+- /* Clean up any state libc stored in thread-local variables. */
+- __libc_thread_freeres ();
+-
+- /* If this is the last thread we terminate the process now. We
+- do not notify the debugger, it might just irritate it if there
+- is no thread left. */
+- if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0))
+- /* This was the last thread. */
+- exit (0);
+-
+- /* Report the death of the thread if this is wanted. */
+- if (__builtin_expect (pd->report_events, 0))
+- {
+- /* See whether TD_DEATH is in any of the mask. */
+- const int idx = __td_eventword (TD_DEATH);
+- const uint32_t mask = __td_eventmask (TD_DEATH);
+-
+- if ((mask & (__nptl_threads_events.event_bits[idx]
+- | pd->eventbuf.eventmask.event_bits[idx])) != 0)
+- {
+- /* Yep, we have to signal the death. Add the descriptor to
+- the list but only if it is not already on it. */
+- if (pd->nextevent == NULL)
+- {
+- pd->eventbuf.eventnum = TD_DEATH;
+- pd->eventbuf.eventdata = pd;
+-
+- do
+- pd->nextevent = __nptl_last_event;
+- while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
+- pd, pd->nextevent));
+- }
+-
+- /* Now call the function to signal the event. */
+- __nptl_death_event ();
+- }
+- }
+-
+- /* The thread is exiting now. Don't set this bit until after we've hit
+- the event-reporting breakpoint, so that td_thr_get_info on us while at
+- the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE. */
+- atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
+-
+- /* If the thread is detached free the TCB. */
+- if (IS_DETACHED (pd))
+- /* Free the TCB. */
+- __free_tcb (pd);
+-
+- /* We cannot call '_exit' here. '_exit' will terminate the process.
+-
+- The 'exit' implementation in the kernel will signal when the
+- process is really dead since 'clone' got passed the CLONE_CLEARTID
+- flag. The 'tid' field in the TCB will be set to zero.
+-
+- The exit code is zero since in case all threads exit by calling
+- 'pthread_exit' the exit status must be 0 (zero). */
+- __exit_thread_inline (0);
+-
+- /* NOTREACHED */
+- return 0;
+-}
+-
+-
+-/* Default thread attributes for the case when the user does not
+- provide any. */
+-static const struct pthread_attr default_attr =
+- {
+- /* Just some value > 0 which gets rounded to the nearest page size. */
+- .guardsize = 1,
+- };
+-
+-
+-int
+-__pthread_create_2_1 (newthread, attr, start_routine, arg)
+- pthread_t *newthread;
+- const pthread_attr_t *attr;
+- void *(*start_routine) (void *);
+- void *arg;
+-{
+- STACK_VARIABLES;
+- const struct pthread_attr *iattr;
+- struct pthread *pd;
+- int err;
+-
+- iattr = (struct pthread_attr *) attr;
+- if (iattr == NULL)
+- /* Is this the best idea? On NUMA machines this could mean
+- accessing far-away memory. */
+- iattr = &default_attr;
+-
+- err = ALLOCATE_STACK (iattr, &pd);
+- if (__builtin_expect (err != 0, 0))
+- /* Something went wrong. Maybe a parameter of the attributes is
+- invalid or we could not allocate memory. */
+- return err;
+-
+-
+- /* Initialize the TCB. All initializations with zero should be
+- performed in 'get_cached_stack'. This way we avoid doing this if
+- the stack freshly allocated with 'mmap'. */
+-
+-#ifdef TLS_TCB_AT_TP
+- /* Reference to the TCB itself. */
+- pd->header.self = pd;
+-
+- /* Self-reference for TLS. */
+- pd->header.tcb = pd;
+-#endif
+-
+- /* Store the address of the start routine and the parameter. Since
+- we do not start the function directly the stillborn thread will
+- get the information from its thread descriptor. */
+- pd->start_routine = start_routine;
+- pd->arg = arg;
+-
+- /* Copy the thread attribute flags. */
+- struct pthread *self = THREAD_SELF;
+- pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
+- | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
+-
+- /* Initialize the field for the ID of the thread which is waiting
+- for us. This is a self-reference in case the thread is created
+- detached. */
+- pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
+-
+- /* The debug events are inherited from the parent. */
+- pd->eventbuf = self->eventbuf;
+-
+-
+- /* Copy the parent's scheduling parameters. The flags will say what
+- is valid and what is not. */
+- pd->schedpolicy = self->schedpolicy;
+- pd->schedparam = self->schedparam;
+-
+- /* Determine scheduling parameters for the thread. */
+- if (attr != NULL
+- && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
+- && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0)
+- {
+- INTERNAL_SYSCALL_DECL (err);
+-
+- /* Use the scheduling parameters the user provided. */
+- if (iattr->flags & ATTR_FLAG_POLICY_SET)
+- pd->schedpolicy = iattr->schedpolicy;
+- else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
+- {
+- pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, err, 1, 0);
+- pd->flags |= ATTR_FLAG_POLICY_SET;
+- }
+-
+- if (iattr->flags & ATTR_FLAG_SCHED_SET)
+- memcpy (&pd->schedparam, &iattr->schedparam,
+- sizeof (struct sched_param));
+- else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
+- {
+- INTERNAL_SYSCALL (sched_getparam, err, 2, 0, &pd->schedparam);
+- pd->flags |= ATTR_FLAG_SCHED_SET;
+- }
+-
+- /* Check for valid priorities. */
+- int minprio = INTERNAL_SYSCALL (sched_get_priority_min, err, 1,
+- iattr->schedpolicy);
+- int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, err, 1,
+- iattr->schedpolicy);
+- if (pd->schedparam.sched_priority < minprio
+- || pd->schedparam.sched_priority > maxprio)
+- {
+- err = EINVAL;
+- goto errout;
+- }
+- }
+-
+- /* Pass the descriptor to the caller. */
+- *newthread = (pthread_t) pd;
+-
+- /* Remember whether the thread is detached or not. In case of an
+- error we have to free the stacks of non-detached stillborn
+- threads. */
+- bool is_detached = IS_DETACHED (pd);
+-
+- /* Start the thread. */
+- err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
+- if (err != 0)
+- {
+- /* Something went wrong. Free the resources. */
+- if (!is_detached)
+- {
+- errout:
+- __deallocate_stack (pd);
+- }
+- return err;
+- }
+-
+- return 0;
+-}
+-versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);
+-
+-
+-#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+-int
+-__pthread_create_2_0 (newthread, attr, start_routine, arg)
+- pthread_t *newthread;
+- const pthread_attr_t *attr;
+- void *(*start_routine) (void *);
+- void *arg;
+-{
+- /* The ATTR attribute is not really of type `pthread_attr_t *'. It has
+- the old size and access to the new members might crash the program.
+- We convert the struct now. */
+- struct pthread_attr new_attr;
+-
+- if (attr != NULL)
+- {
+- struct pthread_attr *iattr = (struct pthread_attr *) attr;
+- size_t ps = __getpagesize ();
+-
+- /* Copy values from the user-provided attributes. */
+- new_attr.schedparam = iattr->schedparam;
+- new_attr.schedpolicy = iattr->schedpolicy;
+- new_attr.flags = iattr->flags;
+-
+- /* Fill in default values for the fields not present in the old
+- implementation. */
+- new_attr.guardsize = ps;
+- new_attr.stackaddr = NULL;
+- new_attr.stacksize = 0;
+- new_attr.cpuset = NULL;
+-
+- /* We will pass this value on to the real implementation. */
+- attr = (pthread_attr_t *) &new_attr;
+- }
+-
+- return __pthread_create_2_1 (newthread, attr, start_routine, arg);
+-}
+-compat_symbol (libpthread, __pthread_create_2_0, pthread_create,
+- GLIBC_2_0);
+-#endif
+-
+-/* Information for libthread_db. */
+-
+-#include "../nptl_db/db_info.c"
+-
+-/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread
+- functions to be present as well. */
+-PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock)
+-PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock)
+-
+-PTHREAD_STATIC_FN_REQUIRE (pthread_once)
+-PTHREAD_STATIC_FN_REQUIRE (pthread_cancel)
+-
+-PTHREAD_STATIC_FN_REQUIRE (pthread_key_create)
+-PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific)
+-PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific)
+diff -x CVS -rupN libc/nptl/sem_open.c libc/nptl/sem_open.c
+--- libc/nptl/sem_open.c 2003-05-31 21:57:50.000000000 +0200
++++ libc/nptl/sem_open.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,404 +0,0 @@
+-/* 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 <errno.h>
+-#include <fcntl.h>
+-#include <mntent.h>
+-#include <paths.h>
+-#include <pthread.h>
+-#include <search.h>
+-#include <semaphore.h>
+-#include <stdarg.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <unistd.h>
+-#include <sys/mman.h>
+-#include <sys/stat.h>
+-#include <sys/statfs.h>
+-#include <linux_fsinfo.h>
+-#include "semaphoreP.h"
+-
+-
+-
+-/* Information about the mount point. */
+-struct mountpoint_info mountpoint attribute_hidden;
+-
+-/* This is the default mount point. */
+-static const char defaultmount[] = "/dev/shm";
+-/* This is the default directory. */
+-static const char defaultdir[] = "/dev/shm/sem.";
+-
+-/* Protect the `mountpoint' variable above. */
+-pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT;
+-
+-
+-/* Determine where the shmfs is mounted (if at all). */
+-void
+-attribute_hidden
+-__where_is_shmfs (void)
+-{
+- char buf[512];
+- struct statfs f;
+- struct mntent resmem;
+- struct mntent *mp;
+- FILE *fp;
+-
+- /* The canonical place is /dev/shm. This is at least what the
+- documentation tells everybody to do. */
+- if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
+- {
+- /* It is in the normal place. */
+- mountpoint.dir = (char *) defaultdir;
+- mountpoint.dirlen = sizeof (defaultdir) - 1;
+-
+- return;
+- }
+-
+- /* OK, do it the hard way. Look through the /proc/mounts file and if
+- this does not exist through /etc/fstab to find the mount point. */
+- fp = __setmntent ("/proc/mounts", "r");
+- if (__builtin_expect (fp == NULL, 0))
+- {
+- fp = __setmntent (_PATH_MNTTAB, "r");
+- if (__builtin_expect (fp == NULL, 0))
+- /* There is nothing we can do. Blind guesses are not helpful. */
+- return;
+- }
+-
+- /* Now read the entries. */
+- while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
+- /* The original name is "shm" but this got changed in early Linux
+- 2.4.x to "tmpfs". */
+- if (strcmp (mp->mnt_type, "tmpfs") == 0
+- || strcmp (mp->mnt_type, "shm") == 0)
+- {
+- /* Found it. There might be more than one place where the
+- filesystem is mounted but one is enough for us. */
+- size_t namelen;
+-
+- /* First make sure this really is the correct entry. At least
+- some versions of the kernel give wrong information because
+- of the implicit mount of the shmfs for SysV IPC. */
+- if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
+- continue;
+-
+- namelen = strlen (mp->mnt_dir);
+-
+- if (namelen == 0)
+- /* Hum, maybe some crippled entry. Keep on searching. */
+- continue;
+-
+- mountpoint.dir = (char *) malloc (namelen + 4 + 2);
+- if (mountpoint.dir != NULL)
+- {
+- char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
+- if (cp[-1] != '/')
+- *cp++ = '/';
+- cp = stpcpy (cp, "sem.");
+- mountpoint.dirlen = cp - mountpoint.dir;
+- }
+-
+- break;
+- }
+-
+- /* Close the stream. */
+- __endmntent (fp);
+-}
+-
+-
+-/* Comparison function for search of existing mapping. */
+-int
+-attribute_hidden
+-__sem_search (const void *a, const void *b)
+-{
+- const struct inuse_sem *as = (const struct inuse_sem *) a;
+- const struct inuse_sem *bs = (const struct inuse_sem *) b;
+-
+- if (as->ino != bs->ino)
+- /* Cannot return the difference the type is larger than int. */
+- return as->ino < bs->ino ? -1 : (as->ino == bs->ino ? 0 : 1);
+-
+- if (as->dev != bs->dev)
+- /* Cannot return the difference the type is larger than int. */
+- return as->dev < bs->dev ? -1 : (as->dev == bs->dev ? 0 : 1);
+-
+- return strcmp (as->name, bs->name);
+-}
+-
+-
+-/* The search tree for existing mappings. */
+-void *__sem_mappings attribute_hidden;
+-
+-/* Lock to protect the search tree. */
+-lll_lock_t __sem_mappings_lock = LLL_LOCK_INITIALIZER;
+-
+-
+-/* Search for existing mapping and if possible add the one provided. */
+-static sem_t *
+-check_add_mapping (const char *name, size_t namelen, int fd, sem_t *existing)
+-{
+- sem_t *result = SEM_FAILED;
+-
+- /* Get the information about the file. */
+- struct stat64 st;
+- if (__fxstat64 (_STAT_VER, fd, &st) == 0)
+- {
+- /* Get the lock. */
+- lll_lock (__sem_mappings_lock);
+-
+- /* Search for an existing mapping given the information we have. */
+- struct inuse_sem *fake;
+- fake = (struct inuse_sem *) alloca (sizeof (*fake) + namelen);
+- memcpy (fake->name, name, namelen);
+- fake->dev = st.st_dev;
+- fake->ino = st.st_ino;
+-
+- struct inuse_sem **foundp = tfind (fake, &__sem_mappings, __sem_search);
+- if (foundp != NULL)
+- {
+- /* There is already a mapping. Use it. */
+- result = (*foundp)->sem;
+- ++(*foundp)->refcnt;
+- }
+- else
+- {
+- /* We haven't found a mapping. Install ione. */
+- struct inuse_sem *newp;
+-
+- newp = (struct inuse_sem *) malloc (sizeof (*newp) + namelen);
+- if (newp != NULL)
+- {
+- /* If the caller hasn't provided any map it now. */
+- if (existing == SEM_FAILED)
+- existing = (sem_t *) mmap (NULL, sizeof (sem_t),
+- PROT_READ | PROT_WRITE, MAP_SHARED,
+- fd, 0);
+-
+- newp->dev = st.st_dev;
+- newp->ino = st.st_ino;
+- newp->refcnt = 1;
+- newp->sem = existing;
+- memcpy (newp->name, name, namelen);
+-
+- /* Insert the new value. */
+- if (existing != MAP_FAILED
+- && tsearch (newp, &__sem_mappings, __sem_search) != NULL)
+- /* Successful. */
+- result = existing;
+- else
+- /* Something went wrong while inserting the new
+- value. We fail completely. */
+- free (newp);
+- }
+- }
+-
+- /* Release the lock. */
+- lll_unlock (__sem_mappings_lock);
+- }
+-
+- if (result != existing && existing != SEM_FAILED && existing != MAP_FAILED)
+- {
+- /* Do not disturb errno. */
+- INTERNAL_SYSCALL_DECL (err);
+- INTERNAL_SYSCALL (munmap, err, 2, existing, sizeof (sem_t));
+- }
+-
+- return result;
+-}
+-
+-
+-sem_t *
+-sem_open (const char *name, int oflag, ...)
+-{
+- char *finalname;
+- sem_t *result = SEM_FAILED;
+- int fd;
+-
+- /* Determine where the shmfs is mounted. */
+- INTUSE(__pthread_once) (&__namedsem_once, __where_is_shmfs);
+-
+- /* If we don't know the mount points there is nothing we can do. Ever. */
+- if (mountpoint.dir == NULL)
+- {
+- __set_errno (ENOSYS);
+- return SEM_FAILED;
+- }
+-
+- /* Construct the filename. */
+- while (name[0] == '/')
+- ++name;
+-
+- if (name[0] == '\0')
+- {
+- /* The name "/" is not supported. */
+- __set_errno (EINVAL);
+- return SEM_FAILED;
+- }
+- size_t namelen = strlen (name) + 1;
+-
+- /* Create the name of the final file. */
+- finalname = (char *) alloca (mountpoint.dirlen + namelen);
+- __mempcpy (__mempcpy (finalname, mountpoint.dir, mountpoint.dirlen),
+- name, namelen);
+-
+- /* If the semaphore object has to exist simply open it. */
+- if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0)
+- {
+- try_again:
+- fd = __libc_open (finalname,
+- (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR);
+-
+- if (fd == -1)
+- {
+- /* If we are supposed to create the file try this next. */
+- if ((oflag & O_CREAT) != 0 && errno == ENOENT)
+- goto try_create;
+-
+- /* Return. errno is already set. */
+- }
+- else
+- /* Check whether we already have this semaphore mapped and
+- create one if necessary. */
+- result = check_add_mapping (name, namelen, fd, SEM_FAILED);
+- }
+- else
+- {
+- /* We have to open a temporary file first since it must have the
+- correct form before we can start using it. */
+- char *tmpfname;
+- mode_t mode;
+- unsigned int value;
+- va_list ap;
+-
+- try_create:
+- va_start (ap, oflag);
+-
+- mode = va_arg (ap, mode_t);
+- value = va_arg (ap, unsigned int);
+-
+- va_end (ap);
+-
+- if (value > SEM_VALUE_MAX)
+- {
+- __set_errno (EINVAL);
+- return SEM_FAILED;
+- }
+-
+- /* Create the initial file content. */
+- sem_t initsem;
+-
+- struct sem *iinitsem = (struct sem *) &initsem;
+- iinitsem->count = value;
+-
+- /* Initialize the remaining bytes as well. */
+- memset ((char *) &initsem + sizeof (struct sem), '\0',
+- sizeof (sem_t) - sizeof (struct sem));
+-
+- tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
+- char *xxxxxx = __mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen);
+-
+- int retries = 0;
+-#define NRETRIES 50
+- while (1)
+- {
+- /* Add the suffix for mktemp. */
+- strcpy (xxxxxx, "XXXXXX");
+-
+- /* We really want to use mktemp here. We cannot use mkstemp
+- since the file must be opened with a specific mode. The
+- mode cannot later be set since then we cannot apply the
+- file create mask. */
+- if (mktemp (tmpfname) == NULL)
+- return SEM_FAILED;
+-
+- /* Open the file. Make sure we do not overwrite anything. */
+- fd = __libc_open (tmpfname, O_RDWR | O_CREAT | O_EXCL, mode);
+- if (fd == -1)
+- {
+- if (errno == EEXIST)
+- {
+- if (++retries < NRETRIES)
+- continue;
+-
+- __set_errno (EAGAIN);
+- }
+-
+- return SEM_FAILED;
+- }
+-
+- /* We got a file. */
+- break;
+- }
+-
+- if (TEMP_FAILURE_RETRY (__libc_write (fd, &initsem, sizeof (sem_t)))
+- == sizeof (sem_t)
+- /* Map the sem_t structure from the file. */
+- && (result = (sem_t *) mmap (NULL, sizeof (sem_t),
+- PROT_READ | PROT_WRITE, MAP_SHARED,
+- fd, 0)) != MAP_FAILED)
+- {
+- /* Create the file. Don't overwrite an existing file. */
+- if (link (tmpfname, finalname) != 0)
+- {
+- /* Undo the mapping. */
+- (void) munmap (result, sizeof (sem_t));
+-
+- /* Reinitialize 'result'. */
+- result = SEM_FAILED;
+-
+- /* This failed. If O_EXCL is not set and the problem was
+- that the file exists, try again. */
+- if ((oflag & O_EXCL) == 0 && errno == EEXIST)
+- {
+- /* Remove the file. */
+- (void) unlink (tmpfname);
+-
+- /* Close the file. */
+- (void) __libc_close (fd);
+-
+- goto try_again;
+- }
+- }
+- else
+- /* Insert the mapping into the search tree. This also
+- determines whether another thread sneaked by and already
+- added such a mapping despite the fact that we created it. */
+- result = check_add_mapping (name, namelen, fd, result);
+- }
+-
+- /* Now remove the temporary name. This should never fail. If
+- it fails we leak a file name. Better fix the kernel. */
+- (void) unlink (tmpfname);
+- }
+-
+- /* Map the mmap error to the error we need. */
+- if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED)
+- result = SEM_FAILED;
+-
+- /* We don't need the file descriptor anymore. */
+- if (fd != -1)
+- {
+- /* Do not disturb errno. */
+- INTERNAL_SYSCALL_DECL (err);
+- INTERNAL_SYSCALL (close, err, 1, fd);
+- }
+-
+- return result;
+-}
+diff -x CVS -rupN libc/nptl/sysdeps/i386/pthreaddef.h libc/nptl/sysdeps/i386/pthreaddef.h
+--- libc/nptl/sysdeps/i386/pthreaddef.h 2003-03-25 20:19:43.000000000 +0100
++++ libc/nptl/sysdeps/i386/pthreaddef.h 2005-01-23 19:35:29.000000000 +0100
+@@ -35,6 +35,8 @@
+ #define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+
++#if 0
++
+ /* XXX Until we have a better place keep the definitions here. */
+
+ /* While there is no such syscall. */
+@@ -46,3 +48,5 @@
+ asm volatile ("movl %1, %%ebx; int $0x80" \
+ :: "a" (__NR_exit), "r" (val)); \
+ }
++
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/allocatestack.c libc/nptl/sysdeps/l4/hurd/allocatestack.c
+--- libc/nptl/sysdeps/l4/hurd/allocatestack.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/allocatestack.c 2005-01-23 20:02:13.000000000 +0100
+@@ -0,0 +1,949 @@
++/* Copyright (C) 2002, 2003, 2004 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 <assert.h>
++#include <errno.h>
++#include <signal.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/mman.h>
++#include <sys/param.h>
++#include <dl-sysdep.h>
++#include <tls.h>
++#include <lowlevellock.h>
++
++
++#ifndef NEED_SEPARATE_REGISTER_STACK
++
++/* Most architectures have exactly one stack pointer. Some have more. */
++# define STACK_VARIABLES void *stackaddr
++
++/* How to pass the values to the 'create_thread' function. */
++# define STACK_VARIABLES_ARGS stackaddr
++
++/* How to declare function which gets there parameters. */
++# define STACK_VARIABLES_PARMS void *stackaddr
++
++/* How to declare allocate_stack. */
++# define ALLOCATE_STACK_PARMS void **stack
++
++/* This is how the function is called. We do it this way to allow
++ other variants of the function to have more parameters. */
++# define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
++
++#else
++
++/* We need two stacks. The kernel will place them but we have to tell
++ the kernel about the size of the reserved address space. */
++# define STACK_VARIABLES void *stackaddr; size_t stacksize
++
++/* How to pass the values to the 'create_thread' function. */
++# define STACK_VARIABLES_ARGS stackaddr, stacksize
++
++/* How to declare function which gets there parameters. */
++# define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize
++
++/* How to declare allocate_stack. */
++# define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize
++
++/* This is how the function is called. We do it this way to allow
++ other variants of the function to have more parameters. */
++# define ALLOCATE_STACK(attr, pd) \
++ allocate_stack (attr, pd, &stackaddr, &stacksize)
++
++#endif
++
++
++/* Default alignment of stack. */
++#ifndef STACK_ALIGN
++# define STACK_ALIGN __alignof__ (long double)
++#endif
++
++/* Default value for minimal stack size after allocating thread
++ descriptor and guard. */
++#ifndef MINIMAL_REST_STACK
++# define MINIMAL_REST_STACK 4096
++#endif
++
++
++/* Let the architecture add some flags to the mmap() call used to
++ allocate stacks. */
++#ifndef ARCH_MAP_FLAGS
++# define ARCH_MAP_FLAGS 0
++#endif
++
++/* This yields the pointer that TLS support code calls the thread pointer. */
++#if TLS_TCB_AT_TP
++# define TLS_TPADJ(pd) (pd)
++#elif TLS_DTV_AT_TP
++# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE))
++#endif
++
++/* Cache handling for not-yet free stacks. */
++
++/* Maximum size in kB of cache. */
++static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */
++static size_t stack_cache_actsize;
++
++/* Mutex protecting this variable. */
++static lll_lock_t stack_cache_lock = LLL_LOCK_INITIALIZER;
++
++/* List of queued stack frames. */
++static LIST_HEAD (stack_cache);
++
++/* List of the stacks in use. */
++static LIST_HEAD (stack_used);
++
++/* List of the threads with user provided stacks in use. No need to
++ initialize this, since it's done in __pthread_initialize_minimal. */
++list_t __stack_user __attribute__ ((nocommon));
++hidden_data_def (__stack_user)
++
++#if COLORING_INCREMENT != 0
++/* Number of threads created. */
++static unsigned int nptl_ncreated;
++#endif
++
++
++/* Check whether the stack is still used or not. */
++#define FREE_P(descr) ((descr)->tid <= 0)
++
++
++/* We create a double linked list of all cache entries. Double linked
++ because this allows removing entries from the end. */
++
++
++/* Get a stack frame from the cache. We have to match by size since
++ some blocks might be too small or far too large. */
++static struct pthread *
++get_cached_stack (size_t *sizep, void **memp)
++{
++ size_t size = *sizep;
++ struct pthread *result = NULL;
++ list_t *entry;
++
++ lll_lock (stack_cache_lock);
++
++ /* Search the cache for a matching entry. We search for the
++ smallest stack which has at least the required size. Note that
++ in normal situations the size of all allocated stacks is the
++ same. As the very least there are only a few different sizes.
++ Therefore this loop will exit early most of the time with an
++ exact match. */
++ list_for_each (entry, &stack_cache)
++ {
++ struct pthread *curr;
++
++ curr = list_entry (entry, struct pthread, list);
++ if (FREE_P (curr) && curr->stackblock_size >= size)
++ {
++ if (curr->stackblock_size == size)
++ {
++ result = curr;
++ break;
++ }
++
++ if (result == NULL
++ || result->stackblock_size > curr->stackblock_size)
++ result = curr;
++ }
++ }
++
++ if (__builtin_expect (result == NULL, 0)
++ /* Make sure the size difference is not too excessive. In that
++ case we do not use the block. */
++ || __builtin_expect (result->stackblock_size > 4 * size, 0))
++ {
++ /* Release the lock. */
++ lll_unlock (stack_cache_lock);
++
++ return NULL;
++ }
++
++ /* Dequeue the entry. */
++ list_del (&result->list);
++
++ /* And add to the list of stacks in use. */
++ list_add (&result->list, &stack_used);
++
++ /* And decrease the cache size. */
++ stack_cache_actsize -= result->stackblock_size;
++
++ /* Release the lock early. */
++ lll_unlock (stack_cache_lock);
++
++ /* Report size and location of the stack to the caller. */
++ *sizep = result->stackblock_size;
++ *memp = result->stackblock;
++
++ /* Cancellation handling is back to the default. */
++ result->cancelhandling = 0;
++ result->cleanup = NULL;
++
++ /* No pending event. */
++ result->nextevent = NULL;
++
++ /* Clear the DTV. */
++ dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
++ memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
++
++ /* Re-initialize the TLS. */
++ _dl_allocate_tls_init (TLS_TPADJ (result));
++
++ return result;
++}
++
++
++/* Add a stack frame which is not used anymore to the stack. Must be
++ called with the cache lock held. */
++static inline void
++__attribute ((always_inline))
++queue_stack (struct pthread *stack)
++{
++ /* We unconditionally add the stack to the list. The memory may
++ still be in use but it will not be reused until the kernel marks
++ the stack as not used anymore. */
++ list_add (&stack->list, &stack_cache);
++
++ stack_cache_actsize += stack->stackblock_size;
++ if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0))
++ {
++ /* We reduce the size of the cache. Remove the last entries
++ until the size is below the limit. */
++ list_t *entry;
++ list_t *prev;
++
++ /* Search from the end of the list. */
++ list_for_each_prev_safe (entry, prev, &stack_cache)
++ {
++ struct pthread *curr;
++
++ curr = list_entry (entry, struct pthread, list);
++ if (FREE_P (curr))
++ {
++ /* Unlink the block. */
++ list_del (entry);
++
++ /* Account for the freed memory. */
++ stack_cache_actsize -= curr->stackblock_size;
++
++ /* Free the memory associated with the ELF TLS. */
++ _dl_deallocate_tls (TLS_TPADJ (curr), false);
++
++ /* Remove this block. This should never fail. If it
++ does something is really wrong. */
++ if (munmap (curr->stackblock, curr->stackblock_size) != 0)
++ abort ();
++
++ /* Maybe we have freed enough. */
++ if (stack_cache_actsize <= stack_cache_maxsize)
++ break;
++ }
++ }
++ }
++}
++
++
++static int
++internal_function
++change_stack_perm (struct pthread *pd
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , size_t pagemask
++#endif
++ )
++{
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ void *stack = (pd->stackblock
++ + (((((pd->stackblock_size - pd->guardsize) / 2)
++ & pagemask) + pd->guardsize) & pagemask));
++ size_t len = pd->stackblock + pd->stackblock_size - stack;
++#else
++ void *stack = pd->stackblock + pd->guardsize;
++ size_t len = pd->stackblock_size - pd->guardsize;
++#endif
++ if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
++ return errno;
++
++ return 0;
++}
++
++
++static int
++allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
++ ALLOCATE_STACK_PARMS)
++{
++ struct pthread *pd;
++ size_t size;
++ size_t pagesize_m1 = __getpagesize () - 1;
++ void *stacktop;
++
++ assert (attr != NULL);
++ assert (powerof2 (pagesize_m1 + 1));
++ assert (TCB_ALIGNMENT >= STACK_ALIGN);
++
++ /* Get the stack size from the attribute if it is set. Otherwise we
++ use the default we determined at start time. */
++ size = attr->stacksize ?: __default_stacksize;
++
++ /* Get memory for the stack. */
++ if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
++ {
++ uintptr_t adj;
++
++ /* If the user also specified the size of the stack make sure it
++ is large enough. */
++ if (attr->stacksize != 0
++ && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK))
++ return EINVAL;
++
++ /* Adjust stack size for alignment of the TLS block. */
++#if TLS_TCB_AT_TP
++ adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE)
++ & __static_tls_align_m1;
++ assert (size > adj + TLS_TCB_SIZE);
++#elif TLS_DTV_AT_TP
++ adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
++ & __static_tls_align_m1;
++ assert (size > adj);
++#endif
++
++ /* The user provided some memory. Let's hope it matches the
++ size... We do not allocate guard pages if the user provided
++ the stack. It is the user's responsibility to do this if it
++ is wanted. */
++#if TLS_TCB_AT_TP
++ pd = (struct pthread *) ((uintptr_t) attr->stackaddr
++ - TLS_TCB_SIZE - adj);
++#elif TLS_DTV_AT_TP
++ pd = (struct pthread *) (((uintptr_t) attr->stackaddr
++ - __static_tls_size - adj)
++ - TLS_PRE_TCB_SIZE);
++#endif
++
++ /* The user provided stack memory needs to be cleared. */
++ memset (pd, '\0', sizeof (struct pthread));
++
++ /* The first TSD block is included in the TCB. */
++ pd->specific[0] = pd->specific_1stblock;
++
++ /* Remember the stack-related values. */
++ pd->stackblock = (char *) attr->stackaddr - size;
++ pd->stackblock_size = size;
++
++ /* This is a user-provided stack. It will not be queued in the
++ stack cache nor will the memory (except the TLS memory) be freed. */
++ pd->user_stack = true;
++
++ /* This is at least the second thread. */
++ pd->header.multiple_threads = 1;
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++ __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
++#endif
++
++#ifdef NEED_DL_SYSINFO
++ /* Copy the sysinfo value from the parent. */
++ THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
++#endif
++
++ /* The process ID is also the same as that of the caller. */
++ pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
++
++ /* Allocate the DTV for this thread. */
++ if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
++ {
++ /* Something went wrong. */
++ assert (errno == ENOMEM);
++ return EAGAIN;
++ }
++
++
++ /* Prepare to modify global data. */
++ lll_lock (stack_cache_lock);
++
++ /* And add to the list of stacks in use. */
++ list_add (&pd->list, &__stack_user);
++
++ lll_unlock (stack_cache_lock);
++ }
++ else
++ {
++ /* Allocate some anonymous memory. If possible use the cache. */
++ size_t guardsize;
++ size_t reqsize;
++ void *mem;
++ const int prot = (PROT_READ | PROT_WRITE
++ | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
++
++#if COLORING_INCREMENT != 0
++ /* Add one more page for stack coloring. Don't do it for stacks
++ with 16 times pagesize or larger. This might just cause
++ unnecessary misalignment. */
++ if (size <= 16 * pagesize_m1)
++ size += pagesize_m1 + 1;
++#endif
++
++ /* Adjust the stack size for alignment. */
++ size &= ~__static_tls_align_m1;
++ assert (size != 0);
++
++ /* Make sure the size of the stack is enough for the guard and
++ eventually the thread descriptor. */
++ guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1;
++ if (__builtin_expect (size < (guardsize + __static_tls_size
++ + MINIMAL_REST_STACK + pagesize_m1 + 1),
++ 0))
++ /* The stack is too small (or the guard too large). */
++ return EINVAL;
++
++ /* Try to get a stack from the cache. */
++ reqsize = size;
++ pd = get_cached_stack (&size, &mem);
++ if (pd == NULL)
++ {
++ /* To avoid aliasing effects on a larger scale than pages we
++ adjust the allocated stack size if necessary. This way
++ allocations directly following each other will not have
++ aliasing problems. */
++#if MULTI_PAGE_ALIASING != 0
++ if ((size % MULTI_PAGE_ALIASING) == 0)
++ size += pagesize_m1 + 1;
++#endif
++
++ mem = mmap (NULL, size, prot,
++ MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0);
++
++ if (__builtin_expect (mem == MAP_FAILED, 0))
++ {
++#ifdef ARCH_RETRY_MMAP
++ mem = ARCH_RETRY_MMAP (size);
++ if (__builtin_expect (mem == MAP_FAILED, 0))
++#endif
++ return errno;
++ }
++
++ /* SIZE is guaranteed to be greater than zero.
++ So we can never get a null pointer back from mmap. */
++ assert (mem != NULL);
++
++#if COLORING_INCREMENT != 0
++ /* Atomically increment NCREATED. */
++ unsigned int ncreated = atomic_increment_val (&nptl_ncreated);
++
++ /* We chose the offset for coloring by incrementing it for
++ every new thread by a fixed amount. The offset used
++ module the page size. Even if coloring would be better
++ relative to higher alignment values it makes no sense to
++ do it since the mmap() interface does not allow us to
++ specify any alignment for the returned memory block. */
++ size_t coloring = (ncreated * COLORING_INCREMENT) & pagesize_m1;
++
++ /* Make sure the coloring offsets does not disturb the alignment
++ of the TCB and static TLS block. */
++ if (__builtin_expect ((coloring & __static_tls_align_m1) != 0, 0))
++ coloring = (((coloring + __static_tls_align_m1)
++ & ~(__static_tls_align_m1))
++ & ~pagesize_m1);
++#else
++ /* Unless specified we do not make any adjustments. */
++# define coloring 0
++#endif
++
++ /* Place the thread descriptor at the end of the stack. */
++#if TLS_TCB_AT_TP
++ pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
++#elif TLS_DTV_AT_TP
++ pd = (struct pthread *) ((((uintptr_t) mem + size - coloring
++ - __static_tls_size)
++ & ~__static_tls_align_m1)
++ - TLS_PRE_TCB_SIZE);
++#endif
++
++ /* Remember the stack-related values. */
++ pd->stackblock = mem;
++ pd->stackblock_size = size;
++
++ /* We allocated the first block thread-specific data array.
++ This address will not change for the lifetime of this
++ descriptor. */
++ pd->specific[0] = pd->specific_1stblock;
++
++ /* This is at least the second thread. */
++ pd->header.multiple_threads = 1;
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++ __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
++#endif
++
++#ifdef NEED_DL_SYSINFO
++ /* Copy the sysinfo value from the parent. */
++ THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
++#endif
++
++ /* The process ID is also the same as that of the caller. */
++ pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
++
++ /* Allocate the DTV for this thread. */
++ if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
++ {
++ /* Something went wrong. */
++ assert (errno == ENOMEM);
++
++ /* Free the stack memory we just allocated. */
++ (void) munmap (mem, size);
++
++ return EAGAIN;
++ }
++
++
++ /* Prepare to modify global data. */
++ lll_lock (stack_cache_lock);
++
++ /* And add to the list of stacks in use. */
++ list_add (&pd->list, &stack_used);
++
++ lll_unlock (stack_cache_lock);
++
++
++ /* There might have been a race. Another thread might have
++ caused the stacks to get exec permission while this new
++ stack was prepared. Detect if this was possible and
++ change the permission if necessary. */
++ if (__builtin_expect ((GL(dl_stack_flags) & PF_X) != 0
++ && (prot & PROT_EXEC) == 0, 0))
++ {
++ int err = change_stack_perm (pd
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , ~pagesize_m1
++#endif
++ );
++ if (err != 0)
++ {
++ /* Free the stack memory we just allocated. */
++ (void) munmap (mem, size);
++
++ return err;
++ }
++ }
++
++
++ /* Note that all of the stack and the thread descriptor is
++ zeroed. This means we do not have to initialize fields
++ with initial value zero. This is specifically true for
++ the 'tid' field which is always set back to zero once the
++ stack is not used anymore and for the 'guardsize' field
++ which will be read next. */
++ }
++
++ /* Create or resize the guard area if necessary. */
++ if (__builtin_expect (guardsize > pd->guardsize, 0))
++ {
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
++#else
++ char *guard = mem;
++#endif
++ if (mprotect (guard, guardsize, PROT_NONE) != 0)
++ {
++ int err;
++ mprot_error:
++ err = errno;
++
++ lll_lock (stack_cache_lock);
++
++ /* Remove the thread from the list. */
++ list_del (&pd->list);
++
++ lll_unlock (stack_cache_lock);
++
++ /* Get rid of the TLS block we allocated. */
++ _dl_deallocate_tls (TLS_TPADJ (pd), false);
++
++ /* Free the stack memory regardless of whether the size
++ of the cache is over the limit or not. If this piece
++ of memory caused problems we better do not use it
++ anymore. Uh, and we ignore possible errors. There
++ is nothing we could do. */
++ (void) munmap (mem, size);
++
++ return err;
++ }
++
++ pd->guardsize = guardsize;
++ }
++ else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize,
++ 0))
++ {
++ /* The old guard area is too large. */
++
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
++ char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1);
++
++ if (oldguard < guard
++ && mprotect (oldguard, guard - oldguard, prot) != 0)
++ goto mprot_error;
++
++ if (mprotect (guard + guardsize,
++ oldguard + pd->guardsize - guard - guardsize,
++ prot) != 0)
++ goto mprot_error;
++#else
++ if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
++ prot) != 0)
++ goto mprot_error;
++#endif
++
++ pd->guardsize = guardsize;
++ }
++ /* The pthread_getattr_np() calls need to get passed the size
++ requested in the attribute, regardless of how large the
++ actually used guardsize is. */
++ pd->reported_guardsize = guardsize;
++ }
++
++ /* Initialize the lock. We have to do this unconditionally since the
++ stillborn thread could be canceled while the lock is taken. */
++ pd->lock = LLL_LOCK_INITIALIZER;
++
++ /* We place the thread descriptor at the end of the stack. */
++ *pdp = pd;
++
++#if TLS_TCB_AT_TP
++ /* The stack begins before the TCB and the static TLS block. */
++ stacktop = ((char *) (pd + 1) - __static_tls_size);
++#elif TLS_DTV_AT_TP
++ stacktop = (char *) (pd - 1);
++#endif
++
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ *stack = pd->stackblock;
++ *stacksize = stacktop - *stack;
++#else
++ *stack = stacktop;
++#endif
++
++ return 0;
++}
++
++
++void
++internal_function
++__deallocate_stack (struct pthread *pd)
++{
++ lll_lock (stack_cache_lock);
++
++ /* Remove the thread from the list of threads with user defined
++ stacks. */
++ list_del (&pd->list);
++
++ /* Not much to do. Just free the mmap()ed memory. Note that we do
++ not reset the 'used' flag in the 'tid' field. This is done by
++ the kernel. If no thread has been created yet this field is
++ still zero. */
++ if (__builtin_expect (! pd->user_stack, 1))
++ (void) queue_stack (pd);
++ else
++ /* Free the memory associated with the ELF TLS. */
++ _dl_deallocate_tls (TLS_TPADJ (pd), false);
++
++ lll_unlock (stack_cache_lock);
++}
++
++
++int
++internal_function
++__make_stacks_executable (void **stack_endp)
++{
++ /* First the main thread's stack. */
++ int err = _dl_make_stack_executable (stack_endp);
++ if (err != 0)
++ return err;
++
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ const size_t pagemask = ~(__getpagesize () - 1);
++#endif
++
++ lll_lock (stack_cache_lock);
++
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ err = change_stack_perm (list_entry (runp, struct pthread, list)
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , pagemask
++#endif
++ );
++ if (err != 0)
++ break;
++ }
++
++ /* Also change the permission for the currently unused stacks. This
++ might be wasted time but better spend it here than adding a check
++ in the fast path. */
++ if (err == 0)
++ list_for_each (runp, &stack_cache)
++ {
++ err = change_stack_perm (list_entry (runp, struct pthread, list)
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , pagemask
++#endif
++ );
++ if (err != 0)
++ break;
++ }
++
++ lll_unlock (stack_cache_lock);
++
++ return err;
++}
++
++
++/* In case of a fork() call the memory allocation in the child will be
++ the same but only one thread is running. All stacks except that of
++ the one running thread are not used anymore. We have to recycle
++ them. */
++void
++__reclaim_stacks (void)
++{
++ struct pthread *self = (struct pthread *) THREAD_SELF;
++
++ /* No locking necessary. The caller is the only stack in use. */
++
++ /* Mark all stacks except the still running one as free. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (runp, struct pthread, list);
++ if (curp != self)
++ {
++ /* This marks the stack as free. */
++ curp->tid = 0;
++
++ /* The PID field must be initialized for the new process. */
++ curp->pid = self->pid;
++
++ /* Account for the size of the stack. */
++ stack_cache_actsize += curp->stackblock_size;
++ }
++ }
++
++ /* Add the stack of all running threads to the cache. */
++ list_splice (&stack_used, &stack_cache);
++
++ /* Remove the entry for the current thread to from the cache list
++ and add it to the list of running threads. Which of the two
++ lists is decided by the user_stack flag. */
++ list_del (&self->list);
++
++ /* Re-initialize the lists for all the threads. */
++ INIT_LIST_HEAD (&stack_used);
++ INIT_LIST_HEAD (&__stack_user);
++
++ if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0))
++ list_add (&self->list, &__stack_user);
++ else
++ list_add (&self->list, &stack_used);
++
++ /* There is one thread running. */
++ __nptl_nthreads = 1;
++
++ /* Initialize the lock. */
++ stack_cache_lock = LLL_LOCK_INITIALIZER;
++}
++
++
++#if HP_TIMING_AVAIL
++# undef __find_thread_by_id
++/* Find a thread given the thread ID. */
++attribute_hidden
++struct pthread *
++__find_thread_by_id (pid_t tid)
++{
++ struct pthread *result = NULL;
++
++ lll_lock (stack_cache_lock);
++
++ /* Iterate over the list with system-allocated threads first. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (runp, struct pthread, list);
++
++ if (curp->tid == tid)
++ {
++ result = curp;
++ goto out;
++ }
++ }
++
++ /* Now the list with threads using user-allocated stacks. */
++ list_for_each (runp, &__stack_user)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (runp, struct pthread, list);
++
++ if (curp->tid == tid)
++ {
++ result = curp;
++ goto out;
++ }
++ }
++
++ out:
++ lll_unlock (stack_cache_lock);
++
++ return result;
++}
++#endif
++
++int
++attribute_hidden
++__nptl_setxid (struct xid_command *cmdp)
++{
++#if 0
++ int result;
++ lll_lock (stack_cache_lock);
++
++ __xidcmd = cmdp;
++ cmdp->cntr = 0;
++
++ INTERNAL_SYSCALL_DECL (err);
++
++ struct pthread *self = THREAD_SELF;
++
++ /* Iterate over the list with system-allocated threads first. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t != self)
++ {
++ int val;
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
++#endif
++
++ if (!INTERNAL_SYSCALL_ERROR_P (val, err))
++ atomic_increment (&cmdp->cntr);
++ }
++ }
++
++ /* Now the list with threads using user-allocated stacks. */
++ list_for_each (runp, &__stack_user)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t != self)
++ {
++ int val;
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
++#endif
++
++ if (!INTERNAL_SYSCALL_ERROR_P (val, err))
++ atomic_increment (&cmdp->cntr);
++ }
++ }
++
++ int cur = cmdp->cntr;
++ while (cur != 0)
++ {
++ lll_futex_wait (&cmdp->cntr, cur);
++ cur = cmdp->cntr;
++ }
++
++ /* This must be last, otherwise the current thread might not have
++ permissions to send SIGSETXID syscall to the other threads. */
++ result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3,
++ cmdp->id[0], cmdp->id[1], cmdp->id[2]);
++ if (INTERNAL_SYSCALL_ERROR_P (result, err))
++ {
++ __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
++ result = -1;
++ }
++
++ lll_unlock (stack_cache_lock);
++ return result;
++#endif
++}
++
++static inline void __attribute__((always_inline))
++init_one_static_tls (struct pthread *curp, struct link_map *map)
++{
++ dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
++# if TLS_TCB_AT_TP
++ void *dest = (char *) curp - map->l_tls_offset;
++# elif TLS_DTV_AT_TP
++ void *dest = (char *) curp + 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);
++}
++
++void
++attribute_hidden
++__pthread_init_static_tls (struct link_map *map)
++{
++ lll_lock (stack_cache_lock);
++
++ /* Iterate over the list with system-allocated threads first. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ init_one_static_tls (list_entry (runp, struct pthread, list), map);
++
++ /* Now the list with threads using user-allocated stacks. */
++ list_for_each (runp, &__stack_user)
++ init_one_static_tls (list_entry (runp, struct pthread, list), map);
++
++ lll_unlock (stack_cache_lock);
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/bits/local_lim.h libc/nptl/sysdeps/l4/hurd/bits/local_lim.h
+--- libc/nptl/sysdeps/l4/hurd/bits/local_lim.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/bits/local_lim.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,71 @@
++/* Minimum guaranteed maximum values for system limits. Hurd version.
++ Copyright (C) 1993,94,96,98,2002 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* GNU has no arbitrary fixed limits on most of these things, so we
++ don't define the macros. Some things are unlimited. Some are in
++ fact limited but the limit is run-time dependent and fetched with
++ `sysconf' or `pathconf'. */
++
++/* This one value is actually constrained by the `struct dirent'
++ layout, in which the `d_namlen' member is only 8 bits wide. */
++
++#define NAME_MAX 255
++
++/* POSIX.1 requires that we define NGROUPS_MAX (though none of the others
++ is required). GNU allows any number of supplementary groups,
++ dynamically allocated. So we pick a number which seems vaguely
++ suitable, and `sysconf' will return a number at least as large. */
++
++#define NGROUPS_MAX 256
++
++/* The maximum number of symbolic links that are allowed in a single file
++ name resolution. When a further link is encountered, the call returns
++ ELOOP. This name is a GNU extension; POSIX.1 has no such limit, and BSD
++ calls it MAXSYMLINKS in <sys/param.h>. (We define the name under
++ _BSD_SOURCE even without _GNU_SOURCE because our <sys/param.h> uses it
++ to define MAXSYMLINKS.) */
++
++#if defined __USE_GNU || defined __USE_BSD /* 1003.1a defines this */
++#define SYMLOOP_MAX 8
++#endif
++
++/* The number of data keys per process. */
++#define _POSIX_THREAD_KEYS_MAX 128
++/* This is the value this implementation supports. */
++#define PTHREAD_KEYS_MAX 1024
++
++/* Controlling the iterations of destructors for thread-specific data. */
++#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
++/* Number of iterations this implementation does. */
++#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
++
++/* The number of threads per process. */
++#define _POSIX_THREAD_THREADS_MAX 64
++/* We have no predefined limit on the number of threads. */
++#undef PTHREAD_THREADS_MAX
++
++/* Maximum amount by which a process can descrease its asynchronous I/O
++ priority level. */
++#define AIO_PRIO_DELTA_MAX 20
++
++/* Minimum size for a thread. We are free to choose a reasonable value. */
++#define PTHREAD_STACK_MIN 16384
++
++/* Maximum number of timer expiration overruns. */
++#define DELAYTIMER_MAX 2147483647
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/createthread.c libc/nptl/sysdeps/l4/hurd/createthread.c
+--- libc/nptl/sysdeps/l4/hurd/createthread.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/createthread.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,266 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <sched.h>
++#include <setjmp.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <atomic.h>
++#include <ldsodefs.h>
++#include <tls.h>
++
++#if 0
++#include "kernel-features.h"
++#endif
++
++#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
++
++/* Unless otherwise specified, the thread "register" is going to be
++ initialized with a pointer to the TCB. */
++#ifndef TLS_VALUE
++# define TLS_VALUE pd
++#endif
++
++#ifndef ARCH_CLONE
++# define ARCH_CLONE __clone
++#endif
++
++
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++/* Variable set to a nonzero value if more than one thread runs or ran. */
++int __pthread_multiple_threads attribute_hidden;
++/* Pointer to the corresponding variable in libc. */
++int *__libc_multiple_threads_ptr attribute_hidden;
++#endif
++
++
++static int
++do_clone (struct pthread *pd, const struct pthread_attr *attr,
++ int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS,
++ int stopped)
++{
++#ifdef PREPARE_CREATE
++ PREPARE_CREATE;
++#endif
++
++ if (stopped)
++ /* We Make sure the thread does not run far by forcing it to get a
++ lock. We lock it here too so that the new thread cannot continue
++ until we tell it to. */
++ lll_lock (pd->lock);
++
++ /* One more thread. We cannot have the thread do this itself, since it
++ might exist but not have been scheduled yet by the time we've returned
++ and need to check the value to behave correctly. We must do it before
++ creating the thread, in case it does get scheduled first and then
++ might mistakenly think it was the only thread. In the failure case,
++ we momentarily store a false value; this doesn't matter because there
++ is no kosher thing a signal handler interrupting us right here can do
++ that cares whether the thread count is correct. */
++ atomic_increment (&__nptl_nthreads);
++
++ if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
++ pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
++ {
++ atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */
++
++ /* Failed. If the thread is detached, remove the TCB here since
++ the caller cannot do this. The caller remembered the thread
++ as detached and cannot reverify that it is not since it must
++ not access the thread descriptor again. */
++ if (IS_DETACHED (pd))
++ __deallocate_stack (pd);
++
++ return errno;
++ }
++
++#if 0
++ /* Now we have the possibility to set scheduling parameters etc. */
++ if (__builtin_expect (stopped != 0, 0))
++ {
++ INTERNAL_SYSCALL_DECL (err);
++ int res = 0;
++
++ /* Set the affinity mask if necessary. */
++ if (attr->cpuset != NULL)
++ {
++ res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
++ sizeof (cpu_set_t), attr->cpuset);
++
++ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
++ {
++ /* The operation failed. We have to kill the thread. First
++ send it the cancellation signal. */
++ INTERNAL_SYSCALL_DECL (err2);
++ err_out:
++#if __ASSUME_TGKILL
++ (void) INTERNAL_SYSCALL (tgkill, err2, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ pd->tid, SIGCANCEL);
++#else
++ (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
++#endif
++
++ return (INTERNAL_SYSCALL_ERROR_P (res, err)
++ ? INTERNAL_SYSCALL_ERRNO (res, err)
++ : 0);
++ }
++ }
++
++ /* Set the scheduling parameters. */
++ if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
++ {
++ res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
++ pd->schedpolicy, &pd->schedparam);
++
++ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
++ goto err_out;
++ }
++ }
++#endif
++
++ /* We now have for sure more than one thread. The main thread might
++ not yet have the flag set. No need to set the global variable
++ again if this is what we use. */
++ THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
++
++ return 0;
++}
++
++
++static int
++create_thread (struct pthread *pd, const struct pthread_attr *attr,
++ STACK_VARIABLES_PARMS)
++{
++#ifdef TLS_TCB_AT_TP
++ assert (pd->header.tcb != NULL);
++#endif
++
++ /* We rely heavily on various flags the CLONE function understands:
++
++ CLONE_VM, CLONE_FS, CLONE_FILES
++ These flags select semantics with shared address space and
++ file descriptors according to what POSIX requires.
++
++ CLONE_SIGNAL
++ This flag selects the POSIX signal semantics.
++
++ CLONE_SETTLS
++ The sixth parameter to CLONE determines the TLS area for the
++ new thread.
++
++ CLONE_PARENT_SETTID
++ The kernels writes the thread ID of the newly created thread
++ into the location pointed to by the fifth parameters to CLONE.
++
++ Note that it would be semantically equivalent to use
++ CLONE_CHILD_SETTID but it is be more expensive in the kernel.
++
++ CLONE_CHILD_CLEARTID
++ The kernels clears the thread ID of a thread that has called
++ sys_exit() in the location pointed to by the seventh parameter
++ to CLONE.
++
++ CLONE_DETACHED
++ No signal is generated if the thread exists and it is
++ automatically reaped.
++
++ The termination signal is chosen to be zero which means no signal
++ is sent. */
++#if 0
++ int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
++ | CLONE_SETTLS | CLONE_PARENT_SETTID
++ | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
++#if __ASSUME_NO_CLONE_DETACHED == 0
++ | CLONE_DETACHED
++#endif
++ | 0);
++#endif
++
++ if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
++ {
++ /* The parent thread is supposed to report events. Check whether
++ the TD_CREATE event is needed, too. */
++ const int _idx = __td_eventword (TD_CREATE);
++ const uint32_t _mask = __td_eventmask (TD_CREATE);
++
++ if ((_mask & (__nptl_threads_events.event_bits[_idx]
++ | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
++ {
++ /* We always must have the thread start stopped. */
++ pd->stopped_start = true;
++
++#if 0
++ /* Create the thread. We always create the thread stopped
++ so that it does not get far before we tell the debugger. */
++ int res = do_clone (pd, attr, clone_flags, start_thread,
++ STACK_VARIABLES_ARGS, 1);
++ if (res == 0)
++ {
++ /* Now fill in the information about the new thread in
++ the newly created thread's data structure. We cannot let
++ the new thread do this since we don't know whether it was
++ already scheduled when we send the event. */
++ pd->eventbuf.eventnum = TD_CREATE;
++ pd->eventbuf.eventdata = pd;
++
++ /* Enqueue the descriptor. */
++ do
++ pd->nextevent = __nptl_last_event;
++ while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
++ pd, pd->nextevent)
++ != 0);
++
++ /* Now call the function which signals the event. */
++ __nptl_create_event ();
++
++ /* And finally restart the new thread. */
++ lll_unlock (pd->lock);
++ }
++
++ return res;
++#endif
++ }
++ }
++
++#ifdef NEED_DL_SYSINFO
++ assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd));
++#endif
++
++ /* Determine whether the newly created threads has to be started
++ stopped since we have to set the scheduling parameters or set the
++ affinity. */
++ bool stopped = false;
++ if (attr != NULL && (attr->cpuset != NULL
++ || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
++ stopped = true;
++ pd->stopped_start = stopped;
++
++#if 0
++ /* Actually create the thread. */
++ int res = do_clone (pd, attr, clone_flags, start_thread,
++ STACK_VARIABLES_ARGS, stopped);
++
++ if (res == 0 && stopped)
++ /* And finally restart the new thread. */
++ lll_unlock (pd->lock);
++
++ return res;
++#endif
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/fork.c libc/nptl/sysdeps/l4/hurd/fork.c
+--- libc/nptl/sysdeps/l4/hurd/fork.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/fork.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,214 @@
++/* 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 <assert.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sysdep.h>
++#include <libio/libioP.h>
++#include <tls.h>
++#include "fork.h"
++#include <hp-timing.h>
++#include <ldsodefs.h>
++#include <bits/stdio-lock.h>
++#include <atomic.h>
++
++
++unsigned long int *__fork_generation_pointer;
++
++
++
++/* The single linked list of all currently registered for handlers. */
++struct fork_handler *__fork_handlers;
++
++
++static void
++fresetlockfiles (void)
++{
++ _IO_ITER i;
++
++ for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
++ _IO_lock_init (*((_IO_lock_t *) _IO_iter_file(i)->_lock));
++}
++
++
++pid_t
++__libc_fork (void)
++{
++ pid_t pid;
++ struct used_handler
++ {
++ struct fork_handler *handler;
++ struct used_handler *next;
++ } *allp = NULL;
++
++ /* Run all the registered preparation handlers. In reverse order.
++ While doing this we build up a list of all the entries. */
++ struct fork_handler *runp;
++ while ((runp = __fork_handlers) != NULL)
++ {
++ unsigned int oldval = runp->refcntr;
++
++ if (oldval == 0)
++ /* This means some other thread removed the list just after
++ the pointer has been loaded. Try again. Either the list
++ is empty or we can retry it. */
++ continue;
++
++ /* Bump the reference counter. */
++ if (atomic_compare_and_exchange_bool_acq (&__fork_handlers->refcntr,
++ oldval + 1, oldval))
++ /* The value changed, try again. */
++ continue;
++
++ /* We bumped the reference counter for the first entry in the
++ list. That means that none of the following entries will
++ just go away. The unloading code works in the order of the
++ list.
++
++ While executing the registered handlers we are building a
++ list of all the entries so that we can go backward later on. */
++ while (1)
++ {
++ /* Execute the handler if there is one. */
++ if (runp->prepare_handler != NULL)
++ runp->prepare_handler ();
++
++ /* Create a new element for the list. */
++ struct used_handler *newp
++ = (struct used_handler *) alloca (sizeof (*newp));
++ newp->handler = runp;
++ newp->next = allp;
++ allp = newp;
++
++ /* Advance to the next handler. */
++ runp = runp->next;
++ if (runp == NULL)
++ break;
++
++ /* Bump the reference counter for the next entry. */
++ atomic_increment (&runp->refcntr);
++ }
++
++ /* We are done. */
++ break;
++ }
++
++ _IO_list_lock ();
++
++#ifndef NDEBUG
++ pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid);
++#endif
++
++ /* We need to prevent the getpid() code to update the PID field so
++ that, if a signal arrives in the child very early and the signal
++ handler uses getpid(), the value returned is correct. */
++ pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid);
++ THREAD_SETMEM (THREAD_SELF, pid, -parentpid);
++
++#if 0
++#ifdef ARCH_FORK
++ pid = ARCH_FORK ();
++#else
++# error "ARCH_FORK must be defined so that the CLONE_SETTID flag is used"
++ pid = INLINE_SYSCALL (fork, 0);
++#endif
++#endif
++
++ if (pid == 0)
++ {
++ struct pthread *self = THREAD_SELF;
++
++ assert (THREAD_GETMEM (self, tid) != ppid);
++
++ if (__fork_generation_pointer != NULL)
++ *__fork_generation_pointer += 4;
++
++ /* Adjust the PID field for the new process. */
++ THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid));
++
++#if HP_TIMING_AVAIL
++ /* The CPU clock of the thread and process have to be set to zero. */
++ hp_timing_t now;
++ HP_TIMING_NOW (now);
++ THREAD_SETMEM (self, cpuclock_offset, now);
++ GL(dl_cpuclock_offset) = now;
++#endif
++
++ /* Reset the file list. These are recursive mutexes. */
++ fresetlockfiles ();
++
++ /* Reset locks in the I/O code. */
++ _IO_list_resetlock ();
++
++ /* Reset the lock the dynamic loader uses to protect its data. */
++ __rtld_lock_initialize (GL(dl_load_lock));
++
++ /* Run the handlers registered for the child. */
++ while (allp != NULL)
++ {
++ if (allp->handler->child_handler != NULL)
++ allp->handler->child_handler ();
++
++ /* Note that we do not have to wake any possible waiter.
++ This is the only thread in the new process. */
++ --allp->handler->refcntr;
++
++ /* XXX We could at this point look through the object pool
++ and mark all objects not on the __fork_handlers list as
++ unused. This is necessary in case the fork() happened
++ while another thread called dlclose() and that call had
++ to create a new list. */
++
++ allp = allp->next;
++ }
++
++ /* Initialize the fork lock. */
++ __fork_lock = (lll_lock_t) LLL_LOCK_INITIALIZER;
++ }
++ else
++ {
++ assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid);
++
++ /* Restore the PID value. */
++ THREAD_SETMEM (THREAD_SELF, pid, parentpid);
++
++ /* We execute this even if the 'fork' call failed. */
++ _IO_list_unlock ();
++
++ /* Run the handlers registered for the parent. */
++ while (allp != NULL)
++ {
++ if (allp->handler->parent_handler != NULL)
++ allp->handler->parent_handler ();
++
++ if (atomic_decrement_and_test (&allp->handler->refcntr)
++ && allp->handler->need_signal)
++ lll_futex_wake (allp->handler->refcntr, 1);
++
++ allp = allp->next;
++ }
++ }
++
++ return pid;
++}
++weak_alias (__libc_fork, __fork)
++libc_hidden_def (__fork)
++weak_alias (__libc_fork, fork)
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/fork.h libc/nptl/sysdeps/l4/hurd/fork.h
+--- libc/nptl/sysdeps/l4/hurd/fork.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/fork.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,57 @@
++/* 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 <lowlevellock.h>
++
++/* The fork generation counter, defined in libpthread. */
++extern unsigned long int __fork_generation attribute_hidden;
++
++/* Pointer to the fork generation counter in the thread library. */
++extern unsigned long int *__fork_generation_pointer attribute_hidden;
++
++/* Lock to protect allocation and deallocation of fork handlers. */
++extern lll_lock_t __fork_lock attribute_hidden;
++
++/* Elements of the fork handler lists. */
++struct fork_handler
++{
++ struct fork_handler *next;
++ void (*prepare_handler) (void);
++ void (*parent_handler) (void);
++ void (*child_handler) (void);
++ void *dso_handle;
++ unsigned int refcntr;
++ int need_signal;
++};
++
++/* The single linked list of all currently registered for handlers. */
++extern struct fork_handler *__fork_handlers;
++
++
++/* Function to call to unregister fork handlers. */
++extern void __unregister_atfork (void *dso_handle) attribute_hidden;
++#define UNREGISTER_ATFORK(dso_handle) __unregister_atfork (dso_handle)
++
++
++/* C library side function to register new fork handlers. */
++extern int __register_atfork (void (*__prepare) (void),
++ void (*__parent) (void),
++ void (*__child) (void),
++ void *dso_handle);
++libc_hidden_proto (__register_atfork)
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/i386/bits/pthreadtypes.h libc/nptl/sysdeps/l4/hurd/i386/bits/pthreadtypes.h
+--- libc/nptl/sysdeps/l4/hurd/i386/bits/pthreadtypes.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/i386/bits/pthreadtypes.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,164 @@
++/* Copyright (C) 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; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _BITS_PTHREADTYPES_H
++#define _BITS_PTHREADTYPES_H 1
++
++/* FIXME: Marcus */
++#define __SIZEOF_PTHREAD_ATTR_T 36
++#define __SIZEOF_PTHREAD_MUTEX_T 24
++#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
++#define __SIZEOF_PTHREAD_COND_T 48
++#define __SIZEOF_PTHREAD_COND_COMPAT_T 12
++#define __SIZEOF_PTHREAD_CONDATTR_T 4
++#define __SIZEOF_PTHREAD_RWLOCK_T 32
++#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
++#define __SIZEOF_PTHREAD_BARRIER_T 20
++#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
++
++
++/* Thread identifiers. The structure of the attribute type is not
++ exposed on purpose. */
++typedef unsigned long int pthread_t;
++
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_ATTR_T];
++ long int __align;
++} pthread_attr_t;
++
++
++/* Data structures for mutex handling. The structure of the attribute
++ type is not exposed on purpose. */
++typedef union
++{
++ struct
++ {
++ /* FIXME: Marcus */
++ int __lock;
++ unsigned int __count;
++ int __owner;
++ /* KIND must stay at this position in the structure to maintain
++ binary compatibility. */
++ int __kind;
++ unsigned int __nusers;
++ int __spins;
++ } __data;
++ char __size[__SIZEOF_PTHREAD_MUTEX_T];
++ long int __align;
++} pthread_mutex_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
++ long int __align;
++} pthread_mutexattr_t;
++
++
++/* Data structure for conditional variable handling. The structure of
++ the attribute type is not exposed on purpose. */
++typedef union
++{
++ struct
++ {
++ /* FIXME: Marcus */
++ int __lock;
++ unsigned int __futex;
++ __extension__ unsigned long long int __total_seq;
++ __extension__ unsigned long long int __wakeup_seq;
++ __extension__ unsigned long long int __woken_seq;
++ void *__mutex;
++ unsigned int __nwaiters;
++ unsigned int __broadcast_seq;
++ } __data;
++ char __size[__SIZEOF_PTHREAD_COND_T];
++ __extension__ long long int __align;
++} pthread_cond_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_CONDATTR_T];
++ long int __align;
++} pthread_condattr_t;
++
++
++/* Keys for thread-specific data */
++typedef unsigned int pthread_key_t;
++
++
++/* Once-only execution */
++typedef int pthread_once_t;
++
++
++#if defined __USE_UNIX98 || defined __USE_XOPEN2K
++/* Data structure for read-write lock variable handling. The
++ structure of the attribute type is not exposed on purpose. */
++typedef union
++{
++ struct
++ {
++ /* FIXME: Marcus */
++ int __lock;
++ unsigned int __nr_readers;
++ unsigned int __readers_wakeup;
++ unsigned int __writer_wakeup;
++ unsigned int __nr_readers_queued;
++ unsigned int __nr_writers_queued;
++ /* FLAGS must stay at this position in the structure to maintain
++ binary compatibility. */
++ unsigned int __flags;
++ int __writer;
++ } __data;
++ char __size[__SIZEOF_PTHREAD_RWLOCK_T];
++ long int __align;
++} pthread_rwlock_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
++ long int __align;
++} pthread_rwlockattr_t;
++#endif
++
++
++#ifdef __USE_XOPEN2K
++/* POSIX spinlock data type. */
++typedef volatile int pthread_spinlock_t;
++
++
++/* POSIX barriers data type. The structure of the type is
++ deliberately not exposed. */
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_BARRIER_T];
++ long int __align;
++} pthread_barrier_t;
++
++typedef union
++{
++ char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
++ int __align;
++} pthread_barrierattr_t;
++#endif
++
++
++/* Extra attributes for the cleanup functions. */
++#define __cleanup_fct_attribute __attribute ((regparm (1)))
++
++#endif /* bits/pthreadtypes.h */
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/i386/bits/semaphore.h libc/nptl/sysdeps/l4/hurd/i386/bits/semaphore.h
+--- libc/nptl/sysdeps/l4/hurd/i386/bits/semaphore.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/i386/bits/semaphore.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,39 @@
++/* Copyright (C) 2002 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _SEMAPHORE_H
++# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
++#endif
++
++
++#define __SIZEOF_SEM_T 16
++
++
++/* Value returned if `sem_open' failed. */
++#define SEM_FAILED ((sem_t *) 0)
++
++/* Maximum value the semaphore can have. */
++#define SEM_VALUE_MAX (2147483647)
++
++
++typedef union
++{
++ char __size[__SIZEOF_SEM_T];
++ long int __align;
++} sem_t;
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/i386/pthread_once.S libc/nptl/sysdeps/l4/hurd/i386/pthread_once.S
+--- libc/nptl/sysdeps/l4/hurd/i386/pthread_once.S 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/i386/pthread_once.S 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,183 @@
++/* 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 <sysdep.h>
++
++#ifndef UP
++# define LOCK lock
++#else
++# define LOCK
++#endif
++
++#define SYS_futex 240
++#define FUTEX_WAKE 1
++
++ .comm __fork_generation, 4, 4
++
++ .text
++
++
++ .globl __pthread_once
++ .type __pthread_once,@function
++ .align 16
++ cfi_startproc
++__pthread_once:
++#if 0
++ movl 4(%esp), %ecx
++ testl $2, (%ecx)
++ jz 1f
++ xorl %eax, %eax
++ ret
++
++1: pushl %ebx
++ cfi_adjust_cfa_offset (4)
++ cfi_rel_offset (3, 0)
++ pushl %esi
++ cfi_adjust_cfa_offset (4)
++ cfi_rel_offset (6, 0)
++ movl %ecx, %ebx
++ xorl %esi, %esi
++
++ /* Not yet initialized or initialization in progress.
++ Get the fork generation counter now. */
++6: movl (%ebx), %eax
++#ifdef PIC
++ call __i686.get_pc_thunk.cx
++ addl $_GLOBAL_OFFSET_TABLE_, %ecx
++#endif
++
++5: movl %eax, %edx
++
++ testl $2, %eax
++ jnz 4f
++
++ andl $3, %edx
++#ifdef PIC
++ orl __fork_generation@GOTOFF(%ecx), %edx
++#else
++ orl __fork_generation, %edx
++#endif
++ orl $1, %edx
++
++ LOCK
++ cmpxchgl %edx, (%ebx)
++ jnz 5b
++
++ /* Check whether another thread already runs the initializer. */
++ testl $1, %eax
++ jz 3f /* No -> do it. */
++
++ /* Check whether the initializer execution was interrupted
++ by a fork. */
++ xorl %edx, %eax
++ testl $0xfffffffc, %eax
++ jnz 3f /* Different for generation -> run initializer. */
++
++ /* Somebody else got here first. Wait. */
++ movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */
++ movl $SYS_futex, %eax
++ ENTER_KERNEL
++ jmp 6b
++
++3: /* Call the initializer function after setting up the
++ cancellation handler. Note that it is not possible here
++ to use the unwind-based cleanup handling. This would require
++ that the user-provided function and all the code it calls
++ is compiled with exceptions. Unfortunately this cannot be
++ guaranteed. */
++ subl $UNWINDBUFSIZE+8, %esp
++ cfi_adjust_cfa_offset (UNWINDBUFSIZE+8)
++ movl %ecx, %ebx /* PIC register value. */
++
++ leal 8+UWJMPBUF(%esp), %eax
++ movl $0, 4(%esp)
++ movl %eax, (%esp)
++ call __sigsetjmp@PLT
++ testl %eax, %eax
++ jne 7f
++
++ leal 8(%esp), %eax
++ call HIDDEN_JUMPTARGET(__pthread_register_cancel)
++
++ /* Call the user-provided initialization function. */
++ call *24+UNWINDBUFSIZE(%esp)
++
++ /* Pop the cleanup handler. */
++ leal 8(%esp), %eax
++ call HIDDEN_JUMPTARGET(__pthread_unregister_cancel)
++ addl $UNWINDBUFSIZE+8, %esp
++ cfi_adjust_cfa_offset (-UNWINDBUFSIZE-8)
++
++ /* Sucessful run of the initializer. Signal that we are done. */
++ movl 12(%esp), %ebx
++ LOCK
++ addl $1, (%ebx)
++
++ /* Wake up all other threads. */
++ movl $0x7fffffff, %edx
++ movl $FUTEX_WAKE, %ecx
++ movl $SYS_futex, %eax
++ ENTER_KERNEL
++
++4: popl %esi
++ cfi_adjust_cfa_offset (-4)
++ cfi_restore (6)
++ popl %ebx
++ cfi_adjust_cfa_offset (-4)
++ cfi_restore (3)
++ xorl %eax, %eax
++ ret
++
++7: /* __sigsetjmp returned for the second time. */
++ movl 20+UNWINDBUFSIZE(%esp), %ebx
++ cfi_adjust_cfa_offset (UNWINDBUFSIZE+16)
++ cfi_offset (3, -8)
++ cfi_offset (6, -12)
++ movl $0, (%ebx)
++
++ movl $0x7fffffff, %edx
++ movl $FUTEX_WAKE, %ecx
++ movl $SYS_futex, %eax
++ ENTER_KERNEL
++
++ leal 8(%esp), %eax
++ call HIDDEN_JUMPTARGET (__pthread_unwind_next)
++#endif
++ /* NOTREACHED */
++ hlt
++ cfi_endproc
++ .size __pthread_once,.-__pthread_once
++
++ .globl __pthread_once_internal
++__pthread_once_internal = __pthread_once
++
++ .globl pthread_once
++pthread_once = __pthread_once
++
++
++#ifdef PIC
++ .section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
++ .globl __i686.get_pc_thunk.cx
++ .hidden __i686.get_pc_thunk.cx
++ .type __i686.get_pc_thunk.cx,@function
++__i686.get_pc_thunk.cx:
++ movl (%esp), %ecx;
++ ret
++ .size __i686.get_pc_thunk.cx,.-__i686.get_pc_thunk.cx
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/Implies libc/nptl/sysdeps/l4/hurd/Implies
+--- libc/nptl/sysdeps/l4/hurd/Implies 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/Implies 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1 @@
++pthread
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/init.c libc/nptl/sysdeps/l4/hurd/init.c
+--- libc/nptl/sysdeps/l4/hurd/init.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/init.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,365 @@
++/* Copyright (C) 2002, 2003, 2004 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 <assert.h>
++#include <limits.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/param.h>
++#include <sys/resource.h>
++#include <pthreadP.h>
++#include <atomic.h>
++#include <ldsodefs.h>
++#include <tls.h>
++#include <fork.h>
++#include <version.h>
++#include <shlib-compat.h>
++#include <smp.h>
++#include <lowlevellock.h>
++
++
++#ifndef __NR_set_tid_address
++/* XXX For the time being... Once we can rely on the kernel headers
++ having the definition remove these lines. */
++#if defined __s390__
++# define __NR_set_tid_address 252
++#elif defined __ia64__
++# define __NR_set_tid_address 1233
++#elif defined __i386__
++# define __NR_set_tid_address 258
++#elif defined __x86_64__
++# define __NR_set_tid_address 218
++#elif defined __powerpc__
++# define __NR_set_tid_address 232
++#elif defined __sparc__
++# define __NR_set_tid_address 166
++#else
++# error "define __NR_set_tid_address"
++#endif
++#endif
++
++
++/* Default stack size. */
++size_t __default_stacksize attribute_hidden;
++
++/* Size and alignment of static TLS block. */
++size_t __static_tls_size;
++size_t __static_tls_align_m1;
++
++/* Flag whether the machine is SMP or not. */
++int __is_smp attribute_hidden;
++
++/* Version of the library, used in libthread_db to detect mismatches. */
++static const char nptl_version[] __attribute_used__ = VERSION;
++
++
++#if defined USE_TLS && !defined SHARED
++extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
++#endif
++
++
++#ifdef SHARED
++static const struct pthread_functions pthread_functions =
++ {
++ .ptr_pthread_attr_destroy = __pthread_attr_destroy,
++# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
++ .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0,
++# endif
++ .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
++ .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,
++# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
++ .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
++ .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
++ .ptr___pthread_cond_init_2_0 = __pthread_cond_init_2_0,
++ .ptr___pthread_cond_signal_2_0 = __pthread_cond_signal_2_0,
++ .ptr___pthread_cond_wait_2_0 = __pthread_cond_wait_2_0,
++ .ptr___pthread_cond_timedwait_2_0 = __pthread_cond_timedwait_2_0,
++# endif
++ .ptr_pthread_equal = __pthread_equal,
++ .ptr___pthread_exit = __pthread_exit,
++ .ptr_pthread_getschedparam = __pthread_getschedparam,
++ .ptr_pthread_setschedparam = __pthread_setschedparam,
++ .ptr_pthread_mutex_destroy = INTUSE(__pthread_mutex_destroy),
++ .ptr_pthread_mutex_init = INTUSE(__pthread_mutex_init),
++ .ptr_pthread_mutex_lock = INTUSE(__pthread_mutex_lock),
++ .ptr_pthread_mutex_unlock = INTUSE(__pthread_mutex_unlock),
++ .ptr_pthread_self = __pthread_self,
++ .ptr_pthread_setcancelstate = __pthread_setcancelstate,
++ .ptr_pthread_setcanceltype = __pthread_setcanceltype,
++ .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
++ .ptr___pthread_once = __pthread_once_internal,
++ .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock_internal,
++ .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock_internal,
++ .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock_internal,
++ .ptr___pthread_key_create = __pthread_key_create_internal,
++ .ptr___pthread_getspecific = __pthread_getspecific_internal,
++ .ptr___pthread_setspecific = __pthread_setspecific_internal,
++ .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer,
++ .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore,
++ .ptr_nthreads = &__nptl_nthreads,
++ .ptr___pthread_unwind = &__pthread_unwind,
++ .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
++ .ptr__nptl_setxid = __nptl_setxid
++ };
++# define ptr_pthread_functions &pthread_functions
++#else
++# define ptr_pthread_functions NULL
++#endif
++
++
++/* For asynchronous cancellation we use a signal. This is the handler. */
++static void
++sigcancel_handler (int sig, siginfo_t *si, void *ctx)
++{
++#if 0
++ /* FIXME: This needs to be implemented differently. */
++
++ /* Safety check. It would be possible to call this function for
++ other signals and send a signal from another process. This is not
++ correct and might even be a security problem. Try to catch as
++ many incorrect invocations as possible. */
++ if (sig != SIGCANCEL
++#ifdef __ASSUME_CORRECT_SI_PID
++ /* Kernels before 2.5.75 stored the thread ID and not the process
++ ID in si_pid so we skip this test. */
++ || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
++#endif
++ || si->si_code != SI_TKILL)
++ return;
++
++ struct pthread *self = THREAD_SELF;
++
++ int oldval = THREAD_GETMEM (self, cancelhandling);
++ while (1)
++ {
++ /* We are canceled now. When canceled by another thread this flag
++ is already set but if the signal is directly send (internally or
++ from another process) is has to be done here. */
++ int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
++
++ if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
++ /* Already canceled or exiting. */
++ break;
++
++ int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
++ oldval);
++ if (curval == oldval)
++ {
++ /* Set the return value. */
++ THREAD_SETMEM (self, result, PTHREAD_CANCELED);
++
++ /* Make sure asynchronous cancellation is still enabled. */
++ if ((newval & CANCELTYPE_BITMASK) != 0)
++ /* Run the registered destructors and terminate the thread. */
++ __do_cancel ();
++
++ break;
++ }
++
++ oldval = curval;
++ }
++#endif
++}
++
++
++struct xid_command *__xidcmd attribute_hidden;
++
++/* For asynchronous cancellation we use a signal. This is the handler. */
++static void
++sighandler_setxid (int sig, siginfo_t *si, void *ctx)
++{
++#if 0
++ /* FIXME: This needs to be implemented differently. */
++
++ /* Safety check. It would be possible to call this function for
++ other signals and send a signal from another process. This is not
++ correct and might even be a security problem. Try to catch as
++ many incorrect invocations as possible. */
++ if (sig != SIGSETXID
++#ifdef __ASSUME_CORRECT_SI_PID
++ /* Kernels before 2.5.75 stored the thread ID and not the process
++ ID in si_pid so we skip this test. */
++ || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
++#endif
++ || si->si_code != SI_TKILL)
++ return;
++
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
++ __xidcmd->id[1], __xidcmd->id[2]);
++
++ if (atomic_decrement_val (&__xidcmd->cntr) == 0)
++ lll_futex_wake (&__xidcmd->cntr, 1);
++
++#endif
++}
++
++
++/* 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));
++
++
++void
++__pthread_initialize_minimal_internal (void)
++{
++#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);
++
++ /* We must prevent gcc from being clever and move any of the
++ following code ahead of the __libc_setup_tls call. This function
++ will initialize the thread register which is subsequently
++ used. */
++ __asm __volatile ("");
++#endif
++
++ /* Minimal initialization of the thread descriptor. */
++ struct pthread *pd = THREAD_SELF;
++#if 0
++ /* FIXME: Implement this. */
++ INTERNAL_SYSCALL_DECL (err);
++ pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
++#endif
++
++ THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
++ THREAD_SETMEM (pd, user_stack, true);
++ if (LLL_LOCK_INITIALIZER != 0)
++ THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
++#if HP_TIMING_AVAIL
++ THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
++#endif
++
++ /* Set initial thread's stack block from 0 up to __libc_stack_end.
++ It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
++ purposes this is good enough. */
++ THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
++
++ /* Initialize the list of all running threads with the main thread. */
++ INIT_LIST_HEAD (&__stack_user);
++ list_add (&pd->list, &__stack_user);
++
++
++#if 0
++ /* FIXME: This needs to be implemented somehow. */
++ /* Install the cancellation signal handler. If for some reason we
++ cannot install the handler we do not abort. Maybe we should, but
++ it is only asynchronous cancellation which is affected. */
++ struct sigaction sa;
++ sa.sa_sigaction = sigcancel_handler;
++ sa.sa_flags = SA_SIGINFO;
++ sigemptyset (&sa.sa_mask);
++
++ (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
++
++ /* Install the handle to change the threads' uid/gid. */
++ sa.sa_sigaction = sighandler_setxid;
++ sa.sa_flags = SA_SIGINFO | SA_RESTART;
++
++ (void) __libc_sigaction (SIGSETXID, &sa, NULL);
++
++ /* The parent process might have left the signal blocked. Just in
++ case, unblock it. We reuse the signal mask in the sigaction
++ structure. It is already cleared. */
++ __sigaddset (&sa.sa_mask, SIGCANCEL);
++ (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
++ NULL, _NSIG / 8);
++#endif
++
++ /* Determine the default allowed stack size. This is the size used
++ in case the user does not specify one. */
++ struct rlimit limit;
++ if (getrlimit (RLIMIT_STACK, &limit) != 0
++ || limit.rlim_cur == RLIM_INFINITY)
++ /* The system limit is not usable. Use an architecture-specific
++ default. */
++ __default_stacksize = ARCH_STACK_DEFAULT_SIZE;
++ else if (limit.rlim_cur < PTHREAD_STACK_MIN)
++ /* The system limit is unusably small.
++ Use the minimal size acceptable. */
++ __default_stacksize = PTHREAD_STACK_MIN;
++ else
++ {
++ /* Round the resource limit up to page size. */
++ const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
++ __default_stacksize = (limit.rlim_cur + pagesz - 1) & -pagesz;
++ }
++
++ /* Get the size of the static and alignment requirements for the TLS
++ block. */
++ size_t static_tls_align;
++ _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);
++
++ /* Make sure the size takes all the alignments into account. */
++ if (STACK_ALIGN > static_tls_align)
++ static_tls_align = STACK_ALIGN;
++ __static_tls_align_m1 = static_tls_align - 1;
++
++ __static_tls_size = roundup (__static_tls_size, static_tls_align);
++
++#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 *) INTUSE (__pthread_mutex_lock);
++ GL(dl_rtld_unlock_recursive) = (void *) INTUSE (__pthread_mutex_unlock);
++ unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
++ GL(dl_load_lock).mutex.__data.__count = 0;
++ while (rtld_lock_count-- > 0)
++ INTUSE (__pthread_mutex_lock) (&GL(dl_load_lock).mutex);
++
++ GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
++#endif
++
++ GL(dl_init_static_tls) = &__pthread_init_static_tls;
++
++ /* Register the fork generation counter with the libc. */
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++ __libc_multiple_threads_ptr =
++#endif
++ __libc_pthread_init (&__fork_generation, __reclaim_stacks,
++ ptr_pthread_functions);
++
++ /* Determine whether the machine is SMP or not. */
++ __is_smp = is_smp_system ();
++}
++strong_alias (__pthread_initialize_minimal_internal,
++ __pthread_initialize_minimal)
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/internaltypes.h libc/nptl/sysdeps/l4/hurd/internaltypes.h
+--- libc/nptl/sysdeps/l4/hurd/internaltypes.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/internaltypes.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,152 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _INTERNALTYPES_H
++#define _INTERNALTYPES_H 1
++
++#include <stdint.h>
++
++
++struct pthread_attr
++{
++ /* Scheduler parameters and priority. */
++ struct sched_param schedparam;
++ int schedpolicy;
++ /* Various flags like detachstate, scope, etc. */
++ int flags;
++ /* Size of guard area. */
++ size_t guardsize;
++ /* Stack handling. */
++ void *stackaddr;
++ size_t stacksize;
++ /* Affinity map. */
++ cpu_set_t *cpuset;
++ size_t cpusetsize;
++};
++
++#define ATTR_FLAG_DETACHSTATE 0x0001
++#define ATTR_FLAG_NOTINHERITSCHED 0x0002
++#define ATTR_FLAG_SCOPEPROCESS 0x0004
++#define ATTR_FLAG_STACKADDR 0x0008
++#define ATTR_FLAG_OLDATTR 0x0010
++#define ATTR_FLAG_SCHED_SET 0x0020
++#define ATTR_FLAG_POLICY_SET 0x0040
++
++
++/* Mutex attribute data structure. */
++struct pthread_mutexattr
++{
++ /* Identifier for the kind of mutex.
++
++ Bit 31 is set if the mutex is to be shared between processes.
++
++ Bit 0 to 30 contain one of the PTHREAD_MUTEX_ values to identify
++ the type of the mutex. */
++ int mutexkind;
++};
++
++
++/* Conditional variable attribute data structure. */
++struct pthread_condattr
++{
++ /* Combination of values:
++
++ Bit 0 : flag whether coditional variable will be shareable between
++ processes.
++
++ Bit 1-7: clock ID. */
++ int value;
++};
++
++
++/* The __NWAITERS field is used as a counter and to house the number
++ of bits which represent the clock. COND_CLOCK_BITS is the number
++ of bits reserved for the clock. */
++#define COND_CLOCK_BITS 1
++
++
++/* Read-write lock variable attribute data structure. */
++struct pthread_rwlockattr
++{
++ int lockkind;
++ int pshared;
++};
++
++
++/* Barrier data structure. */
++struct pthread_barrier
++{
++ unsigned int curr_event;
++ int lock;
++ unsigned int left;
++ unsigned int init_count;
++};
++
++
++/* Barrier variable attribute data structure. */
++struct pthread_barrierattr
++{
++ int pshared;
++};
++
++
++/* Thread-local data handling. */
++struct pthread_key_struct
++{
++ /* Sequence numbers. Even numbers indicated vacant entries. Note
++ that zero is even. We use uintptr_t to not require padding on
++ 32- and 64-bit machines. On 64-bit machines it helps to avoid
++ wrapping, too. */
++ uintptr_t seq;
++
++ /* Destructor for the data. */
++ void (*destr) (void *);
++};
++
++/* Check whether an entry is unused. */
++#define KEY_UNUSED(p) (((p) & 1) == 0)
++/* Check whether a key is usable. We cannot reuse an allocated key if
++ the sequence counter would overflow after the next destroy call.
++ This would mean that we potentially free memory for a key with the
++ same sequence. This is *very* unlikely to happen, A program would
++ have to create and destroy a key 2^31 times (on 32-bit platforms,
++ on 64-bit platforms that would be 2^63). If it should happen we
++ simply don't use this specific key anymore. */
++#define KEY_USABLE(p) (((uintptr_t) (p)) < ((uintptr_t) ((p) + 2)))
++
++
++/* Handling of read-write lock data. */
++// XXX For now there is only one flag. Maybe more in future.
++#define RWLOCK_RECURSIVE(rwlock) ((rwlock)->__data.__flags != 0)
++
++
++/* Semaphore variable structure. */
++struct sem
++{
++ unsigned int count;
++};
++
++
++/* Compatibility type for old conditional variable interfaces. */
++typedef struct
++{
++ pthread_cond_t *cond;
++} pthread_cond_2_0_t;
++
++#endif /* internaltypes.h */
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/libc-lowlevellock.c libc/nptl/sysdeps/l4/hurd/libc-lowlevellock.c
+--- libc/nptl/sysdeps/l4/hurd/libc-lowlevellock.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/libc-lowlevellock.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,21 @@
++/* Copyright (C) 2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* No difference to lowlevellock.c, except we lose a couple of functions. */
++#include "lowlevellock.c"
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/lowlevellock.c libc/nptl/sysdeps/l4/hurd/lowlevellock.c
+--- libc/nptl/sysdeps/l4/hurd/lowlevellock.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/lowlevellock.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,25 @@
++/* low level locking for pthread library. Generic futex-using version.
++ Copyright (C) 2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <sysdep.h>
++#include <lowlevellock.h>
++#include <sys/time.h>
++
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/lowlevellock.h libc/nptl/sysdeps/l4/hurd/lowlevellock.h
+--- libc/nptl/sysdeps/l4/hurd/lowlevellock.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/lowlevellock.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,374 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _LOWLEVELLOCK_H
++#define _LOWLEVELLOCK_H 1
++
++#include <time.h>
++#include <sys/param.h>
++#include <bits/pthreadtypes.h>
++
++/* Type for lock object. */
++typedef int lll_lock_t;
++
++/* Initializers for lock. */
++#define LLL_LOCK_INITIALIZER (0)
++#define LLL_LOCK_INITIALIZER_LOCKED (1)
++
++# define lll_trylock(futex) (0)
++# define lll_lock(futex) (0)
++# define lll_unlock(futex) (0)
++
++extern int lll_unlock_wake_cb (lll_lock_t *__lock) attribute_hidden;
++
++#define lll_mutex_lock(futex) (0)
++#define lll_mutex_trylock(futex) (0)
++#define lll_mutex_islocked(futex) (futex != 0)
++#define lll_futex_wake(futex, nr) (0)
++#define lll_futex_wait(futex, val) (0)
++#define lll_mutex_unlock(futex) (0)
++#define lll_futex_timed_wait(ftx, val, timespec) (0)
++
++#define lll_mutex_cond_trylock(futex) (0)
++#define lll_mutex_cond_lock(futex) (0)
++
++
++#if 0
++
++/* Initializer for compatibility lock. */
++#define LLL_MUTEX_LOCK_INITIALIZER (0)
++#define LLL_MUTEX_LOCK_INITIALIZER_LOCKED (1)
++#define LLL_MUTEX_LOCK_INITIALIZER_WAITERS (2)
++
++
++#ifdef PIC
++# define LLL_EBX_LOAD "xchgl %2, %%ebx\n"
++# define LLL_EBX_REG "D"
++#else
++# define LLL_EBX_LOAD
++# define LLL_EBX_REG "b"
++#endif
++
++
++/* Delay in spinlock loop. */
++#define BUSY_WAIT_NOP asm ("rep; nop")
++
++
++#define lll_futex_wait(futex, val) \
++ do { \
++ int __ignore; \
++ register __typeof (val) _val asm ("edx") = (val); \
++ __asm __volatile (LLL_EBX_LOAD \
++ LLL_ENTER_KERNEL \
++ LLL_EBX_LOAD \
++ : "=a" (__ignore) \
++ : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \
++ "c" (FUTEX_WAIT), "d" (_val), \
++ "i" (offsetof (tcbhead_t, sysinfo))); \
++ } while (0)
++
++
++#define lll_futex_wake(futex, nr) \
++ do { \
++ int __ignore; \
++ register __typeof (nr) _nr asm ("edx") = (nr); \
++ __asm __volatile (LLL_EBX_LOAD \
++ LLL_ENTER_KERNEL \
++ LLL_EBX_LOAD \
++ : "=a" (__ignore) \
++ : "0" (SYS_futex), LLL_EBX_REG (futex), \
++ "c" (FUTEX_WAKE), "d" (_nr), \
++ "i" (0) /* phony, to align next arg's number */, \
++ "i" (offsetof (tcbhead_t, sysinfo))); \
++ } while (0)
++
++
++/* Does not preserve %eax and %ecx. */
++extern int __lll_mutex_lock_wait (int val, int *__futex)
++ __attribute ((regparm (2))) attribute_hidden;
++/* Does not preserve %eax, %ecx, and %edx. */
++extern int __lll_mutex_timedlock_wait (int val, int *__futex,
++ const struct timespec *abstime)
++ __attribute ((regparm (3))) attribute_hidden;
++/* Preserves all registers but %eax. */
++extern int __lll_mutex_unlock_wake (int *__futex)
++ __attribute ((regparm (1))) attribute_hidden;
++
++
++/* NB: in the lll_mutex_trylock macro we simply return the value in %eax
++ after the cmpxchg instruction. In case the operation succeded this
++ value is zero. In case the operation failed, the cmpxchg instruction
++ has loaded the current value of the memory work which is guaranteed
++ to be nonzero. */
++#define lll_mutex_trylock(futex) \
++ ({ int ret; \
++ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
++ : "=a" (ret), "=m" (futex) \
++ : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\
++ "0" (LLL_MUTEX_LOCK_INITIALIZER) \
++ : "memory"); \
++ ret; })
++
++
++#define lll_mutex_cond_trylock(futex) \
++ ({ int ret; \
++ __asm __volatile (LOCK_INSTR "cmpxchgl %2, %1" \
++ : "=a" (ret), "=m" (futex) \
++ : "r" (LLL_MUTEX_LOCK_INITIALIZER_WAITERS), \
++ "m" (futex), "0" (LLL_MUTEX_LOCK_INITIALIZER) \
++ : "memory"); \
++ ret; })
++
++
++#define lll_mutex_lock(futex) \
++ (void) ({ int ignore1, ignore2; \
++ __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
++ "jnz _L_mutex_lock_%=\n\t" \
++ ".subsection 1\n\t" \
++ ".type _L_mutex_lock_%=,@function\n" \
++ "_L_mutex_lock_%=:\n\t" \
++ "leal %2, %%ecx\n\t" \
++ "call __lll_mutex_lock_wait\n\t" \
++ "jmp 1f\n\t" \
++ ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \
++ ".previous\n" \
++ "1:" \
++ : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
++ : "0" (0), "1" (1), "m" (futex) \
++ : "memory"); })
++
++
++/* Special version of lll_mutex_lock which causes the unlock function to
++ always wakeup waiters. */
++#define lll_mutex_cond_lock(futex) \
++ (void) ({ int ignore1, ignore2; \
++ __asm __volatile (LOCK_INSTR "cmpxchgl %1, %2\n\t" \
++ "jnz _L_mutex_cond_lock_%=\n\t" \
++ ".subsection 1\n\t" \
++ ".type _L_mutex_cond_lock_%=,@function\n" \
++ "_L_mutex_cond_lock_%=:\n\t" \
++ "leal %2, %%ecx\n\t" \
++ "call __lll_mutex_lock_wait\n\t" \
++ "jmp 1f\n\t" \
++ ".size _L_mutex_cond_lock_%=,.-_L_mutex_cond_lock_%=\n" \
++ ".previous\n" \
++ "1:" \
++ : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
++ : "0" (0), "1" (2), "m" (futex) \
++ : "memory"); })
++
++
++#define lll_mutex_timedlock(futex, timeout) \
++ ({ int result, ignore1, ignore2; \
++ __asm __volatile (LOCK_INSTR "cmpxchgl %1, %3\n\t" \
++ "jnz _L_mutex_timedlock_%=\n\t" \
++ ".subsection 1\n\t" \
++ ".type _L_mutex_timedlock_%=,@function\n" \
++ "_L_mutex_timedlock_%=:\n\t" \
++ "leal %3, %%ecx\n\t" \
++ "movl %7, %%edx\n\t" \
++ "call __lll_mutex_timedlock_wait\n\t" \
++ "jmp 1f\n\t" \
++ ".size _L_mutex_timedlock_%=,.-_L_mutex_timedlock_%=\n"\
++ ".previous\n" \
++ "1:" \
++ : "=a" (result), "=c" (ignore1), "=&d" (ignore2), \
++ "=m" (futex) \
++ : "0" (0), "1" (1), "m" (futex), "m" (timeout) \
++ : "memory"); \
++ result; })
++
++
++#define lll_mutex_unlock(futex) \
++ (void) ({ int ignore; \
++ __asm __volatile (LOCK_INSTR "subl $1,%0\n\t" \
++ "jne _L_mutex_unlock_%=\n\t" \
++ ".subsection 1\n\t" \
++ ".type _L_mutex_unlock_%=,@function\n" \
++ "_L_mutex_unlock_%=:\n\t" \
++ "leal %0, %%eax\n\t" \
++ "call __lll_mutex_unlock_wake\n\t" \
++ "jmp 1f\n\t" \
++ ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \
++ ".previous\n" \
++ "1:" \
++ : "=m" (futex), "=&a" (ignore) \
++ : "m" (futex) \
++ : "memory"); })
++
++
++#define lll_mutex_islocked(futex) \
++ (futex != 0)
++
++
++/* We have a separate internal lock implementation which is not tied
++ to binary compatibility. */
++
++
++
++extern int __lll_lock_wait (int val, int *__futex)
++ __attribute ((regparm (2))) attribute_hidden;
++extern int __lll_unlock_wake (int *__futex)
++ __attribute ((regparm (1))) attribute_hidden;
++extern int lll_unlock_wake_cb (int *__futex) attribute_hidden;
++
++
++/* The states of a lock are:
++ 0 - untaken
++ 1 - taken by one user
++ 2 - taken by more users */
++
++
++#if defined NOT_IN_libc || defined UP
++# define lll_trylock(futex) lll_mutex_trylock (futex)
++# define lll_lock(futex) lll_mutex_lock (futex)
++# define lll_unlock(futex) lll_mutex_unlock (futex)
++#else
++/* Special versions of the macros for use in libc itself. They avoid
++ the lock prefix when the thread library is not used.
++
++ XXX In future we might even want to avoid it on UP machines. */
++# include <tls.h>
++
++# define lll_trylock(futex) \
++ ({ unsigned char ret; \
++ __asm __volatile ("cmpl $0, %%gs:%P5\n\t" \
++ "je,pt 0f\n\t" \
++ "lock\n" \
++ "0:\tcmpxchgl %2, %1; setne %0" \
++ : "=a" (ret), "=m" (futex) \
++ : "r" (LLL_MUTEX_LOCK_INITIALIZER_LOCKED), "m" (futex),\
++ "0" (LLL_MUTEX_LOCK_INITIALIZER), \
++ "i" (offsetof (tcbhead_t, multiple_threads)) \
++ : "memory"); \
++ ret; })
++
++
++# define lll_lock(futex) \
++ (void) ({ int ignore1, ignore2; \
++ __asm __volatile ("cmpl $0, %%gs:%P6\n\t" \
++ "je,pt 0f\n\t" \
++ "lock\n" \
++ "0:\tcmpxchgl %1, %2\n\t" \
++ "jnz _L_mutex_lock_%=\n\t" \
++ ".subsection 1\n\t" \
++ ".type _L_mutex_lock_%=,@function\n" \
++ "_L_mutex_lock_%=:\n\t" \
++ "leal %2, %%ecx\n\t" \
++ "call __lll_mutex_lock_wait\n\t" \
++ "jmp 1f\n\t" \
++ ".size _L_mutex_lock_%=,.-_L_mutex_lock_%=\n" \
++ ".previous\n" \
++ "1:" \
++ : "=a" (ignore1), "=c" (ignore2), "=m" (futex) \
++ : "0" (0), "1" (1), "m" (futex), \
++ "i" (offsetof (tcbhead_t, multiple_threads)) \
++ : "memory"); })
++
++
++# define lll_unlock(futex) \
++ (void) ({ int ignore; \
++ __asm __volatile ("cmpl $0, %%gs:%P3\n\t" \
++ "je,pt 0f\n\t" \
++ "lock\n" \
++ "0:\tsubl $1,%0\n\t" \
++ "jne _L_mutex_unlock_%=\n\t" \
++ ".subsection 1\n\t" \
++ ".type _L_mutex_unlock_%=,@function\n" \
++ "_L_mutex_unlock_%=:\n\t" \
++ "leal %0, %%eax\n\t" \
++ "call __lll_mutex_unlock_wake\n\t" \
++ "jmp 1f\n\t" \
++ ".size _L_mutex_unlock_%=,.-_L_mutex_unlock_%=\n" \
++ ".previous\n" \
++ "1:" \
++ : "=m" (futex), "=&a" (ignore) \
++ : "m" (futex), \
++ "i" (offsetof (tcbhead_t, multiple_threads)) \
++ : "memory"); })
++#endif
++
++
++#define lll_islocked(futex) \
++ (futex != LLL_LOCK_INITIALIZER)
++
++
++/* The kernel notifies a process with uses CLONE_CLEARTID via futex
++ wakeup when the clone terminates. The memory location contains the
++ thread ID while the clone is running and is reset to zero
++ afterwards.
++
++ The macro parameter must not have any side effect. */
++#define lll_wait_tid(tid) \
++ do { \
++ int __ignore; \
++ register __typeof (tid) _tid asm ("edx") = (tid); \
++ if (_tid != 0) \
++ __asm __volatile (LLL_EBX_LOAD \
++ "1:\tmovl %1, %%eax\n\t" \
++ LLL_ENTER_KERNEL \
++ "cmpl $0, (%%ebx)\n\t" \
++ "jne,pn 1b\n\t" \
++ LLL_EBX_LOAD \
++ : "=&a" (__ignore) \
++ : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0), \
++ "c" (FUTEX_WAIT), "d" (_tid), \
++ "i" (offsetof (tcbhead_t, sysinfo))); \
++ } while (0)
++
++extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
++ __attribute__ ((regparm (2))) attribute_hidden;
++#define lll_timedwait_tid(tid, abstime) \
++ ({ \
++ int __result = 0; \
++ if (tid != 0) \
++ { \
++ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) \
++ __result = EINVAL; \
++ else \
++ __result = __lll_timedwait_tid (&tid, abstime); \
++ } \
++ __result; })
++
++
++/* Conditional variable handling. */
++
++extern void __lll_cond_wait (pthread_cond_t *cond)
++ __attribute ((regparm (1))) attribute_hidden;
++extern int __lll_cond_timedwait (pthread_cond_t *cond,
++ const struct timespec *abstime)
++ __attribute ((regparm (2))) attribute_hidden;
++extern void __lll_cond_wake (pthread_cond_t *cond)
++ __attribute ((regparm (1))) attribute_hidden;
++extern void __lll_cond_broadcast (pthread_cond_t *cond)
++ __attribute ((regparm (1))) attribute_hidden;
++
++
++#define lll_cond_wait(cond) \
++ __lll_cond_wait (cond)
++#define lll_cond_timedwait(cond, abstime) \
++ __lll_cond_timedwait (cond, abstime)
++#define lll_cond_wake(cond) \
++ __lll_cond_wake (cond)
++#define lll_cond_broadcast(cond) \
++ __lll_cond_broadcast (cond)
++
++#endif
++
++#endif /* lowlevellock.h */
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/Makefile libc/nptl/sysdeps/l4/hurd/Makefile
+--- libc/nptl/sysdeps/l4/hurd/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/Makefile 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,30 @@
++# Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++# This file is part of the GNU C Library.
++# Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++# The GNU C Library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2.1 of the License, or (at your option) any later version.
++
++# The GNU C Library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# Lesser General Public License for more details.
++
++# You should have received a copy of the GNU Lesser General Public
++# License along with the GNU C Library; if not, write to the Free
++# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++# 02111-1307 USA. */
++
++ifeq ($(subdir),nptl)
++sysdep_routines += register-atfork unregister-atfork
++
++libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock
++endif
++
++ifeq ($(subdir),posix)
++CFLAGS-fork.c = -D_IO_MTSAFE_IO
++CFLAGS-getpid.o = -fomit-frame-pointer
++CFLAGS-getpid.os = -fomit-frame-pointer
++endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pt-fork.c libc/nptl/sysdeps/l4/hurd/pt-fork.c
+--- libc/nptl/sysdeps/l4/hurd/pt-fork.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pt-fork.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,28 @@
++/* Copyright (C) 2002 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <unistd.h>
++
++
++pid_t
++__fork (void)
++{
++ return __libc_fork ();
++}
++strong_alias (__fork, fork)
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_attr_getaffinity.c libc/nptl/sysdeps/l4/hurd/pthread_attr_getaffinity.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_attr_getaffinity.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_attr_getaffinity.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,71 @@
++/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <pthreadP.h>
++#include <string.h>
++#include <sysdep.h>
++#include <sys/types.h>
++#include <shlib-compat.h>
++
++
++int
++__pthread_attr_getaffinity_new (const pthread_attr_t *attr, size_t cpusetsize,
++ cpu_set_t *cpuset)
++{
++ const struct pthread_attr *iattr;
++
++#if 0
++ assert (sizeof (*attr) >= sizeof (struct pthread_attr));
++ iattr = (const struct pthread_attr *) attr;
++
++ if (iattr->cpuset != NULL)
++ {
++ /* Check whether there are any bits set beyond the limits
++ the user requested. */
++ for (size_t cnt = cpusetsize; cnt < iattr->cpusetsize; ++cnt)
++ if (((char *) iattr->cpuset)[cnt] != 0)
++ return EINVAL;
++
++ void *p = mempcpy (cpuset, iattr->cpuset, iattr->cpusetsize);
++ if (cpusetsize > iattr->cpusetsize)
++ memset (p, '\0', cpusetsize - iattr->cpusetsize);
++ }
++ else
++ /* We have no information. */
++ memset (cpuset, -1, cpusetsize);
++#endif
++
++ return 0;
++}
++versioned_symbol (libpthread, __pthread_attr_getaffinity_new,
++ pthread_attr_getaffinity_np, GLIBC_2_3_4);
++
++
++#if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4)
++int
++__pthread_attr_getaffinity_old (const pthread_attr_t *attr, cpu_set_t *cpuset)
++{
++ /* The old interface by default assumed a 1024 processor bitmap. */
++ return __pthread_attr_getaffinity_new (attr, 128, cpuset);
++}
++compat_symbol (libpthread, __pthread_attr_getaffinity_old,
++ pthread_attr_getaffinity_np, GLIBC_2_3_3);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_attr_setaffinity.c libc/nptl/sysdeps/l4/hurd/pthread_attr_setaffinity.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_attr_setaffinity.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_attr_setaffinity.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,97 @@
++/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <limits.h>
++#include <stdlib.h>
++#include <string.h>
++#include <pthreadP.h>
++#include <shlib-compat.h>
++
++
++/* Defined in pthread_setaffinity.c. */
++extern size_t __kernel_cpumask_size;
++extern int __determine_cpumask_size (pid_t tid);
++
++
++int
++__pthread_attr_setaffinity_new (pthread_attr_t *attr, size_t cpusetsize,
++ const cpu_set_t *cpuset)
++{
++ struct pthread_attr *iattr;
++
++#if 0
++ assert (sizeof (*attr) >= sizeof (struct pthread_attr));
++ iattr = (struct pthread_attr *) attr;
++
++ if (cpuset == NULL || cpusetsize == 0)
++ {
++ free (iattr->cpuset);
++ iattr->cpuset = NULL;
++ iattr->cpusetsize = 0;
++ }
++ else
++ {
++ if (__kernel_cpumask_size == 0)
++ {
++ int res = __determine_cpumask_size (THREAD_SELF->tid);
++ if (res != 0)
++ /* Some serious problem. */
++ return res;
++ }
++
++ /* Check whether the new bitmask has any bit set beyond the
++ last one the kernel accepts. */
++ for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt)
++ if (((char *) cpuset)[cnt] != '\0')
++ /* Found a nonzero byte. This means the user request cannot be
++ fulfilled. */
++ return EINVAL;
++
++ if (iattr->cpusetsize != cpusetsize)
++ {
++ void *newp = (cpu_set_t *) realloc (iattr->cpuset, cpusetsize);
++ if (newp == NULL)
++ return ENOMEM;
++
++ iattr->cpuset = newp;
++ iattr->cpusetsize = cpusetsize;
++ }
++
++ memcpy (iattr->cpuset, cpuset, cpusetsize);
++ }
++
++#endif
++ return 0;
++}
++versioned_symbol (libpthread, __pthread_attr_setaffinity_new,
++ pthread_attr_setaffinity_np, GLIBC_2_3_4);
++
++
++#if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4)
++int
++__pthread_attr_setaffinity_old (pthread_attr_t *attr, cpu_set_t *cpuset)
++{
++ /* The old interface by default assumed a 1024 processor bitmap. */
++ return __pthread_attr_setaffinity_new (attr, 128, cpuset);
++}
++compat_symbol (libpthread, __pthread_attr_setaffinity_old,
++ pthread_attr_setaffinity_np, GLIBC_2_3_3);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_cancel.c libc/nptl/sysdeps/l4/hurd/pthread_cancel.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_cancel.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_cancel.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,105 @@
++/* 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 <errno.h>
++#include <signal.h>
++#include "pthreadP.h"
++#include "atomic.h"
++#include <sysdep.h>
++
++
++int
++pthread_cancel (th)
++ pthread_t th;
++{
++ volatile struct pthread *pd = (volatile struct pthread *) th;
++
++ /* Make sure the descriptor is valid. */
++ if (INVALID_TD_P (pd))
++ /* Not a valid thread handle. */
++ return ESRCH;
++
++#ifdef SHARED
++ pthread_cancel_init ();
++#endif
++ int result = 0;
++ int oldval;
++ int newval;
++ do
++ {
++ oldval = pd->cancelhandling;
++ newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
++
++ /* Avoid doing unnecessary work. The atomic operation can
++ potentially be expensive if the bug has to be locked and
++ remote cache lines have to be invalidated. */
++ if (oldval == newval)
++ break;
++
++ /* If the cancellation is handled asynchronously just send a
++ signal. We avoid this if possible since it's more
++ expensive. */
++ if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
++ {
++ /* Mark the cancellation as "in progress". */
++ atomic_bit_set (&pd->cancelhandling, CANCELING_BIT);
++
++#if 0
++ /* FIXME */
++
++ /* The cancellation handler will take care of marking the
++ thread as canceled. */
++ INTERNAL_SYSCALL_DECL (err);
++
++ /* One comment: The PID field in the TCB can temporarily be
++ changed (in fork). But this must not affect this code
++ here. Since this function would have to be called while
++ the thread is executing fork, it would have to happen in
++ a signal handler. But this is no allowed, pthread_cancel
++ is not guaranteed to be async-safe. */
++ int val;
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
++ SIGCANCEL);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
++ SIGCANCEL);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL);
++#endif
++
++ if (INTERNAL_SYSCALL_ERROR_P (val, err))
++ result = INTERNAL_SYSCALL_ERRNO (val, err);
++
++#endif
++ break;
++ }
++ }
++ /* Mark the thread as canceled. This has to be done
++ atomically since other bits could be modified as well. */
++ while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval,
++ oldval));
++
++ return result;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_condattr_setclock.c libc/nptl/sysdeps/l4/hurd/pthread_condattr_setclock.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_condattr_setclock.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_condattr_setclock.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,73 @@
++/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <time.h>
++#include <sysdep.h>
++#include "pthreadP.h"
++
++
++int
++pthread_condattr_setclock (attr, clock_id)
++ pthread_condattr_t *attr;
++ clockid_t clock_id;
++{
++#if 0
++ /* Only a few clocks are allowed. CLOCK_REALTIME is always allowed.
++ CLOCK_MONOTONIC only if the kernel has the necessary support. */
++ if (clock_id == CLOCK_MONOTONIC)
++ {
++#ifndef __ASSUME_POSIX_TIMERS
++# ifdef __NR_clock_getres
++ /* Check whether the clock is available. */
++ static int avail;
++
++ if (avail == 0)
++ {
++ struct timespec ts;
++
++ INTERNAL_SYSCALL_DECL (err);
++ int val;
++ val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts);
++ avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1;
++ }
++
++ if (avail < 0)
++# endif
++ /* Not available. */
++ return EINVAL;
++#endif
++ }
++ else if (clock_id != CLOCK_REALTIME)
++ /* If more clocks are allowed some day the storing of the clock ID
++ in the pthread_cond_t structure needs to be adjusted. */
++#endif
++ return EINVAL;
++#if 0
++ /* Make sure the value fits in the bits we reserved. */
++ assert (clock_id < (1 << COND_CLOCK_BITS));
++
++ int *valuep = &((struct pthread_condattr *) attr)->value;
++
++ *valuep = (*valuep & ~(1 << (COND_CLOCK_BITS + 1)) & ~1) | (clock_id << 1);
++ return 0;
++#endif
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_create.c libc/nptl/sysdeps/l4/hurd/pthread_create.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_create.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_create.c 2005-01-23 20:07:51.000000000 +0100
+@@ -0,0 +1,528 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include "pthreadP.h"
++#include <hp-timing.h>
++#include <ldsodefs.h>
++#include <atomic.h>
++#include <libc-internal.h>
++#include <resolv.h>
++
++#include <shlib-compat.h>
++
++
++/* Local function to start thread and handle cleanup. */
++static int start_thread (void *arg);
++
++
++/* Nozero if debugging mode is enabled. */
++int __pthread_debug;
++
++/* Globally enabled events. */
++static td_thr_events_t __nptl_threads_events;
++
++/* Pointer to descriptor with the last event. */
++static struct pthread *__nptl_last_event;
++
++/* Number of threads running. */
++unsigned int __nptl_nthreads = 1;
++
++
++/* Code to allocate and deallocate a stack. */
++#include "allocatestack.c"
++
++/* Code to create the thread. */
++#include "createthread.c"
++
++
++struct pthread *
++internal_function
++__find_in_stack_list (pd)
++ struct pthread *pd;
++{
++ list_t *entry;
++ struct pthread *result = NULL;
++
++ lll_lock (stack_cache_lock);
++
++ list_for_each (entry, &stack_used)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (entry, struct pthread, list);
++ if (curp == pd)
++ {
++ result = curp;
++ break;
++ }
++ }
++
++ if (result == NULL)
++ list_for_each (entry, &__stack_user)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (entry, struct pthread, list);
++ if (curp == pd)
++ {
++ result = curp;
++ break;
++ }
++ }
++
++ lll_unlock (stack_cache_lock);
++
++ return result;
++}
++
++
++/* Deallocate POSIX thread-local-storage. */
++void
++attribute_hidden
++__nptl_deallocate_tsd (void)
++{
++ struct pthread *self = THREAD_SELF;
++
++ /* Maybe no data was ever allocated. This happens often so we have
++ a flag for this. */
++ if (THREAD_GETMEM (self, specific_used))
++ {
++ size_t round;
++ size_t cnt;
++
++ round = 0;
++ do
++ {
++ size_t idx;
++
++ /* So far no new nonzero data entry. */
++ THREAD_SETMEM (self, specific_used, false);
++
++ for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
++ {
++ struct pthread_key_data *level2;
++
++ level2 = THREAD_GETMEM_NC (self, specific, cnt);
++
++ if (level2 != NULL)
++ {
++ size_t inner;
++
++ for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
++ ++inner, ++idx)
++ {
++ void *data = level2[inner].data;
++
++ if (data != NULL)
++ {
++ /* Always clear the data. */
++ level2[inner].data = NULL;
++
++ /* Make sure the data corresponds to a valid
++ key. This test fails if the key was
++ deallocated and also if it was
++ re-allocated. It is the user's
++ responsibility to free the memory in this
++ case. */
++ if (level2[inner].seq
++ == __pthread_keys[idx].seq
++ /* It is not necessary to register a destructor
++ function. */
++ && __pthread_keys[idx].destr != NULL)
++ /* Call the user-provided destructor. */
++ __pthread_keys[idx].destr (data);
++ }
++ }
++ }
++ else
++ idx += PTHREAD_KEY_1STLEVEL_SIZE;
++ }
++
++ if (THREAD_GETMEM (self, specific_used) == 0)
++ /* No data has been modified. */
++ goto just_free;
++ }
++ /* We only repeat the process a fixed number of times. */
++ while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0));
++
++ /* Just clear the memory of the first block for reuse. */
++ memset (&THREAD_SELF->specific_1stblock, '\0',
++ sizeof (self->specific_1stblock));
++
++ just_free:
++ /* Free the memory for the other blocks. */
++ for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
++ {
++ struct pthread_key_data *level2;
++
++ level2 = THREAD_GETMEM_NC (self, specific, cnt);
++ if (level2 != NULL)
++ {
++ /* The first block is allocated as part of the thread
++ descriptor. */
++ free (level2);
++ THREAD_SETMEM_NC (self, specific, cnt, NULL);
++ }
++ }
++
++ THREAD_SETMEM (self, specific_used, false);
++ }
++}
++
++
++/* Deallocate a thread's stack after optionally making sure the thread
++ descriptor is still valid. */
++void
++internal_function
++__free_tcb (struct pthread *pd)
++{
++ /* The thread is exiting now. */
++ if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling,
++ TERMINATED_BIT) == 0, 1))
++ {
++ /* Remove the descriptor from the list. */
++ if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
++ /* Something is really wrong. The descriptor for a still
++ running thread is gone. */
++ abort ();
++
++ /* Queue the stack memory block for reuse and exit the process. The
++ kernel will signal via writing to the address returned by
++ QUEUE-STACK when the stack is available. */
++ __deallocate_stack (pd);
++ }
++}
++
++
++static int
++start_thread (void *arg)
++{
++ struct pthread *pd = (struct pthread *) arg;
++
++#if HP_TIMING_AVAIL
++ /* Remember the time when the thread was started. */
++ hp_timing_t now;
++ HP_TIMING_NOW (now);
++ THREAD_SETMEM (pd, cpuclock_offset, now);
++#endif
++
++ /* Initialize resolver state pointer. */
++ __resp = &pd->res;
++
++ /* This is where the try/finally block should be created. For
++ compilers without that support we do use setjmp. */
++ struct pthread_unwind_buf unwind_buf;
++
++ /* No previous handlers. */
++ unwind_buf.priv.data.prev = NULL;
++ unwind_buf.priv.data.cleanup = NULL;
++
++ int not_first_call;
++ not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
++ if (__builtin_expect (! not_first_call, 1))
++ {
++ /* Store the new cleanup handler info. */
++ THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
++
++ if (__builtin_expect (pd->stopped_start, 0))
++ {
++ int oldtype = CANCEL_ASYNC ();
++
++ /* Get the lock the parent locked to force synchronization. */
++ lll_lock (pd->lock);
++ /* And give it up right away. */
++ lll_unlock (pd->lock);
++
++ CANCEL_RESET (oldtype);
++ }
++
++ /* Run the code the user provided. */
++#ifdef CALL_THREAD_FCT
++ THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd));
++#else
++ THREAD_SETMEM (pd, result, pd->start_routine (pd->arg));
++#endif
++ }
++
++ /* Run the destructor for the thread-local data. */
++ __nptl_deallocate_tsd ();
++
++ /* Clean up any state libc stored in thread-local variables. */
++ __libc_thread_freeres ();
++
++ /* If this is the last thread we terminate the process now. We
++ do not notify the debugger, it might just irritate it if there
++ is no thread left. */
++ if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0))
++ /* This was the last thread. */
++ exit (0);
++
++ /* Report the death of the thread if this is wanted. */
++ if (__builtin_expect (pd->report_events, 0))
++ {
++ /* See whether TD_DEATH is in any of the mask. */
++ const int idx = __td_eventword (TD_DEATH);
++ const uint32_t mask = __td_eventmask (TD_DEATH);
++
++ if ((mask & (__nptl_threads_events.event_bits[idx]
++ | pd->eventbuf.eventmask.event_bits[idx])) != 0)
++ {
++ /* Yep, we have to signal the death. Add the descriptor to
++ the list but only if it is not already on it. */
++ if (pd->nextevent == NULL)
++ {
++ pd->eventbuf.eventnum = TD_DEATH;
++ pd->eventbuf.eventdata = pd;
++
++ do
++ pd->nextevent = __nptl_last_event;
++ while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
++ pd, pd->nextevent));
++ }
++
++ /* Now call the function to signal the event. */
++ __nptl_death_event ();
++ }
++ }
++
++ /* The thread is exiting now. Don't set this bit until after we've hit
++ the event-reporting breakpoint, so that td_thr_get_info on us while at
++ the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE. */
++ atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
++
++ /* If the thread is detached free the TCB. */
++ if (IS_DETACHED (pd))
++ /* Free the TCB. */
++ __free_tcb (pd);
++
++ /* We cannot call '_exit' here. '_exit' will terminate the process.
++
++ The 'exit' implementation in the kernel will signal when the
++ process is really dead since 'clone' got passed the CLONE_CLEARTID
++ flag. The 'tid' field in the TCB will be set to zero.
++
++ The exit code is zero since in case all threads exit by calling
++ 'pthread_exit' the exit status must be 0 (zero). */
++#if 0
++ __exit_thread_inline (0);
++#else
++ __exit_thread (0);
++#endif
++
++ /* NOTREACHED */
++ return 0;
++}
++
++
++/* Default thread attributes for the case when the user does not
++ provide any. */
++static const struct pthread_attr default_attr =
++ {
++ /* Just some value > 0 which gets rounded to the nearest page size. */
++ .guardsize = 1,
++ };
++
++
++int
++__pthread_create_2_1 (newthread, attr, start_routine, arg)
++ pthread_t *newthread;
++ const pthread_attr_t *attr;
++ void *(*start_routine) (void *);
++ void *arg;
++{
++ STACK_VARIABLES;
++ const struct pthread_attr *iattr;
++ struct pthread *pd;
++ int err;
++
++ iattr = (struct pthread_attr *) attr;
++ if (iattr == NULL)
++ /* Is this the best idea? On NUMA machines this could mean
++ accessing far-away memory. */
++ iattr = &default_attr;
++
++ err = ALLOCATE_STACK (iattr, &pd);
++ if (__builtin_expect (err != 0, 0))
++ /* Something went wrong. Maybe a parameter of the attributes is
++ invalid or we could not allocate memory. */
++ return err;
++
++
++ /* Initialize the TCB. All initializations with zero should be
++ performed in 'get_cached_stack'. This way we avoid doing this if
++ the stack freshly allocated with 'mmap'. */
++
++#ifdef TLS_TCB_AT_TP
++ /* Reference to the TCB itself. */
++ pd->header.self = pd;
++
++ /* Self-reference for TLS. */
++ pd->header.tcb = pd;
++#endif
++
++ /* Store the address of the start routine and the parameter. Since
++ we do not start the function directly the stillborn thread will
++ get the information from its thread descriptor. */
++ pd->start_routine = start_routine;
++ pd->arg = arg;
++
++ /* Copy the thread attribute flags. */
++ struct pthread *self = THREAD_SELF;
++ pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
++ | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
++
++ /* Initialize the field for the ID of the thread which is waiting
++ for us. This is a self-reference in case the thread is created
++ detached. */
++ pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
++
++ /* The debug events are inherited from the parent. */
++ pd->eventbuf = self->eventbuf;
++
++
++ /* Copy the parent's scheduling parameters. The flags will say what
++ is valid and what is not. */
++ pd->schedpolicy = self->schedpolicy;
++ pd->schedparam = self->schedparam;
++
++ /* Determine scheduling parameters for the thread. */
++ if (attr != NULL
++ && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
++ && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0)
++ {
++#if 0
++ INTERNAL_SYSCALL_DECL (err);
++
++ /* Use the scheduling parameters the user provided. */
++ if (iattr->flags & ATTR_FLAG_POLICY_SET)
++ pd->schedpolicy = iattr->schedpolicy;
++ else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
++ {
++ pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, err, 1, 0);
++ pd->flags |= ATTR_FLAG_POLICY_SET;
++ }
++
++ if (iattr->flags & ATTR_FLAG_SCHED_SET)
++ memcpy (&pd->schedparam, &iattr->schedparam,
++ sizeof (struct sched_param));
++ else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
++ {
++ INTERNAL_SYSCALL (sched_getparam, err, 2, 0, &pd->schedparam);
++ pd->flags |= ATTR_FLAG_SCHED_SET;
++ }
++
++ /* Check for valid priorities. */
++ int minprio = INTERNAL_SYSCALL (sched_get_priority_min, err, 1,
++ iattr->schedpolicy);
++ int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, err, 1,
++ iattr->schedpolicy);
++ if (pd->schedparam.sched_priority < minprio
++ || pd->schedparam.sched_priority > maxprio)
++ {
++ err = EINVAL;
++ goto errout;
++ }
++#endif
++ }
++
++ /* Pass the descriptor to the caller. */
++ *newthread = (pthread_t) pd;
++
++ /* Remember whether the thread is detached or not. In case of an
++ error we have to free the stacks of non-detached stillborn
++ threads. */
++ bool is_detached = IS_DETACHED (pd);
++
++ /* Start the thread. */
++ err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
++ if (err != 0)
++ {
++ /* Something went wrong. Free the resources. */
++ if (!is_detached)
++ {
++ errout:
++ __deallocate_stack (pd);
++ }
++ return err;
++ }
++
++ return 0;
++}
++versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);
++
++
++#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
++int
++__pthread_create_2_0 (newthread, attr, start_routine, arg)
++ pthread_t *newthread;
++ const pthread_attr_t *attr;
++ void *(*start_routine) (void *);
++ void *arg;
++{
++ /* The ATTR attribute is not really of type `pthread_attr_t *'. It has
++ the old size and access to the new members might crash the program.
++ We convert the struct now. */
++ struct pthread_attr new_attr;
++
++ if (attr != NULL)
++ {
++ struct pthread_attr *iattr = (struct pthread_attr *) attr;
++ size_t ps = __getpagesize ();
++
++ /* Copy values from the user-provided attributes. */
++ new_attr.schedparam = iattr->schedparam;
++ new_attr.schedpolicy = iattr->schedpolicy;
++ new_attr.flags = iattr->flags;
++
++ /* Fill in default values for the fields not present in the old
++ implementation. */
++ new_attr.guardsize = ps;
++ new_attr.stackaddr = NULL;
++ new_attr.stacksize = 0;
++ new_attr.cpuset = NULL;
++
++ /* We will pass this value on to the real implementation. */
++ attr = (pthread_attr_t *) &new_attr;
++ }
++
++ return __pthread_create_2_1 (newthread, attr, start_routine, arg);
++}
++compat_symbol (libpthread, __pthread_create_2_0, pthread_create,
++ GLIBC_2_0);
++#endif
++
++/* Information for libthread_db. */
++
++#include "../nptl_db/db_info.c"
++
++/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread
++ functions to be present as well. */
++PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock)
++PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock)
++
++PTHREAD_STATIC_FN_REQUIRE (pthread_once)
++PTHREAD_STATIC_FN_REQUIRE (pthread_cancel)
++
++PTHREAD_STATIC_FN_REQUIRE (pthread_key_create)
++PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific)
++PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific)
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_getaffinity.c libc/nptl/sysdeps/l4/hurd/pthread_getaffinity.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_getaffinity.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_getaffinity.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,62 @@
++/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <limits.h>
++#include <pthreadP.h>
++#include <string.h>
++#include <sysdep.h>
++#include <sys/param.h>
++#include <sys/types.h>
++#include <shlib-compat.h>
++
++
++int
++__pthread_getaffinity_new (pthread_t th, size_t cpusetsize, cpu_set_t *cpuset)
++{
++ const struct pthread *pd = (const struct pthread *) th;
++
++#if 0
++ INTERNAL_SYSCALL_DECL (err);
++ int res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, pd->tid,
++ MIN (INT_MAX, cpusetsize), cpuset);
++ if (INTERNAL_SYSCALL_ERROR_P (res, err))
++ return INTERNAL_SYSCALL_ERRNO (res, err);
++
++ /* Clean the rest of the memory the kernel didn't do. */
++ memset ((char *) cpuset + res, '\0', cpusetsize - res);
++
++#endif
++ return 0;
++}
++strong_alias (__pthread_getaffinity_new, __pthread_getaffinity_np)
++versioned_symbol (libpthread, __pthread_getaffinity_new,
++ pthread_getaffinity_np, GLIBC_2_3_4);
++
++
++#if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4)
++int
++__pthread_getaffinity_old (pthread_t th, cpu_set_t *cpuset)
++{
++ /* The old interface by default assumed a 1024 processor bitmap. */
++ return __pthread_getaffinity_new (th, 128, cpuset);
++}
++compat_symbol (libpthread, __pthread_getaffinity_old, pthread_getaffinity_np,
++ GLIBC_2_3_3);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_kill.c libc/nptl/sysdeps/l4/hurd/pthread_kill.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_kill.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_kill.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,42 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <signal.h>
++#include <pthreadP.h>
++#include <tls.h>
++#include <sysdep.h>
++
++
++int
++__pthread_kill (threadid, signo)
++ pthread_t threadid;
++ int signo;
++{
++ struct pthread *pd = (struct pthread *) threadid;
++
++ /* Make sure the descriptor is valid. */
++ if (INVALID_TD_P (pd))
++ /* Not a valid thread handle. */
++ return ESRCH;
++
++ /*FIXME*/
++ return ENOSYS;
++}
++strong_alias (__pthread_kill, pthread_kill)
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_mutex_cond_lock.c libc/nptl/sysdeps/l4/hurd/pthread_mutex_cond_lock.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_mutex_cond_lock.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_mutex_cond_lock.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,8 @@
++#include <pthreadP.h>
++
++#define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex)
++#define LLL_MUTEX_TRYLOCK(mutex) lll_mutex_cond_trylock(mutex)
++#define __pthread_mutex_lock __pthread_mutex_cond_lock
++#define NO_INCR
++
++#include <nptl/pthread_mutex_lock.c>
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_setaffinity.c libc/nptl/sysdeps/l4/hurd/pthread_setaffinity.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_setaffinity.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_setaffinity.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,102 @@
++/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <alloca.h>
++#include <errno.h>
++#include <pthreadP.h>
++#include <sysdep.h>
++#include <sys/types.h>
++#include <shlib-compat.h>
++
++
++/* Determine the current affinity. As a side affect we learn
++ about the size of the cpumask_t in the kernel. */
++int
++__determine_cpumask_size (pid_t tid)
++{
++#if 0
++ INTERNAL_SYSCALL_DECL (err);
++#endif
++ int res;
++
++#if 0
++ size_t psize = 128;
++ void *p = alloca (psize);
++
++ while (res = INTERNAL_SYSCALL (sched_getaffinity, err, 3, tid, psize, p),
++ INTERNAL_SYSCALL_ERROR_P (res, err)
++ && INTERNAL_SYSCALL_ERRNO (res, err) == EINVAL)
++ p = extend_alloca (p, psize, 2 * psize);
++
++ if (res == 0 || INTERNAL_SYSCALL_ERROR_P (res, err))
++ return INTERNAL_SYSCALL_ERRNO (res, err);
++
++ __kernel_cpumask_size = res;
++#endif
++
++ return 0;
++}
++
++
++int
++__pthread_setaffinity_new (pthread_t th, size_t cpusetsize,
++ const cpu_set_t *cpuset)
++{
++ const struct pthread *pd = (const struct pthread *) th;
++
++#if 0
++ INTERNAL_SYSCALL_DECL (err);
++ int res;
++
++ if (__builtin_expect (__kernel_cpumask_size == 0, 0))
++ {
++ res = __determine_cpumask_size (pd->tid);
++ if (res != 0)
++ return res;
++ }
++
++ /* We now know the size of the kernel cpumask_t. Make sure the user
++ does not request to set a bit beyond that. */
++ for (size_t cnt = __kernel_cpumask_size; cnt < cpusetsize; ++cnt)
++ if (((char *) cpuset)[cnt] != '\0')
++ /* Found a nonzero byte. This means the user request cannot be
++ fulfilled. */
++ return EINVAL;
++
++ res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid, cpusetsize,
++ cpuset);
++ return (INTERNAL_SYSCALL_ERROR_P (res, err)
++ ? INTERNAL_SYSCALL_ERRNO (res, err)
++ : 0);
++#endif
++}
++versioned_symbol (libpthread, __pthread_setaffinity_new,
++ pthread_setaffinity_np, GLIBC_2_3_4);
++
++
++#if SHLIB_COMPAT (libpthread, GLIBC_2_3_3, GLIBC_2_3_4)
++int
++__pthread_setaffinity_old (pthread_t th, cpu_set_t *cpuset)
++{
++ /* The old interface by default assumed a 1024 processor bitmap. */
++ return __pthread_setaffinity_new (th, 128, cpuset);
++}
++compat_symbol (libpthread, __pthread_setaffinity_old, pthread_setaffinity_np,
++ GLIBC_2_3_3);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_sigmask.c libc/nptl/sysdeps/l4/hurd/pthread_sigmask.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_sigmask.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_sigmask.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,33 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <signal.h>
++#include <pthreadP.h>
++#include <sysdep.h>
++
++
++int
++pthread_sigmask (how, newmask, oldmask)
++ int how;
++ const sigset_t *newmask;
++ sigset_t *oldmask;
++{
++ return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/pthread_yield.c libc/nptl/sysdeps/l4/hurd/pthread_yield.c
+--- libc/nptl/sysdeps/l4/hurd/pthread_yield.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/pthread_yield.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,30 @@
++/* Copyright (C) 2002 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <pthread.h>
++#include <sched.h>
++
++
++/* With the 1-on-1 model we implement this function is equivalent to
++ the 'sched_yield' function. */
++int
++pthread_yield (void)
++{
++ return sched_yield ();
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/register-atfork.c libc/nptl/sysdeps/l4/hurd/register-atfork.c
+--- libc/nptl/sysdeps/l4/hurd/register-atfork.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/register-atfork.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,135 @@
++/* 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 <errno.h>
++#include <stdlib.h>
++#include <string.h>
++#include "fork.h"
++
++
++/* Lock to protect allocation and deallocation of fork handlers. */
++lll_lock_t __fork_lock = LLL_LOCK_INITIALIZER;
++
++
++/* Number of pre-allocated handler entries. */
++#define NHANDLER 48
++
++/* Memory pool for fork handler structures. */
++static struct fork_handler_pool
++{
++ struct fork_handler_pool *next;
++ struct fork_handler mem[NHANDLER];
++} fork_handler_pool;
++
++
++static struct fork_handler *
++fork_handler_alloc (void)
++{
++ struct fork_handler_pool *runp = &fork_handler_pool;
++ struct fork_handler *result = NULL;
++ unsigned int i;
++
++ do
++ {
++ /* Search for an empty entry. */
++ for (i = 0; i < NHANDLER; ++i)
++ if (runp->mem[i].refcntr == 0)
++ goto found;
++ }
++ while ((runp = runp->next) != NULL);
++
++ /* We have to allocate a new entry. */
++ runp = (struct fork_handler_pool *) calloc (1, sizeof (*runp));
++ if (runp != NULL)
++ {
++ /* Enqueue the new memory pool into the list. */
++ runp->next = fork_handler_pool.next;
++ fork_handler_pool.next = runp;
++
++ /* We use the last entry on the page. This means when we start
++ searching from the front the next time we will find the first
++ entry unused. */
++ i = NHANDLER - 1;
++
++ found:
++ result = &runp->mem[i];
++ result->refcntr = 1;
++ result->need_signal = 0;
++ }
++
++ return result;
++}
++
++
++int
++__register_atfork (prepare, parent, child, dso_handle)
++ void (*prepare) (void);
++ void (*parent) (void);
++ void (*child) (void);
++ void *dso_handle;
++{
++ /* Get the lock to not conflict with other allocations. */
++ lll_lock (__fork_lock);
++
++ struct fork_handler *newp = fork_handler_alloc ();
++
++ if (newp != NULL)
++ {
++ /* Initialize the new record. */
++ newp->prepare_handler = prepare;
++ newp->parent_handler = parent;
++ newp->child_handler = child;
++ newp->dso_handle = dso_handle;
++
++ newp->next = __fork_handlers;
++ __fork_handlers = newp;
++ }
++
++ /* Release the lock. */
++ lll_unlock (__fork_lock);
++
++ return newp == NULL ? ENOMEM : 0;
++}
++libc_hidden_def (__register_atfork)
++
++
++libc_freeres_fn (free_mem)
++{
++ /* Get the lock to not conflict with running forks. */
++ lll_lock (__fork_lock);
++
++ /* No more fork handlers. */
++ __fork_handlers = NULL;
++
++ /* Free eventually alloated memory blocks for the object pool. */
++ struct fork_handler_pool *runp = fork_handler_pool.next;
++
++ memset (&fork_handler_pool, '\0', sizeof (fork_handler_pool));
++
++ /* Release the lock. */
++ lll_unlock (__fork_lock);
++
++ /* We can free the memory after releasing the lock. */
++ while (runp != NULL)
++ {
++ struct fork_handler_pool *oldp = runp;
++ runp = runp->next;
++ free (oldp);
++ }
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/sem_open.c libc/nptl/sysdeps/l4/hurd/sem_open.c
+--- libc/nptl/sysdeps/l4/hurd/sem_open.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/sem_open.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,414 @@
++/* 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 <errno.h>
++#include <fcntl.h>
++#include <mntent.h>
++#include <paths.h>
++#include <pthread.h>
++#include <search.h>
++#include <semaphore.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/mman.h>
++#include <sys/stat.h>
++#include <sys/statfs.h>
++#include "semaphoreP.h"
++
++
++
++/* Information about the mount point. */
++struct mountpoint_info mountpoint attribute_hidden;
++
++/* This is the default mount point. */
++static const char defaultmount[] = "/dev/shm";
++/* This is the default directory. */
++static const char defaultdir[] = "/dev/shm/sem.";
++
++/* Protect the `mountpoint' variable above. */
++pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT;
++
++
++/* Determine where the shmfs is mounted (if at all). */
++void
++attribute_hidden
++__where_is_shmfs (void)
++{
++ char buf[512];
++ struct statfs f;
++ struct mntent resmem;
++ struct mntent *mp;
++ FILE *fp;
++
++#if 0
++ /* The canonical place is /dev/shm. This is at least what the
++ documentation tells everybody to do. */
++ if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
++ {
++ /* It is in the normal place. */
++ mountpoint.dir = (char *) defaultdir;
++ mountpoint.dirlen = sizeof (defaultdir) - 1;
++
++ return;
++ }
++#endif
++
++ /* OK, do it the hard way. Look through the /proc/mounts file and if
++ this does not exist through /etc/fstab to find the mount point. */
++ fp = __setmntent ("/proc/mounts", "r");
++ if (__builtin_expect (fp == NULL, 0))
++ {
++ fp = __setmntent (_PATH_MNTTAB, "r");
++ if (__builtin_expect (fp == NULL, 0))
++ /* There is nothing we can do. Blind guesses are not helpful. */
++ return;
++ }
++
++ /* Now read the entries. */
++ while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
++ /* The original name is "shm" but this got changed in early Linux
++ 2.4.x to "tmpfs". */
++ if (strcmp (mp->mnt_type, "tmpfs") == 0
++ || strcmp (mp->mnt_type, "shm") == 0)
++ {
++ /* Found it. There might be more than one place where the
++ filesystem is mounted but one is enough for us. */
++ size_t namelen;
++
++ /* First make sure this really is the correct entry. At least
++ some versions of the kernel give wrong information because
++ of the implicit mount of the shmfs for SysV IPC. */
++#if 0
++ if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
++ continue;
++#endif
++
++ namelen = strlen (mp->mnt_dir);
++
++ if (namelen == 0)
++ /* Hum, maybe some crippled entry. Keep on searching. */
++ continue;
++
++ mountpoint.dir = (char *) malloc (namelen + 4 + 2);
++ if (mountpoint.dir != NULL)
++ {
++ char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
++ if (cp[-1] != '/')
++ *cp++ = '/';
++ cp = stpcpy (cp, "sem.");
++ mountpoint.dirlen = cp - mountpoint.dir;
++ }
++
++ break;
++ }
++
++ /* Close the stream. */
++ __endmntent (fp);
++}
++
++
++/* Comparison function for search of existing mapping. */
++int
++attribute_hidden
++__sem_search (const void *a, const void *b)
++{
++ const struct inuse_sem *as = (const struct inuse_sem *) a;
++ const struct inuse_sem *bs = (const struct inuse_sem *) b;
++
++ if (as->ino != bs->ino)
++ /* Cannot return the difference the type is larger than int. */
++ return as->ino < bs->ino ? -1 : (as->ino == bs->ino ? 0 : 1);
++
++ if (as->dev != bs->dev)
++ /* Cannot return the difference the type is larger than int. */
++ return as->dev < bs->dev ? -1 : (as->dev == bs->dev ? 0 : 1);
++
++ return strcmp (as->name, bs->name);
++}
++
++
++/* The search tree for existing mappings. */
++void *__sem_mappings attribute_hidden;
++
++/* Lock to protect the search tree. */
++lll_lock_t __sem_mappings_lock = LLL_LOCK_INITIALIZER;
++
++
++/* Search for existing mapping and if possible add the one provided. */
++static sem_t *
++check_add_mapping (const char *name, size_t namelen, int fd, sem_t *existing)
++{
++ sem_t *result = SEM_FAILED;
++
++ /* Get the information about the file. */
++ struct stat64 st;
++ if (__fxstat64 (_STAT_VER, fd, &st) == 0)
++ {
++ /* Get the lock. */
++ lll_lock (__sem_mappings_lock);
++
++ /* Search for an existing mapping given the information we have. */
++ struct inuse_sem *fake;
++ fake = (struct inuse_sem *) alloca (sizeof (*fake) + namelen);
++ memcpy (fake->name, name, namelen);
++ fake->dev = st.st_dev;
++ fake->ino = st.st_ino;
++
++ struct inuse_sem **foundp = tfind (fake, &__sem_mappings, __sem_search);
++ if (foundp != NULL)
++ {
++ /* There is already a mapping. Use it. */
++ result = (*foundp)->sem;
++ ++(*foundp)->refcnt;
++ }
++ else
++ {
++ /* We haven't found a mapping. Install ione. */
++ struct inuse_sem *newp;
++
++ newp = (struct inuse_sem *) malloc (sizeof (*newp) + namelen);
++ if (newp != NULL)
++ {
++ /* If the caller hasn't provided any map it now. */
++ if (existing == SEM_FAILED)
++ existing = (sem_t *) mmap (NULL, sizeof (sem_t),
++ PROT_READ | PROT_WRITE, MAP_SHARED,
++ fd, 0);
++
++ newp->dev = st.st_dev;
++ newp->ino = st.st_ino;
++ newp->refcnt = 1;
++ newp->sem = existing;
++ memcpy (newp->name, name, namelen);
++
++ /* Insert the new value. */
++ if (existing != MAP_FAILED
++ && tsearch (newp, &__sem_mappings, __sem_search) != NULL)
++ /* Successful. */
++ result = existing;
++ else
++ /* Something went wrong while inserting the new
++ value. We fail completely. */
++ free (newp);
++ }
++ }
++
++ /* Release the lock. */
++ lll_unlock (__sem_mappings_lock);
++ }
++
++ if (result != existing && existing != SEM_FAILED && existing != MAP_FAILED)
++ {
++ /* Do not disturb errno. */
++#if 0
++ /* FIXME */
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (munmap, err, 2, existing, sizeof (sem_t));
++#endif
++ }
++
++ return result;
++}
++
++
++sem_t *
++sem_open (const char *name, int oflag, ...)
++{
++ char *finalname;
++ sem_t *result = SEM_FAILED;
++ int fd;
++
++ /* Determine where the shmfs is mounted. */
++ INTUSE(__pthread_once) (&__namedsem_once, __where_is_shmfs);
++
++ /* If we don't know the mount points there is nothing we can do. Ever. */
++ if (mountpoint.dir == NULL)
++ {
++ __set_errno (ENOSYS);
++ return SEM_FAILED;
++ }
++
++ /* Construct the filename. */
++ while (name[0] == '/')
++ ++name;
++
++ if (name[0] == '\0')
++ {
++ /* The name "/" is not supported. */
++ __set_errno (EINVAL);
++ return SEM_FAILED;
++ }
++ size_t namelen = strlen (name) + 1;
++
++ /* Create the name of the final file. */
++ finalname = (char *) alloca (mountpoint.dirlen + namelen);
++ __mempcpy (__mempcpy (finalname, mountpoint.dir, mountpoint.dirlen),
++ name, namelen);
++
++ /* If the semaphore object has to exist simply open it. */
++ if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0)
++ {
++ try_again:
++ fd = __libc_open (finalname,
++ (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR);
++
++ if (fd == -1)
++ {
++ /* If we are supposed to create the file try this next. */
++ if ((oflag & O_CREAT) != 0 && errno == ENOENT)
++ goto try_create;
++
++ /* Return. errno is already set. */
++ }
++ else
++ /* Check whether we already have this semaphore mapped and
++ create one if necessary. */
++ result = check_add_mapping (name, namelen, fd, SEM_FAILED);
++ }
++ else
++ {
++ /* We have to open a temporary file first since it must have the
++ correct form before we can start using it. */
++ char *tmpfname;
++ mode_t mode;
++ unsigned int value;
++ va_list ap;
++
++ try_create:
++ va_start (ap, oflag);
++
++ mode = va_arg (ap, mode_t);
++ value = va_arg (ap, unsigned int);
++
++ va_end (ap);
++
++ if (value > SEM_VALUE_MAX)
++ {
++ __set_errno (EINVAL);
++ return SEM_FAILED;
++ }
++
++ /* Create the initial file content. */
++ sem_t initsem;
++
++ struct sem *iinitsem = (struct sem *) &initsem;
++ iinitsem->count = value;
++
++ /* Initialize the remaining bytes as well. */
++ memset ((char *) &initsem + sizeof (struct sem), '\0',
++ sizeof (sem_t) - sizeof (struct sem));
++
++ tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
++ char *xxxxxx = __mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen);
++
++ int retries = 0;
++#define NRETRIES 50
++ while (1)
++ {
++ /* Add the suffix for mktemp. */
++ strcpy (xxxxxx, "XXXXXX");
++
++ /* We really want to use mktemp here. We cannot use mkstemp
++ since the file must be opened with a specific mode. The
++ mode cannot later be set since then we cannot apply the
++ file create mask. */
++ if (mktemp (tmpfname) == NULL)
++ return SEM_FAILED;
++
++ /* Open the file. Make sure we do not overwrite anything. */
++ fd = __libc_open (tmpfname, O_RDWR | O_CREAT | O_EXCL, mode);
++ if (fd == -1)
++ {
++ if (errno == EEXIST)
++ {
++ if (++retries < NRETRIES)
++ continue;
++
++ __set_errno (EAGAIN);
++ }
++
++ return SEM_FAILED;
++ }
++
++ /* We got a file. */
++ break;
++ }
++
++ if (TEMP_FAILURE_RETRY (__libc_write (fd, &initsem, sizeof (sem_t)))
++ == sizeof (sem_t)
++ /* Map the sem_t structure from the file. */
++ && (result = (sem_t *) mmap (NULL, sizeof (sem_t),
++ PROT_READ | PROT_WRITE, MAP_SHARED,
++ fd, 0)) != MAP_FAILED)
++ {
++ /* Create the file. Don't overwrite an existing file. */
++ if (link (tmpfname, finalname) != 0)
++ {
++ /* Undo the mapping. */
++ (void) munmap (result, sizeof (sem_t));
++
++ /* Reinitialize 'result'. */
++ result = SEM_FAILED;
++
++ /* This failed. If O_EXCL is not set and the problem was
++ that the file exists, try again. */
++ if ((oflag & O_EXCL) == 0 && errno == EEXIST)
++ {
++ /* Remove the file. */
++ (void) unlink (tmpfname);
++
++ /* Close the file. */
++ (void) __libc_close (fd);
++
++ goto try_again;
++ }
++ }
++ else
++ /* Insert the mapping into the search tree. This also
++ determines whether another thread sneaked by and already
++ added such a mapping despite the fact that we created it. */
++ result = check_add_mapping (name, namelen, fd, result);
++ }
++
++ /* Now remove the temporary name. This should never fail. If
++ it fails we leak a file name. Better fix the kernel. */
++ (void) unlink (tmpfname);
++ }
++
++ /* Map the mmap error to the error we need. */
++ if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED)
++ result = SEM_FAILED;
++
++ /* We don't need the file descriptor anymore. */
++ if (fd != -1)
++ {
++#if 0
++ /* FIXME */
++
++ /* Do not disturb errno. */
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (close, err, 1, fd);
++#endif
++ }
++
++ return result;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/sem_post.c libc/nptl/sysdeps/l4/hurd/sem_post.c
+--- libc/nptl/sysdeps/l4/hurd/sem_post.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/sem_post.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,49 @@
++/* sem_post -- post to a POSIX semaphore. Generic futex-using version.
++ Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <sysdep.h>
++#include <lowlevellock.h>
++#include <internaltypes.h>
++#include <semaphore.h>
++
++#include <shlib-compat.h>
++
++int
++__new_sem_post (sem_t *sem)
++{
++ int *futex = (int *) sem;
++
++ int nr = atomic_increment_val (futex);
++#if 0
++ int err = lll_futex_wake (futex, nr);
++ if (__builtin_expect (err, 0) < 0)
++ {
++ __set_errno (-err);
++ return -1;
++ }
++#endif
++ return 0;
++}
++versioned_symbol (libpthread, __new_sem_post, sem_post, GLIBC_2_1);
++#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
++strong_alias (__new_sem_post, __old_sem_post)
++compat_symbol (libpthread, __old_sem_post, sem_post, GLIBC_2_0);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/sem_timedwait.c libc/nptl/sysdeps/l4/hurd/sem_timedwait.c
+--- libc/nptl/sysdeps/l4/hurd/sem_timedwait.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/sem_timedwait.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,102 @@
++/* sem_timedwait -- wait on a semaphore. Generic futex-using version.
++ Copyright (C) 2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <sysdep.h>
++#include <lowlevellock.h>
++#include <internaltypes.h>
++#include <semaphore.h>
++
++#include <pthreadP.h>
++#include <shlib-compat.h>
++
++
++int
++sem_timedwait (sem_t *sem, const struct timespec *abstime)
++{
++ /* First check for cancellation. */
++ CANCELLATION_P (THREAD_SELF);
++
++ int *futex = (int *) sem;
++ int val;
++ int err;
++
++ if (*futex > 0)
++ {
++ val = atomic_decrement_if_positive (futex);
++ if (val > 0)
++ return 0;
++ }
++
++ err = -EINVAL;
++ if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)
++ goto error_return;
++
++ do
++ {
++ struct timeval tv;
++ struct timespec rt;
++ int sec, nsec;
++
++ /* Get the current time. */
++ __gettimeofday (&tv, NULL);
++
++ /* Compute relative timeout. */
++ sec = abstime->tv_sec - tv.tv_sec;
++ nsec = abstime->tv_nsec - tv.tv_usec * 1000;
++ if (nsec < 0)
++ {
++ nsec += 1000000000;
++ --sec;
++ }
++
++ /* Already timed out? */
++ err = -ETIMEDOUT;
++ if (sec < 0)
++ goto error_return;
++
++ /* Do wait. */
++ rt.tv_sec = sec;
++ rt.tv_nsec = nsec;
++
++ /* Enable asynchronous cancellation. Required by the standard. */
++ int oldtype = __pthread_enable_asynccancel ();
++
++#if 0
++ /* FIXME*/
++ err = lll_futex_timed_wait (futex, 0, &rt);
++#endif
++
++ /* Disable asynchronous cancellation. */
++ __pthread_disable_asynccancel (oldtype);
++
++ if (err != 0 && err != -EWOULDBLOCK)
++ goto error_return;
++
++ val = atomic_decrement_if_positive (futex);
++ }
++ while (val <= 0);
++
++ return 0;
++
++ error_return:
++ __set_errno (-err);
++ return -1;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/sem_trywait.c libc/nptl/sysdeps/l4/hurd/sem_trywait.c
+--- libc/nptl/sysdeps/l4/hurd/sem_trywait.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/sem_trywait.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,50 @@
++/* sem_trywait -- wait on a semaphore. Generic futex-using version.
++ Copyright (C) 2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <sysdep.h>
++#include <lowlevellock.h>
++#include <internaltypes.h>
++#include <semaphore.h>
++
++#include <shlib-compat.h>
++
++
++int
++__new_sem_trywait (sem_t *sem)
++{
++ int *futex = (int *) sem;
++ int val;
++
++ if (*futex > 0)
++ {
++ val = atomic_decrement_if_positive (futex);
++ if (val > 0)
++ return 0;
++ }
++
++ __set_errno (EAGAIN);
++ return -1;
++}
++versioned_symbol (libpthread, __new_sem_trywait, sem_trywait, GLIBC_2_1);
++#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
++strong_alias (__new_sem_trywait, __old_sem_trywait)
++compat_symbol (libpthread, __old_sem_trywait, sem_trywait, GLIBC_2_0);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/sem_wait.c libc/nptl/sysdeps/l4/hurd/sem_wait.c
+--- libc/nptl/sysdeps/l4/hurd/sem_wait.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/sem_wait.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,66 @@
++/* sem_wait -- wait on a semaphore. Generic futex-using version.
++ Copyright (C) 2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Paul Mackerras <paulus@au.ibm.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <sysdep.h>
++#include <lowlevellock.h>
++#include <internaltypes.h>
++#include <semaphore.h>
++
++#include <pthreadP.h>
++#include <shlib-compat.h>
++
++
++int
++__new_sem_wait (sem_t *sem)
++{
++ /* First check for cancellation. */
++ CANCELLATION_P (THREAD_SELF);
++
++ int *futex = (int *) sem;
++ int err;
++
++ do
++ {
++ if (atomic_decrement_if_positive (futex) > 0)
++ return 0;
++
++ /* Enable asynchronous cancellation. Required by the standard. */
++ int oldtype = __pthread_enable_asynccancel ();
++
++#if 0
++ /*FIXME*/
++ err = lll_futex_wait (futex, 0);
++#endif
++
++ /* Disable asynchronous cancellation. */
++ __pthread_disable_asynccancel (oldtype);
++ }
++ while (err == 0 || err == -EWOULDBLOCK);
++
++ __set_errno (-err);
++ return -1;
++}
++
++versioned_symbol (libpthread, __new_sem_wait, sem_wait, GLIBC_2_1);
++#if SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_1)
++strong_alias (__new_sem_wait, __old_sem_wait)
++compat_symbol (libpthread, __old_sem_wait, sem_wait, GLIBC_2_0);
++#endif
+diff -x CVS -rupN libc/nptl/sysdeps/l4/hurd/unregister-atfork.c libc/nptl/sysdeps/l4/hurd/unregister-atfork.c
+--- libc/nptl/sysdeps/l4/hurd/unregister-atfork.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/hurd/unregister-atfork.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,111 @@
++/* 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 <errno.h>
++#include <stdlib.h>
++#include "fork.h"
++#include <atomic.h>
++
++
++void
++__unregister_atfork (dso_handle)
++ void *dso_handle;
++{
++ /* Check whether there is any entry in the list which we have to
++ remove. It is likely that this is not the case so don't bother
++ getting the lock.
++
++ We do not worry about other threads adding entries for this DSO
++ right this moment. If this happens this is a race and we can do
++ whatever we please. The program will crash anyway seen. */
++ struct fork_handler *runp = __fork_handlers;
++ struct fork_handler *lastp = NULL;
++
++ while (runp != NULL)
++ if (runp->dso_handle == dso_handle)
++ break;
++ else
++ {
++ lastp = runp;
++ runp = runp->next;
++ }
++
++ if (runp == NULL)
++ /* Nothing to do. */
++ return;
++
++ /* Get the lock to not conflict with additions or deletions. Note
++ that there couldn't have been another thread deleting something.
++ The __unregister_atfork function is only called from the
++ dlclose() code which itself serializes the operations. */
++ lll_lock (__fork_lock);
++
++ /* We have to create a new list with all the entries we don't remove. */
++ struct deleted_handler
++ {
++ struct fork_handler *handler;
++ struct deleted_handler *next;
++ } *deleted = NULL;
++
++ /* Remove the entries for the DSO which is unloaded from the list.
++ It's a single linked list so readers are. */
++ do
++ {
++ if (runp->dso_handle == dso_handle)
++ {
++ if (lastp == NULL)
++ __fork_handlers = runp->next;
++ else
++ lastp->next = runp->next;
++
++ /* We cannot overwrite the ->next element now. Put the deleted
++ entries in a separate list. */
++ struct deleted_handler *newp = alloca (sizeof (*newp));
++ newp->handler = runp;
++ newp->next = deleted;
++ deleted = newp;
++ }
++ else
++ lastp = runp;
++
++ runp = runp->next;
++ }
++ while (runp != NULL);
++
++ /* Release the lock. */
++ lll_unlock (__fork_lock);
++
++ /* Walk the list of all entries which have to be deleted. */
++ while (deleted != NULL)
++ {
++ /* We need to be informed by possible current users. */
++ deleted->handler->need_signal = 1;
++ /* Make sure this gets written out first. */
++ atomic_write_barrier ();
++
++ /* Decrement the reference counter. If it does not reach zero
++ wait for the last user. */
++ atomic_decrement (&deleted->handler->refcntr);
++ unsigned int val;
++ while ((val = deleted->handler->refcntr) != 0)
++ lll_futex_wait (&deleted->handler->refcntr, val);
++
++ deleted = deleted->next;
++ }
++}
+diff -x CVS -rupN libc/nptl/sysdeps/l4/smp.h libc/nptl/sysdeps/l4/smp.h
+--- libc/nptl/sysdeps/l4/smp.h 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/l4/smp.h 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,37 @@
++/* Determine whether the host has multiple processors. L4 version.
++ Copyright (C) 1996, 2002, 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 Library General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with the GNU C Library; see the file COPYING.LIB. If not,
++ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ Boston, MA 02111-1307, USA. */
++
++#if 0
++#include <l4.h>
++#endif
++
++
++/* Test whether the machine has more than one processor. This test
++ does not check if the Hurd's scheduler will actually ever schedule
++ us to more than one processor. */
++static inline int
++is_smp_system (void)
++{
++#if 0
++ /* FIXME: Enable this. */
++ return l4_num_processors () > 1;
++#else
++ return 0;
++#endif
++}
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/createthread.c libc/nptl/sysdeps/pthread/createthread.c
+--- libc/nptl/sysdeps/pthread/createthread.c 2005-01-23 18:39:29.000000000 +0100
++++ libc/nptl/sysdeps/pthread/createthread.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,255 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <sched.h>
+-#include <setjmp.h>
+-#include <signal.h>
+-#include <stdlib.h>
+-#include <atomic.h>
+-#include <ldsodefs.h>
+-#include <tls.h>
+-
+-#include "kernel-features.h"
+-
+-
+-#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
+-
+-/* Unless otherwise specified, the thread "register" is going to be
+- initialized with a pointer to the TCB. */
+-#ifndef TLS_VALUE
+-# define TLS_VALUE pd
+-#endif
+-
+-#ifndef ARCH_CLONE
+-# define ARCH_CLONE __clone
+-#endif
+-
+-
+-#ifndef TLS_MULTIPLE_THREADS_IN_TCB
+-/* Pointer to the corresponding variable in libc. */
+-int *__libc_multiple_threads_ptr attribute_hidden;
+-#endif
+-
+-
+-static int
+-do_clone (struct pthread *pd, const struct pthread_attr *attr,
+- int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS,
+- int stopped)
+-{
+-#ifdef PREPARE_CREATE
+- PREPARE_CREATE;
+-#endif
+-
+- if (stopped)
+- /* We Make sure the thread does not run far by forcing it to get a
+- lock. We lock it here too so that the new thread cannot continue
+- until we tell it to. */
+- lll_lock (pd->lock);
+-
+- /* One more thread. We cannot have the thread do this itself, since it
+- might exist but not have been scheduled yet by the time we've returned
+- and need to check the value to behave correctly. We must do it before
+- creating the thread, in case it does get scheduled first and then
+- might mistakenly think it was the only thread. In the failure case,
+- we momentarily store a false value; this doesn't matter because there
+- is no kosher thing a signal handler interrupting us right here can do
+- that cares whether the thread count is correct. */
+- atomic_increment (&__nptl_nthreads);
+-
+- if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
+- pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
+- {
+- atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */
+-
+- /* Failed. If the thread is detached, remove the TCB here since
+- the caller cannot do this. The caller remembered the thread
+- as detached and cannot reverify that it is not since it must
+- not access the thread descriptor again. */
+- if (IS_DETACHED (pd))
+- __deallocate_stack (pd);
+-
+- return errno;
+- }
+-
+- /* Now we have the possibility to set scheduling parameters etc. */
+- if (__builtin_expect (stopped != 0, 0))
+- {
+- INTERNAL_SYSCALL_DECL (err);
+- int res = 0;
+-
+- /* Set the affinity mask if necessary. */
+- if (attr->cpuset != NULL)
+- {
+- res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
+- sizeof (cpu_set_t), attr->cpuset);
+-
+- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+- {
+- /* The operation failed. We have to kill the thread. First
+- send it the cancellation signal. */
+- INTERNAL_SYSCALL_DECL (err2);
+- err_out:
+-#if __ASSUME_TGKILL
+- (void) INTERNAL_SYSCALL (tgkill, err2, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- pd->tid, SIGCANCEL);
+-#else
+- (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
+-#endif
+-
+- return (INTERNAL_SYSCALL_ERROR_P (res, err)
+- ? INTERNAL_SYSCALL_ERRNO (res, err)
+- : 0);
+- }
+- }
+-
+- /* Set the scheduling parameters. */
+- if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
+- {
+- res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
+- pd->schedpolicy, &pd->schedparam);
+-
+- if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
+- goto err_out;
+- }
+- }
+-
+- /* We now have for sure more than one thread. The main thread might
+- not yet have the flag set. No need to set the global variable
+- again if this is what we use. */
+- THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
+-
+- return 0;
+-}
+-
+-
+-static int
+-create_thread (struct pthread *pd, const struct pthread_attr *attr,
+- STACK_VARIABLES_PARMS)
+-{
+-#ifdef TLS_TCB_AT_TP
+- assert (pd->header.tcb != NULL);
+-#endif
+-
+- /* We rely heavily on various flags the CLONE function understands:
+-
+- CLONE_VM, CLONE_FS, CLONE_FILES
+- These flags select semantics with shared address space and
+- file descriptors according to what POSIX requires.
+-
+- CLONE_SIGNAL
+- This flag selects the POSIX signal semantics.
+-
+- CLONE_SETTLS
+- The sixth parameter to CLONE determines the TLS area for the
+- new thread.
+-
+- CLONE_PARENT_SETTID
+- The kernels writes the thread ID of the newly created thread
+- into the location pointed to by the fifth parameters to CLONE.
+-
+- Note that it would be semantically equivalent to use
+- CLONE_CHILD_SETTID but it is be more expensive in the kernel.
+-
+- CLONE_CHILD_CLEARTID
+- The kernels clears the thread ID of a thread that has called
+- sys_exit() in the location pointed to by the seventh parameter
+- to CLONE.
+-
+- CLONE_DETACHED
+- No signal is generated if the thread exists and it is
+- automatically reaped.
+-
+- The termination signal is chosen to be zero which means no signal
+- is sent. */
+- int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
+- | CLONE_SETTLS | CLONE_PARENT_SETTID
+- | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
+-#if __ASSUME_NO_CLONE_DETACHED == 0
+- | CLONE_DETACHED
+-#endif
+- | 0);
+-
+- if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
+- {
+- /* The parent thread is supposed to report events. Check whether
+- the TD_CREATE event is needed, too. */
+- const int _idx = __td_eventword (TD_CREATE);
+- const uint32_t _mask = __td_eventmask (TD_CREATE);
+-
+- if ((_mask & (__nptl_threads_events.event_bits[_idx]
+- | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
+- {
+- /* We always must have the thread start stopped. */
+- pd->stopped_start = true;
+-
+- /* Create the thread. We always create the thread stopped
+- so that it does not get far before we tell the debugger. */
+- int res = do_clone (pd, attr, clone_flags, start_thread,
+- STACK_VARIABLES_ARGS, 1);
+- if (res == 0)
+- {
+- /* Now fill in the information about the new thread in
+- the newly created thread's data structure. We cannot let
+- the new thread do this since we don't know whether it was
+- already scheduled when we send the event. */
+- pd->eventbuf.eventnum = TD_CREATE;
+- pd->eventbuf.eventdata = pd;
+-
+- /* Enqueue the descriptor. */
+- do
+- pd->nextevent = __nptl_last_event;
+- while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
+- pd, pd->nextevent)
+- != 0);
+-
+- /* Now call the function which signals the event. */
+- __nptl_create_event ();
+-
+- /* And finally restart the new thread. */
+- lll_unlock (pd->lock);
+- }
+-
+- return res;
+- }
+- }
+-
+-#ifdef NEED_DL_SYSINFO
+- assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd));
+-#endif
+-
+- /* Determine whether the newly created threads has to be started
+- stopped since we have to set the scheduling parameters or set the
+- affinity. */
+- bool stopped = false;
+- if (attr != NULL && (attr->cpuset != NULL
+- || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
+- stopped = true;
+- pd->stopped_start = stopped;
+-
+- /* Actually create the thread. */
+- int res = do_clone (pd, attr, clone_flags, start_thread,
+- STACK_VARIABLES_ARGS, stopped);
+-
+- if (res == 0 && stopped)
+- /* And finally restart the new thread. */
+- lll_unlock (pd->lock);
+-
+- return res;
+-}
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/pthread_cond_broadcast.c libc/nptl/sysdeps/pthread/pthread_cond_broadcast.c
+--- libc/nptl/sysdeps/pthread/pthread_cond_broadcast.c 2004-10-10 12:41:06.000000000 +0200
++++ libc/nptl/sysdeps/pthread/pthread_cond_broadcast.c 2005-01-23 19:35:29.000000000 +0100
+@@ -25,7 +25,7 @@
+ #include <pthreadP.h>
+
+ #include <shlib-compat.h>
+-#include <kernel-features.h>
++#include <lowlevellock.h>
+
+
+ int
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/pthread_cond_signal.c libc/nptl/sysdeps/pthread/pthread_cond_signal.c
+--- libc/nptl/sysdeps/pthread/pthread_cond_signal.c 2004-10-10 12:41:07.000000000 +0200
++++ libc/nptl/sysdeps/pthread/pthread_cond_signal.c 2005-01-23 19:35:29.000000000 +0100
+@@ -25,7 +25,7 @@
+ #include <pthreadP.h>
+
+ #include <shlib-compat.h>
+-#include <kernel-features.h>
++#include <lowlevellock.h>
+
+
+ int
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/pthread_sigmask.c libc/nptl/sysdeps/pthread/pthread_sigmask.c
+--- libc/nptl/sysdeps/pthread/pthread_sigmask.c 2004-10-10 12:41:07.000000000 +0200
++++ libc/nptl/sysdeps/pthread/pthread_sigmask.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,58 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <errno.h>
+-#include <signal.h>
+-#include <pthreadP.h>
+-#include <sysdep.h>
+-
+-
+-int
+-pthread_sigmask (how, newmask, oldmask)
+- int how;
+- const sigset_t *newmask;
+- sigset_t *oldmask;
+-{
+- sigset_t local_newmask;
+-
+- /* The only thing we have to make sure here is that SIGCANCEL and
+- SIGSETXID is not blocked. */
+- if (newmask != NULL
+- && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0)
+- || __builtin_expect (__sigismember (newmask, SIGSETXID), 0)))
+- {
+- local_newmask = *newmask;
+- __sigdelset (&local_newmask, SIGCANCEL);
+- __sigdelset (&local_newmask, SIGSETXID);
+- newmask = &local_newmask;
+- }
+-
+-#ifdef INTERNAL_SYSCALL
+- /* We know that realtime signals are available if NPTL is used. */
+- INTERNAL_SYSCALL_DECL (err);
+- int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask,
+- oldmask, _NSIG / 8);
+-
+- return (INTERNAL_SYSCALL_ERROR_P (result, err)
+- ? INTERNAL_SYSCALL_ERRNO (result, err)
+- : 0);
+-#else
+- return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0;
+-#endif
+-}
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/sigaction.c libc/nptl/sysdeps/pthread/sigaction.c
+--- libc/nptl/sysdeps/pthread/sigaction.c 2004-10-10 12:41:07.000000000 +0200
++++ libc/nptl/sysdeps/pthread/sigaction.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,54 +0,0 @@
+-/* Copyright (C) 2002, 2003, 2004 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. */
+-
+-/* This is tricky. GCC doesn't like #include_next in the primary
+- source file and even if it did, the first #include_next is this
+- exact file anyway. */
+-#ifndef LIBC_SIGACTION
+-
+-#include <nptl/pthreadP.h>
+-
+-/* We use the libc implementation but we tell it to not allow
+- SIGCANCEL or SIGTIMER to be handled. */
+-# define LIBC_SIGACTION 1
+-
+-# include <nptl/sysdeps/pthread/sigaction.c>
+-
+-int
+-__sigaction (sig, act, oact)
+- int sig;
+- const struct sigaction *act;
+- struct sigaction *oact;
+-{
+- if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0))
+- {
+- __set_errno (EINVAL);
+- return -1;
+- }
+-
+- return __libc_sigaction (sig, act, oact);
+-}
+-libc_hidden_weak (__sigaction)
+-weak_alias (__sigaction, sigaction)
+-
+-#else
+-
+-# include_next <sigaction.c>
+-
+-#endif /* LIBC_SIGACTION */
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/sigfillset.c libc/nptl/sysdeps/pthread/sigfillset.c
+--- libc/nptl/sysdeps/pthread/sigfillset.c 2003-04-21 09:47:36.000000000 +0200
++++ libc/nptl/sysdeps/pthread/sigfillset.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,21 +0,0 @@
+-/* Copyright (C) 2003 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <nptl/pthreadP.h>
+-
+-#include <sysdeps/generic/sigfillset.c>
+diff -x CVS -rupN libc/nptl/sysdeps/pthread/sigprocmask.c libc/nptl/sysdeps/pthread/sigprocmask.c
+--- libc/nptl/sysdeps/pthread/sigprocmask.c 2003-04-21 09:35:27.000000000 +0200
++++ libc/nptl/sysdeps/pthread/sigprocmask.c 1970-01-01 01:00:00.000000000 +0100
+@@ -1,20 +0,0 @@
+-/* Copyright (C) 1997,1998,1999,2000,2001,2003 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+-
+- The GNU C Library is free software; you can redistribute it and/or
+- modify it under the terms of the GNU Lesser General Public
+- License as published by the Free Software Foundation; either
+- version 2.1 of the License, or (at your option) any later version.
+-
+- The GNU C Library is distributed in the hope that it will be useful,
+- but WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- Lesser General Public License for more details.
+-
+- You should have received a copy of the GNU Lesser General Public
+- License along with the GNU C Library; if not, write to the Free
+- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+- 02111-1307 USA. */
+-
+-#include <nptl/pthreadP.h>
+-#include <sysdeps/unix/sysv/linux/sigprocmask.c>
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/allocatestack.c libc/nptl/sysdeps/unix/sysv/linux/allocatestack.c
+--- libc/nptl/sysdeps/unix/sysv/linux/allocatestack.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/allocatestack.c 2005-01-23 20:01:28.000000000 +0100
+@@ -0,0 +1,947 @@
++/* Copyright (C) 2002, 2003, 2004 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 <assert.h>
++#include <errno.h>
++#include <signal.h>
++#include <stdint.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/mman.h>
++#include <sys/param.h>
++#include <dl-sysdep.h>
++#include <tls.h>
++#include <lowlevellock.h>
++
++
++#ifndef NEED_SEPARATE_REGISTER_STACK
++
++/* Most architectures have exactly one stack pointer. Some have more. */
++# define STACK_VARIABLES void *stackaddr
++
++/* How to pass the values to the 'create_thread' function. */
++# define STACK_VARIABLES_ARGS stackaddr
++
++/* How to declare function which gets there parameters. */
++# define STACK_VARIABLES_PARMS void *stackaddr
++
++/* How to declare allocate_stack. */
++# define ALLOCATE_STACK_PARMS void **stack
++
++/* This is how the function is called. We do it this way to allow
++ other variants of the function to have more parameters. */
++# define ALLOCATE_STACK(attr, pd) allocate_stack (attr, pd, &stackaddr)
++
++#else
++
++/* We need two stacks. The kernel will place them but we have to tell
++ the kernel about the size of the reserved address space. */
++# define STACK_VARIABLES void *stackaddr; size_t stacksize
++
++/* How to pass the values to the 'create_thread' function. */
++# define STACK_VARIABLES_ARGS stackaddr, stacksize
++
++/* How to declare function which gets there parameters. */
++# define STACK_VARIABLES_PARMS void *stackaddr, size_t stacksize
++
++/* How to declare allocate_stack. */
++# define ALLOCATE_STACK_PARMS void **stack, size_t *stacksize
++
++/* This is how the function is called. We do it this way to allow
++ other variants of the function to have more parameters. */
++# define ALLOCATE_STACK(attr, pd) \
++ allocate_stack (attr, pd, &stackaddr, &stacksize)
++
++#endif
++
++
++/* Default alignment of stack. */
++#ifndef STACK_ALIGN
++# define STACK_ALIGN __alignof__ (long double)
++#endif
++
++/* Default value for minimal stack size after allocating thread
++ descriptor and guard. */
++#ifndef MINIMAL_REST_STACK
++# define MINIMAL_REST_STACK 4096
++#endif
++
++
++/* Let the architecture add some flags to the mmap() call used to
++ allocate stacks. */
++#ifndef ARCH_MAP_FLAGS
++# define ARCH_MAP_FLAGS 0
++#endif
++
++/* This yields the pointer that TLS support code calls the thread pointer. */
++#if TLS_TCB_AT_TP
++# define TLS_TPADJ(pd) (pd)
++#elif TLS_DTV_AT_TP
++# define TLS_TPADJ(pd) ((struct pthread *)((char *) (pd) + TLS_PRE_TCB_SIZE))
++#endif
++
++/* Cache handling for not-yet free stacks. */
++
++/* Maximum size in kB of cache. */
++static size_t stack_cache_maxsize = 40 * 1024 * 1024; /* 40MiBi by default. */
++static size_t stack_cache_actsize;
++
++/* Mutex protecting this variable. */
++static lll_lock_t stack_cache_lock = LLL_LOCK_INITIALIZER;
++
++/* List of queued stack frames. */
++static LIST_HEAD (stack_cache);
++
++/* List of the stacks in use. */
++static LIST_HEAD (stack_used);
++
++/* List of the threads with user provided stacks in use. No need to
++ initialize this, since it's done in __pthread_initialize_minimal. */
++list_t __stack_user __attribute__ ((nocommon));
++hidden_data_def (__stack_user)
++
++#if COLORING_INCREMENT != 0
++/* Number of threads created. */
++static unsigned int nptl_ncreated;
++#endif
++
++
++/* Check whether the stack is still used or not. */
++#define FREE_P(descr) ((descr)->tid <= 0)
++
++
++/* We create a double linked list of all cache entries. Double linked
++ because this allows removing entries from the end. */
++
++
++/* Get a stack frame from the cache. We have to match by size since
++ some blocks might be too small or far too large. */
++static struct pthread *
++get_cached_stack (size_t *sizep, void **memp)
++{
++ size_t size = *sizep;
++ struct pthread *result = NULL;
++ list_t *entry;
++
++ lll_lock (stack_cache_lock);
++
++ /* Search the cache for a matching entry. We search for the
++ smallest stack which has at least the required size. Note that
++ in normal situations the size of all allocated stacks is the
++ same. As the very least there are only a few different sizes.
++ Therefore this loop will exit early most of the time with an
++ exact match. */
++ list_for_each (entry, &stack_cache)
++ {
++ struct pthread *curr;
++
++ curr = list_entry (entry, struct pthread, list);
++ if (FREE_P (curr) && curr->stackblock_size >= size)
++ {
++ if (curr->stackblock_size == size)
++ {
++ result = curr;
++ break;
++ }
++
++ if (result == NULL
++ || result->stackblock_size > curr->stackblock_size)
++ result = curr;
++ }
++ }
++
++ if (__builtin_expect (result == NULL, 0)
++ /* Make sure the size difference is not too excessive. In that
++ case we do not use the block. */
++ || __builtin_expect (result->stackblock_size > 4 * size, 0))
++ {
++ /* Release the lock. */
++ lll_unlock (stack_cache_lock);
++
++ return NULL;
++ }
++
++ /* Dequeue the entry. */
++ list_del (&result->list);
++
++ /* And add to the list of stacks in use. */
++ list_add (&result->list, &stack_used);
++
++ /* And decrease the cache size. */
++ stack_cache_actsize -= result->stackblock_size;
++
++ /* Release the lock early. */
++ lll_unlock (stack_cache_lock);
++
++ /* Report size and location of the stack to the caller. */
++ *sizep = result->stackblock_size;
++ *memp = result->stackblock;
++
++ /* Cancellation handling is back to the default. */
++ result->cancelhandling = 0;
++ result->cleanup = NULL;
++
++ /* No pending event. */
++ result->nextevent = NULL;
++
++ /* Clear the DTV. */
++ dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
++ memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
++
++ /* Re-initialize the TLS. */
++ _dl_allocate_tls_init (TLS_TPADJ (result));
++
++ return result;
++}
++
++
++/* Add a stack frame which is not used anymore to the stack. Must be
++ called with the cache lock held. */
++static inline void
++__attribute ((always_inline))
++queue_stack (struct pthread *stack)
++{
++ /* We unconditionally add the stack to the list. The memory may
++ still be in use but it will not be reused until the kernel marks
++ the stack as not used anymore. */
++ list_add (&stack->list, &stack_cache);
++
++ stack_cache_actsize += stack->stackblock_size;
++ if (__builtin_expect (stack_cache_actsize > stack_cache_maxsize, 0))
++ {
++ /* We reduce the size of the cache. Remove the last entries
++ until the size is below the limit. */
++ list_t *entry;
++ list_t *prev;
++
++ /* Search from the end of the list. */
++ list_for_each_prev_safe (entry, prev, &stack_cache)
++ {
++ struct pthread *curr;
++
++ curr = list_entry (entry, struct pthread, list);
++ if (FREE_P (curr))
++ {
++ /* Unlink the block. */
++ list_del (entry);
++
++ /* Account for the freed memory. */
++ stack_cache_actsize -= curr->stackblock_size;
++
++ /* Free the memory associated with the ELF TLS. */
++ _dl_deallocate_tls (TLS_TPADJ (curr), false);
++
++ /* Remove this block. This should never fail. If it
++ does something is really wrong. */
++ if (munmap (curr->stackblock, curr->stackblock_size) != 0)
++ abort ();
++
++ /* Maybe we have freed enough. */
++ if (stack_cache_actsize <= stack_cache_maxsize)
++ break;
++ }
++ }
++ }
++}
++
++
++static int
++internal_function
++change_stack_perm (struct pthread *pd
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , size_t pagemask
++#endif
++ )
++{
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ void *stack = (pd->stackblock
++ + (((((pd->stackblock_size - pd->guardsize) / 2)
++ & pagemask) + pd->guardsize) & pagemask));
++ size_t len = pd->stackblock + pd->stackblock_size - stack;
++#else
++ void *stack = pd->stackblock + pd->guardsize;
++ size_t len = pd->stackblock_size - pd->guardsize;
++#endif
++ if (mprotect (stack, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
++ return errno;
++
++ return 0;
++}
++
++
++static int
++allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
++ ALLOCATE_STACK_PARMS)
++{
++ struct pthread *pd;
++ size_t size;
++ size_t pagesize_m1 = __getpagesize () - 1;
++ void *stacktop;
++
++ assert (attr != NULL);
++ assert (powerof2 (pagesize_m1 + 1));
++ assert (TCB_ALIGNMENT >= STACK_ALIGN);
++
++ /* Get the stack size from the attribute if it is set. Otherwise we
++ use the default we determined at start time. */
++ size = attr->stacksize ?: __default_stacksize;
++
++ /* Get memory for the stack. */
++ if (__builtin_expect (attr->flags & ATTR_FLAG_STACKADDR, 0))
++ {
++ uintptr_t adj;
++
++ /* If the user also specified the size of the stack make sure it
++ is large enough. */
++ if (attr->stacksize != 0
++ && attr->stacksize < (__static_tls_size + MINIMAL_REST_STACK))
++ return EINVAL;
++
++ /* Adjust stack size for alignment of the TLS block. */
++#if TLS_TCB_AT_TP
++ adj = ((uintptr_t) attr->stackaddr - TLS_TCB_SIZE)
++ & __static_tls_align_m1;
++ assert (size > adj + TLS_TCB_SIZE);
++#elif TLS_DTV_AT_TP
++ adj = ((uintptr_t) attr->stackaddr - __static_tls_size)
++ & __static_tls_align_m1;
++ assert (size > adj);
++#endif
++
++ /* The user provided some memory. Let's hope it matches the
++ size... We do not allocate guard pages if the user provided
++ the stack. It is the user's responsibility to do this if it
++ is wanted. */
++#if TLS_TCB_AT_TP
++ pd = (struct pthread *) ((uintptr_t) attr->stackaddr
++ - TLS_TCB_SIZE - adj);
++#elif TLS_DTV_AT_TP
++ pd = (struct pthread *) (((uintptr_t) attr->stackaddr
++ - __static_tls_size - adj)
++ - TLS_PRE_TCB_SIZE);
++#endif
++
++ /* The user provided stack memory needs to be cleared. */
++ memset (pd, '\0', sizeof (struct pthread));
++
++ /* The first TSD block is included in the TCB. */
++ pd->specific[0] = pd->specific_1stblock;
++
++ /* Remember the stack-related values. */
++ pd->stackblock = (char *) attr->stackaddr - size;
++ pd->stackblock_size = size;
++
++ /* This is a user-provided stack. It will not be queued in the
++ stack cache nor will the memory (except the TLS memory) be freed. */
++ pd->user_stack = true;
++
++ /* This is at least the second thread. */
++ pd->header.multiple_threads = 1;
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++ __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
++#endif
++
++#ifdef NEED_DL_SYSINFO
++ /* Copy the sysinfo value from the parent. */
++ THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
++#endif
++
++ /* The process ID is also the same as that of the caller. */
++ pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
++
++ /* Allocate the DTV for this thread. */
++ if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
++ {
++ /* Something went wrong. */
++ assert (errno == ENOMEM);
++ return EAGAIN;
++ }
++
++
++ /* Prepare to modify global data. */
++ lll_lock (stack_cache_lock);
++
++ /* And add to the list of stacks in use. */
++ list_add (&pd->list, &__stack_user);
++
++ lll_unlock (stack_cache_lock);
++ }
++ else
++ {
++ /* Allocate some anonymous memory. If possible use the cache. */
++ size_t guardsize;
++ size_t reqsize;
++ void *mem;
++ const int prot = (PROT_READ | PROT_WRITE
++ | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
++
++#if COLORING_INCREMENT != 0
++ /* Add one more page for stack coloring. Don't do it for stacks
++ with 16 times pagesize or larger. This might just cause
++ unnecessary misalignment. */
++ if (size <= 16 * pagesize_m1)
++ size += pagesize_m1 + 1;
++#endif
++
++ /* Adjust the stack size for alignment. */
++ size &= ~__static_tls_align_m1;
++ assert (size != 0);
++
++ /* Make sure the size of the stack is enough for the guard and
++ eventually the thread descriptor. */
++ guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1;
++ if (__builtin_expect (size < (guardsize + __static_tls_size
++ + MINIMAL_REST_STACK + pagesize_m1 + 1),
++ 0))
++ /* The stack is too small (or the guard too large). */
++ return EINVAL;
++
++ /* Try to get a stack from the cache. */
++ reqsize = size;
++ pd = get_cached_stack (&size, &mem);
++ if (pd == NULL)
++ {
++ /* To avoid aliasing effects on a larger scale than pages we
++ adjust the allocated stack size if necessary. This way
++ allocations directly following each other will not have
++ aliasing problems. */
++#if MULTI_PAGE_ALIASING != 0
++ if ((size % MULTI_PAGE_ALIASING) == 0)
++ size += pagesize_m1 + 1;
++#endif
++
++ mem = mmap (NULL, size, prot,
++ MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0);
++
++ if (__builtin_expect (mem == MAP_FAILED, 0))
++ {
++#ifdef ARCH_RETRY_MMAP
++ mem = ARCH_RETRY_MMAP (size);
++ if (__builtin_expect (mem == MAP_FAILED, 0))
++#endif
++ return errno;
++ }
++
++ /* SIZE is guaranteed to be greater than zero.
++ So we can never get a null pointer back from mmap. */
++ assert (mem != NULL);
++
++#if COLORING_INCREMENT != 0
++ /* Atomically increment NCREATED. */
++ unsigned int ncreated = atomic_increment_val (&nptl_ncreated);
++
++ /* We chose the offset for coloring by incrementing it for
++ every new thread by a fixed amount. The offset used
++ module the page size. Even if coloring would be better
++ relative to higher alignment values it makes no sense to
++ do it since the mmap() interface does not allow us to
++ specify any alignment for the returned memory block. */
++ size_t coloring = (ncreated * COLORING_INCREMENT) & pagesize_m1;
++
++ /* Make sure the coloring offsets does not disturb the alignment
++ of the TCB and static TLS block. */
++ if (__builtin_expect ((coloring & __static_tls_align_m1) != 0, 0))
++ coloring = (((coloring + __static_tls_align_m1)
++ & ~(__static_tls_align_m1))
++ & ~pagesize_m1);
++#else
++ /* Unless specified we do not make any adjustments. */
++# define coloring 0
++#endif
++
++ /* Place the thread descriptor at the end of the stack. */
++#if TLS_TCB_AT_TP
++ pd = (struct pthread *) ((char *) mem + size - coloring) - 1;
++#elif TLS_DTV_AT_TP
++ pd = (struct pthread *) ((((uintptr_t) mem + size - coloring
++ - __static_tls_size)
++ & ~__static_tls_align_m1)
++ - TLS_PRE_TCB_SIZE);
++#endif
++
++ /* Remember the stack-related values. */
++ pd->stackblock = mem;
++ pd->stackblock_size = size;
++
++ /* We allocated the first block thread-specific data array.
++ This address will not change for the lifetime of this
++ descriptor. */
++ pd->specific[0] = pd->specific_1stblock;
++
++ /* This is at least the second thread. */
++ pd->header.multiple_threads = 1;
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++ __pthread_multiple_threads = *__libc_multiple_threads_ptr = 1;
++#endif
++
++#ifdef NEED_DL_SYSINFO
++ /* Copy the sysinfo value from the parent. */
++ THREAD_SYSINFO(pd) = THREAD_SELF_SYSINFO;
++#endif
++
++ /* The process ID is also the same as that of the caller. */
++ pd->pid = THREAD_GETMEM (THREAD_SELF, pid);
++
++ /* Allocate the DTV for this thread. */
++ if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL)
++ {
++ /* Something went wrong. */
++ assert (errno == ENOMEM);
++
++ /* Free the stack memory we just allocated. */
++ (void) munmap (mem, size);
++
++ return EAGAIN;
++ }
++
++
++ /* Prepare to modify global data. */
++ lll_lock (stack_cache_lock);
++
++ /* And add to the list of stacks in use. */
++ list_add (&pd->list, &stack_used);
++
++ lll_unlock (stack_cache_lock);
++
++
++ /* There might have been a race. Another thread might have
++ caused the stacks to get exec permission while this new
++ stack was prepared. Detect if this was possible and
++ change the permission if necessary. */
++ if (__builtin_expect ((GL(dl_stack_flags) & PF_X) != 0
++ && (prot & PROT_EXEC) == 0, 0))
++ {
++ int err = change_stack_perm (pd
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , ~pagesize_m1
++#endif
++ );
++ if (err != 0)
++ {
++ /* Free the stack memory we just allocated. */
++ (void) munmap (mem, size);
++
++ return err;
++ }
++ }
++
++
++ /* Note that all of the stack and the thread descriptor is
++ zeroed. This means we do not have to initialize fields
++ with initial value zero. This is specifically true for
++ the 'tid' field which is always set back to zero once the
++ stack is not used anymore and for the 'guardsize' field
++ which will be read next. */
++ }
++
++ /* Create or resize the guard area if necessary. */
++ if (__builtin_expect (guardsize > pd->guardsize, 0))
++ {
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
++#else
++ char *guard = mem;
++#endif
++ if (mprotect (guard, guardsize, PROT_NONE) != 0)
++ {
++ int err;
++ mprot_error:
++ err = errno;
++
++ lll_lock (stack_cache_lock);
++
++ /* Remove the thread from the list. */
++ list_del (&pd->list);
++
++ lll_unlock (stack_cache_lock);
++
++ /* Get rid of the TLS block we allocated. */
++ _dl_deallocate_tls (TLS_TPADJ (pd), false);
++
++ /* Free the stack memory regardless of whether the size
++ of the cache is over the limit or not. If this piece
++ of memory caused problems we better do not use it
++ anymore. Uh, and we ignore possible errors. There
++ is nothing we could do. */
++ (void) munmap (mem, size);
++
++ return err;
++ }
++
++ pd->guardsize = guardsize;
++ }
++ else if (__builtin_expect (pd->guardsize - guardsize > size - reqsize,
++ 0))
++ {
++ /* The old guard area is too large. */
++
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ char *guard = mem + (((size - guardsize) / 2) & ~pagesize_m1);
++ char *oldguard = mem + (((size - pd->guardsize) / 2) & ~pagesize_m1);
++
++ if (oldguard < guard
++ && mprotect (oldguard, guard - oldguard, prot) != 0)
++ goto mprot_error;
++
++ if (mprotect (guard + guardsize,
++ oldguard + pd->guardsize - guard - guardsize,
++ prot) != 0)
++ goto mprot_error;
++#else
++ if (mprotect ((char *) mem + guardsize, pd->guardsize - guardsize,
++ prot) != 0)
++ goto mprot_error;
++#endif
++
++ pd->guardsize = guardsize;
++ }
++ /* The pthread_getattr_np() calls need to get passed the size
++ requested in the attribute, regardless of how large the
++ actually used guardsize is. */
++ pd->reported_guardsize = guardsize;
++ }
++
++ /* Initialize the lock. We have to do this unconditionally since the
++ stillborn thread could be canceled while the lock is taken. */
++ pd->lock = LLL_LOCK_INITIALIZER;
++
++ /* We place the thread descriptor at the end of the stack. */
++ *pdp = pd;
++
++#if TLS_TCB_AT_TP
++ /* The stack begins before the TCB and the static TLS block. */
++ stacktop = ((char *) (pd + 1) - __static_tls_size);
++#elif TLS_DTV_AT_TP
++ stacktop = (char *) (pd - 1);
++#endif
++
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ *stack = pd->stackblock;
++ *stacksize = stacktop - *stack;
++#else
++ *stack = stacktop;
++#endif
++
++ return 0;
++}
++
++
++void
++internal_function
++__deallocate_stack (struct pthread *pd)
++{
++ lll_lock (stack_cache_lock);
++
++ /* Remove the thread from the list of threads with user defined
++ stacks. */
++ list_del (&pd->list);
++
++ /* Not much to do. Just free the mmap()ed memory. Note that we do
++ not reset the 'used' flag in the 'tid' field. This is done by
++ the kernel. If no thread has been created yet this field is
++ still zero. */
++ if (__builtin_expect (! pd->user_stack, 1))
++ (void) queue_stack (pd);
++ else
++ /* Free the memory associated with the ELF TLS. */
++ _dl_deallocate_tls (TLS_TPADJ (pd), false);
++
++ lll_unlock (stack_cache_lock);
++}
++
++
++int
++internal_function
++__make_stacks_executable (void **stack_endp)
++{
++ /* First the main thread's stack. */
++ int err = _dl_make_stack_executable (stack_endp);
++ if (err != 0)
++ return err;
++
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ const size_t pagemask = ~(__getpagesize () - 1);
++#endif
++
++ lll_lock (stack_cache_lock);
++
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ err = change_stack_perm (list_entry (runp, struct pthread, list)
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , pagemask
++#endif
++ );
++ if (err != 0)
++ break;
++ }
++
++ /* Also change the permission for the currently unused stacks. This
++ might be wasted time but better spend it here than adding a check
++ in the fast path. */
++ if (err == 0)
++ list_for_each (runp, &stack_cache)
++ {
++ err = change_stack_perm (list_entry (runp, struct pthread, list)
++#ifdef NEED_SEPARATE_REGISTER_STACK
++ , pagemask
++#endif
++ );
++ if (err != 0)
++ break;
++ }
++
++ lll_unlock (stack_cache_lock);
++
++ return err;
++}
++
++
++/* In case of a fork() call the memory allocation in the child will be
++ the same but only one thread is running. All stacks except that of
++ the one running thread are not used anymore. We have to recycle
++ them. */
++void
++__reclaim_stacks (void)
++{
++ struct pthread *self = (struct pthread *) THREAD_SELF;
++
++ /* No locking necessary. The caller is the only stack in use. */
++
++ /* Mark all stacks except the still running one as free. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (runp, struct pthread, list);
++ if (curp != self)
++ {
++ /* This marks the stack as free. */
++ curp->tid = 0;
++
++ /* The PID field must be initialized for the new process. */
++ curp->pid = self->pid;
++
++ /* Account for the size of the stack. */
++ stack_cache_actsize += curp->stackblock_size;
++ }
++ }
++
++ /* Add the stack of all running threads to the cache. */
++ list_splice (&stack_used, &stack_cache);
++
++ /* Remove the entry for the current thread to from the cache list
++ and add it to the list of running threads. Which of the two
++ lists is decided by the user_stack flag. */
++ list_del (&self->list);
++
++ /* Re-initialize the lists for all the threads. */
++ INIT_LIST_HEAD (&stack_used);
++ INIT_LIST_HEAD (&__stack_user);
++
++ if (__builtin_expect (THREAD_GETMEM (self, user_stack), 0))
++ list_add (&self->list, &__stack_user);
++ else
++ list_add (&self->list, &stack_used);
++
++ /* There is one thread running. */
++ __nptl_nthreads = 1;
++
++ /* Initialize the lock. */
++ stack_cache_lock = LLL_LOCK_INITIALIZER;
++}
++
++
++#if HP_TIMING_AVAIL
++# undef __find_thread_by_id
++/* Find a thread given the thread ID. */
++attribute_hidden
++struct pthread *
++__find_thread_by_id (pid_t tid)
++{
++ struct pthread *result = NULL;
++
++ lll_lock (stack_cache_lock);
++
++ /* Iterate over the list with system-allocated threads first. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (runp, struct pthread, list);
++
++ if (curp->tid == tid)
++ {
++ result = curp;
++ goto out;
++ }
++ }
++
++ /* Now the list with threads using user-allocated stacks. */
++ list_for_each (runp, &__stack_user)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (runp, struct pthread, list);
++
++ if (curp->tid == tid)
++ {
++ result = curp;
++ goto out;
++ }
++ }
++
++ out:
++ lll_unlock (stack_cache_lock);
++
++ return result;
++}
++#endif
++
++int
++attribute_hidden
++__nptl_setxid (struct xid_command *cmdp)
++{
++ int result;
++ lll_lock (stack_cache_lock);
++
++ __xidcmd = cmdp;
++ cmdp->cntr = 0;
++
++ INTERNAL_SYSCALL_DECL (err);
++
++ struct pthread *self = THREAD_SELF;
++
++ /* Iterate over the list with system-allocated threads first. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t != self)
++ {
++ int val;
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
++#endif
++
++ if (!INTERNAL_SYSCALL_ERROR_P (val, err))
++ atomic_increment (&cmdp->cntr);
++ }
++ }
++
++ /* Now the list with threads using user-allocated stacks. */
++ list_for_each (runp, &__stack_user)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t != self)
++ {
++ int val;
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
++#endif
++
++ if (!INTERNAL_SYSCALL_ERROR_P (val, err))
++ atomic_increment (&cmdp->cntr);
++ }
++ }
++
++ int cur = cmdp->cntr;
++ while (cur != 0)
++ {
++ lll_futex_wait (&cmdp->cntr, cur);
++ cur = cmdp->cntr;
++ }
++
++ /* This must be last, otherwise the current thread might not have
++ permissions to send SIGSETXID syscall to the other threads. */
++ result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3,
++ cmdp->id[0], cmdp->id[1], cmdp->id[2]);
++ if (INTERNAL_SYSCALL_ERROR_P (result, err))
++ {
++ __set_errno (INTERNAL_SYSCALL_ERRNO (result, err));
++ result = -1;
++ }
++
++ lll_unlock (stack_cache_lock);
++ return result;
++}
++
++static inline void __attribute__((always_inline))
++init_one_static_tls (struct pthread *curp, struct link_map *map)
++{
++ dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
++# if TLS_TCB_AT_TP
++ void *dest = (char *) curp - map->l_tls_offset;
++# elif TLS_DTV_AT_TP
++ void *dest = (char *) curp + 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);
++}
++
++void
++attribute_hidden
++__pthread_init_static_tls (struct link_map *map)
++{
++ lll_lock (stack_cache_lock);
++
++ /* Iterate over the list with system-allocated threads first. */
++ list_t *runp;
++ list_for_each (runp, &stack_used)
++ init_one_static_tls (list_entry (runp, struct pthread, list), map);
++
++ /* Now the list with threads using user-allocated stacks. */
++ list_for_each (runp, &__stack_user)
++ init_one_static_tls (list_entry (runp, struct pthread, list), map);
++
++ lll_unlock (stack_cache_lock);
++}
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/createthread.c libc/nptl/sysdeps/unix/sysv/linux/createthread.c
+--- libc/nptl/sysdeps/unix/sysv/linux/createthread.c 2003-03-10 07:29:56.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/createthread.c 2005-01-23 18:39:29.000000000 +0100
+@@ -1,6 +1,6 @@
+-/* Copyright (C) 2003 Free Software Foundation, Inc.
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+- Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>.
++ 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
+@@ -9,7 +9,7 @@
+
+ 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
++ 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
+@@ -17,8 +17,239 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-/* Value passed to 'clone' for initialization of the thread register. */
+-#define TLS_VALUE pd
++#include <sched.h>
++#include <setjmp.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <atomic.h>
++#include <ldsodefs.h>
++#include <tls.h>
+
+-/* Get the real implementation. */
+-#include <nptl/sysdeps/pthread/createthread.c>
++#include "kernel-features.h"
++
++
++#define CLONE_SIGNAL (CLONE_SIGHAND | CLONE_THREAD)
++
++/* Unless otherwise specified, the thread "register" is going to be
++ initialized with a pointer to the TCB. */
++#ifndef TLS_VALUE
++# define TLS_VALUE pd
++#endif
++
++#ifndef ARCH_CLONE
++# define ARCH_CLONE __clone
++#endif
++
++
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++/* Pointer to the corresponding variable in libc. */
++int *__libc_multiple_threads_ptr attribute_hidden;
++#endif
++
++
++static int
++do_clone (struct pthread *pd, const struct pthread_attr *attr,
++ int clone_flags, int (*fct) (void *), STACK_VARIABLES_PARMS,
++ int stopped)
++{
++#ifdef PREPARE_CREATE
++ PREPARE_CREATE;
++#endif
++
++ if (stopped)
++ /* We Make sure the thread does not run far by forcing it to get a
++ lock. We lock it here too so that the new thread cannot continue
++ until we tell it to. */
++ lll_lock (pd->lock);
++
++ /* One more thread. We cannot have the thread do this itself, since it
++ might exist but not have been scheduled yet by the time we've returned
++ and need to check the value to behave correctly. We must do it before
++ creating the thread, in case it does get scheduled first and then
++ might mistakenly think it was the only thread. In the failure case,
++ we momentarily store a false value; this doesn't matter because there
++ is no kosher thing a signal handler interrupting us right here can do
++ that cares whether the thread count is correct. */
++ atomic_increment (&__nptl_nthreads);
++
++ if (ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
++ pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)
++ {
++ atomic_decrement (&__nptl_nthreads); /* Oops, we lied for a second. */
++
++ /* Failed. If the thread is detached, remove the TCB here since
++ the caller cannot do this. The caller remembered the thread
++ as detached and cannot reverify that it is not since it must
++ not access the thread descriptor again. */
++ if (IS_DETACHED (pd))
++ __deallocate_stack (pd);
++
++ return errno;
++ }
++
++ /* Now we have the possibility to set scheduling parameters etc. */
++ if (__builtin_expect (stopped != 0, 0))
++ {
++ INTERNAL_SYSCALL_DECL (err);
++ int res = 0;
++
++ /* Set the affinity mask if necessary. */
++ if (attr->cpuset != NULL)
++ {
++ res = INTERNAL_SYSCALL (sched_setaffinity, err, 3, pd->tid,
++ sizeof (cpu_set_t), attr->cpuset);
++
++ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
++ {
++ /* The operation failed. We have to kill the thread. First
++ send it the cancellation signal. */
++ INTERNAL_SYSCALL_DECL (err2);
++ err_out:
++#if __ASSUME_TGKILL
++ (void) INTERNAL_SYSCALL (tgkill, err2, 3,
++ THREAD_GETMEM (THREAD_SELF, pid),
++ pd->tid, SIGCANCEL);
++#else
++ (void) INTERNAL_SYSCALL (tkill, err2, 2, pd->tid, SIGCANCEL);
++#endif
++
++ return (INTERNAL_SYSCALL_ERROR_P (res, err)
++ ? INTERNAL_SYSCALL_ERRNO (res, err)
++ : 0);
++ }
++ }
++
++ /* Set the scheduling parameters. */
++ if ((attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0)
++ {
++ res = INTERNAL_SYSCALL (sched_setscheduler, err, 3, pd->tid,
++ pd->schedpolicy, &pd->schedparam);
++
++ if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
++ goto err_out;
++ }
++ }
++
++ /* We now have for sure more than one thread. The main thread might
++ not yet have the flag set. No need to set the global variable
++ again if this is what we use. */
++ THREAD_SETMEM (THREAD_SELF, header.multiple_threads, 1);
++
++ return 0;
++}
++
++
++static int
++create_thread (struct pthread *pd, const struct pthread_attr *attr,
++ STACK_VARIABLES_PARMS)
++{
++#ifdef TLS_TCB_AT_TP
++ assert (pd->header.tcb != NULL);
++#endif
++
++ /* We rely heavily on various flags the CLONE function understands:
++
++ CLONE_VM, CLONE_FS, CLONE_FILES
++ These flags select semantics with shared address space and
++ file descriptors according to what POSIX requires.
++
++ CLONE_SIGNAL
++ This flag selects the POSIX signal semantics.
++
++ CLONE_SETTLS
++ The sixth parameter to CLONE determines the TLS area for the
++ new thread.
++
++ CLONE_PARENT_SETTID
++ The kernels writes the thread ID of the newly created thread
++ into the location pointed to by the fifth parameters to CLONE.
++
++ Note that it would be semantically equivalent to use
++ CLONE_CHILD_SETTID but it is be more expensive in the kernel.
++
++ CLONE_CHILD_CLEARTID
++ The kernels clears the thread ID of a thread that has called
++ sys_exit() in the location pointed to by the seventh parameter
++ to CLONE.
++
++ CLONE_DETACHED
++ No signal is generated if the thread exists and it is
++ automatically reaped.
++
++ The termination signal is chosen to be zero which means no signal
++ is sent. */
++ int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
++ | CLONE_SETTLS | CLONE_PARENT_SETTID
++ | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
++#if __ASSUME_NO_CLONE_DETACHED == 0
++ | CLONE_DETACHED
++#endif
++ | 0);
++
++ if (__builtin_expect (THREAD_GETMEM (THREAD_SELF, report_events), 0))
++ {
++ /* The parent thread is supposed to report events. Check whether
++ the TD_CREATE event is needed, too. */
++ const int _idx = __td_eventword (TD_CREATE);
++ const uint32_t _mask = __td_eventmask (TD_CREATE);
++
++ if ((_mask & (__nptl_threads_events.event_bits[_idx]
++ | pd->eventbuf.eventmask.event_bits[_idx])) != 0)
++ {
++ /* We always must have the thread start stopped. */
++ pd->stopped_start = true;
++
++ /* Create the thread. We always create the thread stopped
++ so that it does not get far before we tell the debugger. */
++ int res = do_clone (pd, attr, clone_flags, start_thread,
++ STACK_VARIABLES_ARGS, 1);
++ if (res == 0)
++ {
++ /* Now fill in the information about the new thread in
++ the newly created thread's data structure. We cannot let
++ the new thread do this since we don't know whether it was
++ already scheduled when we send the event. */
++ pd->eventbuf.eventnum = TD_CREATE;
++ pd->eventbuf.eventdata = pd;
++
++ /* Enqueue the descriptor. */
++ do
++ pd->nextevent = __nptl_last_event;
++ while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
++ pd, pd->nextevent)
++ != 0);
++
++ /* Now call the function which signals the event. */
++ __nptl_create_event ();
++
++ /* And finally restart the new thread. */
++ lll_unlock (pd->lock);
++ }
++
++ return res;
++ }
++ }
++
++#ifdef NEED_DL_SYSINFO
++ assert (THREAD_SELF_SYSINFO == THREAD_SYSINFO (pd));
++#endif
++
++ /* Determine whether the newly created threads has to be started
++ stopped since we have to set the scheduling parameters or set the
++ affinity. */
++ bool stopped = false;
++ if (attr != NULL && (attr->cpuset != NULL
++ || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
++ stopped = true;
++ pd->stopped_start = stopped;
++
++ /* Actually create the thread. */
++ int res = do_clone (pd, attr, clone_flags, start_thread,
++ STACK_VARIABLES_ARGS, stopped);
++
++ if (res == 0 && stopped)
++ /* And finally restart the new thread. */
++ lll_unlock (pd->lock);
++
++ return res;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/init.c libc/nptl/sysdeps/unix/sysv/linux/init.c
+--- libc/nptl/sysdeps/unix/sysv/linux/init.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/init.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,350 @@
++/* Copyright (C) 2002, 2003, 2004 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 <assert.h>
++#include <limits.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <sys/param.h>
++#include <sys/resource.h>
++#include <pthreadP.h>
++#include <atomic.h>
++#include <ldsodefs.h>
++#include <tls.h>
++#include <fork.h>
++#include <version.h>
++#include <shlib-compat.h>
++#include <smp.h>
++#include <lowlevellock.h>
++
++
++#ifndef __NR_set_tid_address
++/* XXX For the time being... Once we can rely on the kernel headers
++ having the definition remove these lines. */
++#if defined __s390__
++# define __NR_set_tid_address 252
++#elif defined __ia64__
++# define __NR_set_tid_address 1233
++#elif defined __i386__
++# define __NR_set_tid_address 258
++#elif defined __x86_64__
++# define __NR_set_tid_address 218
++#elif defined __powerpc__
++# define __NR_set_tid_address 232
++#elif defined __sparc__
++# define __NR_set_tid_address 166
++#else
++# error "define __NR_set_tid_address"
++#endif
++#endif
++
++
++/* Default stack size. */
++size_t __default_stacksize attribute_hidden;
++
++/* Size and alignment of static TLS block. */
++size_t __static_tls_size;
++size_t __static_tls_align_m1;
++
++/* Flag whether the machine is SMP or not. */
++int __is_smp attribute_hidden;
++
++/* Version of the library, used in libthread_db to detect mismatches. */
++static const char nptl_version[] __attribute_used__ = VERSION;
++
++
++#if defined USE_TLS && !defined SHARED
++extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
++#endif
++
++
++#ifdef SHARED
++static const struct pthread_functions pthread_functions =
++ {
++ .ptr_pthread_attr_destroy = __pthread_attr_destroy,
++# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
++ .ptr___pthread_attr_init_2_0 = __pthread_attr_init_2_0,
++# endif
++ .ptr___pthread_attr_init_2_1 = __pthread_attr_init_2_1,
++ .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,
++# if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2)
++ .ptr___pthread_cond_broadcast_2_0 = __pthread_cond_broadcast_2_0,
++ .ptr___pthread_cond_destroy_2_0 = __pthread_cond_destroy_2_0,
++ .ptr___pthread_cond_init_2_0 = __pthread_cond_init_2_0,
++ .ptr___pthread_cond_signal_2_0 = __pthread_cond_signal_2_0,
++ .ptr___pthread_cond_wait_2_0 = __pthread_cond_wait_2_0,
++ .ptr___pthread_cond_timedwait_2_0 = __pthread_cond_timedwait_2_0,
++# endif
++ .ptr_pthread_equal = __pthread_equal,
++ .ptr___pthread_exit = __pthread_exit,
++ .ptr_pthread_getschedparam = __pthread_getschedparam,
++ .ptr_pthread_setschedparam = __pthread_setschedparam,
++ .ptr_pthread_mutex_destroy = INTUSE(__pthread_mutex_destroy),
++ .ptr_pthread_mutex_init = INTUSE(__pthread_mutex_init),
++ .ptr_pthread_mutex_lock = INTUSE(__pthread_mutex_lock),
++ .ptr_pthread_mutex_unlock = INTUSE(__pthread_mutex_unlock),
++ .ptr_pthread_self = __pthread_self,
++ .ptr_pthread_setcancelstate = __pthread_setcancelstate,
++ .ptr_pthread_setcanceltype = __pthread_setcanceltype,
++ .ptr___pthread_cleanup_upto = __pthread_cleanup_upto,
++ .ptr___pthread_once = __pthread_once_internal,
++ .ptr___pthread_rwlock_rdlock = __pthread_rwlock_rdlock_internal,
++ .ptr___pthread_rwlock_wrlock = __pthread_rwlock_wrlock_internal,
++ .ptr___pthread_rwlock_unlock = __pthread_rwlock_unlock_internal,
++ .ptr___pthread_key_create = __pthread_key_create_internal,
++ .ptr___pthread_getspecific = __pthread_getspecific_internal,
++ .ptr___pthread_setspecific = __pthread_setspecific_internal,
++ .ptr__pthread_cleanup_push_defer = __pthread_cleanup_push_defer,
++ .ptr__pthread_cleanup_pop_restore = __pthread_cleanup_pop_restore,
++ .ptr_nthreads = &__nptl_nthreads,
++ .ptr___pthread_unwind = &__pthread_unwind,
++ .ptr__nptl_deallocate_tsd = __nptl_deallocate_tsd,
++ .ptr__nptl_setxid = __nptl_setxid
++ };
++# define ptr_pthread_functions &pthread_functions
++#else
++# define ptr_pthread_functions NULL
++#endif
++
++
++/* For asynchronous cancellation we use a signal. This is the handler. */
++static void
++sigcancel_handler (int sig, siginfo_t *si, void *ctx)
++{
++ /* Safety check. It would be possible to call this function for
++ other signals and send a signal from another process. This is not
++ correct and might even be a security problem. Try to catch as
++ many incorrect invocations as possible. */
++ if (sig != SIGCANCEL
++#ifdef __ASSUME_CORRECT_SI_PID
++ /* Kernels before 2.5.75 stored the thread ID and not the process
++ ID in si_pid so we skip this test. */
++ || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
++#endif
++ || si->si_code != SI_TKILL)
++ return;
++
++ struct pthread *self = THREAD_SELF;
++
++ int oldval = THREAD_GETMEM (self, cancelhandling);
++ while (1)
++ {
++ /* We are canceled now. When canceled by another thread this flag
++ is already set but if the signal is directly send (internally or
++ from another process) is has to be done here. */
++ int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
++
++ if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
++ /* Already canceled or exiting. */
++ break;
++
++ int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval,
++ oldval);
++ if (curval == oldval)
++ {
++ /* Set the return value. */
++ THREAD_SETMEM (self, result, PTHREAD_CANCELED);
++
++ /* Make sure asynchronous cancellation is still enabled. */
++ if ((newval & CANCELTYPE_BITMASK) != 0)
++ /* Run the registered destructors and terminate the thread. */
++ __do_cancel ();
++
++ break;
++ }
++
++ oldval = curval;
++ }
++}
++
++
++struct xid_command *__xidcmd attribute_hidden;
++
++/* For asynchronous cancellation we use a signal. This is the handler. */
++static void
++sighandler_setxid (int sig, siginfo_t *si, void *ctx)
++{
++ /* Safety check. It would be possible to call this function for
++ other signals and send a signal from another process. This is not
++ correct and might even be a security problem. Try to catch as
++ many incorrect invocations as possible. */
++ if (sig != SIGSETXID
++#ifdef __ASSUME_CORRECT_SI_PID
++ /* Kernels before 2.5.75 stored the thread ID and not the process
++ ID in si_pid so we skip this test. */
++ || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
++#endif
++ || si->si_code != SI_TKILL)
++ return;
++
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
++ __xidcmd->id[1], __xidcmd->id[2]);
++
++ if (atomic_decrement_val (&__xidcmd->cntr) == 0)
++ lll_futex_wake (&__xidcmd->cntr, 1);
++}
++
++
++/* 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));
++
++
++void
++__pthread_initialize_minimal_internal (void)
++{
++#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);
++
++ /* We must prevent gcc from being clever and move any of the
++ following code ahead of the __libc_setup_tls call. This function
++ will initialize the thread register which is subsequently
++ used. */
++ __asm __volatile ("");
++#endif
++
++ /* Minimal initialization of the thread descriptor. */
++ struct pthread *pd = THREAD_SELF;
++ INTERNAL_SYSCALL_DECL (err);
++ pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
++ THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
++ THREAD_SETMEM (pd, user_stack, true);
++ if (LLL_LOCK_INITIALIZER != 0)
++ THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
++#if HP_TIMING_AVAIL
++ THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
++#endif
++
++ /* Set initial thread's stack block from 0 up to __libc_stack_end.
++ It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
++ purposes this is good enough. */
++ THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);
++
++ /* Initialize the list of all running threads with the main thread. */
++ INIT_LIST_HEAD (&__stack_user);
++ list_add (&pd->list, &__stack_user);
++
++
++ /* Install the cancellation signal handler. If for some reason we
++ cannot install the handler we do not abort. Maybe we should, but
++ it is only asynchronous cancellation which is affected. */
++ struct sigaction sa;
++ sa.sa_sigaction = sigcancel_handler;
++ sa.sa_flags = SA_SIGINFO;
++ sigemptyset (&sa.sa_mask);
++
++ (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
++
++ /* Install the handle to change the threads' uid/gid. */
++ sa.sa_sigaction = sighandler_setxid;
++ sa.sa_flags = SA_SIGINFO | SA_RESTART;
++
++ (void) __libc_sigaction (SIGSETXID, &sa, NULL);
++
++ /* The parent process might have left the signal blocked. Just in
++ case, unblock it. We reuse the signal mask in the sigaction
++ structure. It is already cleared. */
++ __sigaddset (&sa.sa_mask, SIGCANCEL);
++ (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
++ NULL, _NSIG / 8);
++
++
++ /* Determine the default allowed stack size. This is the size used
++ in case the user does not specify one. */
++ struct rlimit limit;
++ if (getrlimit (RLIMIT_STACK, &limit) != 0
++ || limit.rlim_cur == RLIM_INFINITY)
++ /* The system limit is not usable. Use an architecture-specific
++ default. */
++ __default_stacksize = ARCH_STACK_DEFAULT_SIZE;
++ else if (limit.rlim_cur < PTHREAD_STACK_MIN)
++ /* The system limit is unusably small.
++ Use the minimal size acceptable. */
++ __default_stacksize = PTHREAD_STACK_MIN;
++ else
++ {
++ /* Round the resource limit up to page size. */
++ const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
++ __default_stacksize = (limit.rlim_cur + pagesz - 1) & -pagesz;
++ }
++
++ /* Get the size of the static and alignment requirements for the TLS
++ block. */
++ size_t static_tls_align;
++ _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);
++
++ /* Make sure the size takes all the alignments into account. */
++ if (STACK_ALIGN > static_tls_align)
++ static_tls_align = STACK_ALIGN;
++ __static_tls_align_m1 = static_tls_align - 1;
++
++ __static_tls_size = roundup (__static_tls_size, static_tls_align);
++
++#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 *) INTUSE (__pthread_mutex_lock);
++ GL(dl_rtld_unlock_recursive) = (void *) INTUSE (__pthread_mutex_unlock);
++ unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
++ GL(dl_load_lock).mutex.__data.__count = 0;
++ while (rtld_lock_count-- > 0)
++ INTUSE (__pthread_mutex_lock) (&GL(dl_load_lock).mutex);
++
++ GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
++#endif
++
++ GL(dl_init_static_tls) = &__pthread_init_static_tls;
++
++ /* Register the fork generation counter with the libc. */
++#ifndef TLS_MULTIPLE_THREADS_IN_TCB
++ __libc_multiple_threads_ptr =
++#endif
++ __libc_pthread_init (&__fork_generation, __reclaim_stacks,
++ ptr_pthread_functions);
++
++ /* Determine whether the machine is SMP or not. */
++ __is_smp = is_smp_system ();
++}
++strong_alias (__pthread_initialize_minimal_internal,
++ __pthread_initialize_minimal)
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/Makefile libc/nptl/sysdeps/unix/sysv/linux/Makefile
+--- libc/nptl/sysdeps/unix/sysv/linux/Makefile 2004-01-03 09:55:30.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/Makefile 2005-01-23 19:35:29.000000000 +0100
+@@ -21,10 +21,14 @@ ifeq ($(subdir),nptl)
+ sysdep_routines += register-atfork unregister-atfork libc_pthread_init \
+ libc_multiple_threads
+
+-libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock
++libpthread-sysdep_routines += pt-fork pthread_mutex_cond_lock pt-vfork \
++ ptw-llseek
+
+ gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \
+ lowlevelbarrier.sym unwindbuf.sym
++
++tests += tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x
++tests-reverse += tst-vfork1x tst-vfork2x
+ endif
+
+ ifeq ($(subdir),posix)
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/pthread_cancel.c libc/nptl/sysdeps/unix/sysv/linux/pthread_cancel.c
+--- libc/nptl/sysdeps/unix/sysv/linux/pthread_cancel.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/pthread_cancel.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,102 @@
++/* 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 <errno.h>
++#include <signal.h>
++#include "pthreadP.h"
++#include "atomic.h"
++#include <sysdep.h>
++#include <kernel-features.h>
++
++
++int
++pthread_cancel (th)
++ pthread_t th;
++{
++ volatile struct pthread *pd = (volatile struct pthread *) th;
++
++ /* Make sure the descriptor is valid. */
++ if (INVALID_TD_P (pd))
++ /* Not a valid thread handle. */
++ return ESRCH;
++
++#ifdef SHARED
++ pthread_cancel_init ();
++#endif
++ int result = 0;
++ int oldval;
++ int newval;
++ do
++ {
++ oldval = pd->cancelhandling;
++ newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK;
++
++ /* Avoid doing unnecessary work. The atomic operation can
++ potentially be expensive if the bug has to be locked and
++ remote cache lines have to be invalidated. */
++ if (oldval == newval)
++ break;
++
++ /* If the cancellation is handled asynchronously just send a
++ signal. We avoid this if possible since it's more
++ expensive. */
++ if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
++ {
++ /* Mark the cancellation as "in progress". */
++ atomic_bit_set (&pd->cancelhandling, CANCELING_BIT);
++
++ /* The cancellation handler will take care of marking the
++ thread as canceled. */
++ INTERNAL_SYSCALL_DECL (err);
++
++ /* One comment: The PID field in the TCB can temporarily be
++ changed (in fork). But this must not affect this code
++ here. Since this function would have to be called while
++ the thread is executing fork, it would have to happen in
++ a signal handler. But this is no allowed, pthread_cancel
++ is not guaranteed to be async-safe. */
++ int val;
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
++ SIGCANCEL);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3,
++ THREAD_GETMEM (THREAD_SELF, pid), pd->tid,
++ SIGCANCEL);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, pd->tid, SIGCANCEL);
++#endif
++
++ if (INTERNAL_SYSCALL_ERROR_P (val, err))
++ result = INTERNAL_SYSCALL_ERRNO (val, err);
++
++ break;
++ }
++ }
++ /* Mark the thread as canceled. This has to be done
++ atomically since other bits could be modified as well. */
++ while (atomic_compare_and_exchange_bool_acq (&pd->cancelhandling, newval,
++ oldval));
++
++ return result;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/pthread_condattr_setclock.c libc/nptl/sysdeps/unix/sysv/linux/pthread_condattr_setclock.c
+--- libc/nptl/sysdeps/unix/sysv/linux/pthread_condattr_setclock.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/pthread_condattr_setclock.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,72 @@
++/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <time.h>
++#include <sysdep.h>
++#include "pthreadP.h"
++#include <kernel-features.h>
++
++
++int
++pthread_condattr_setclock (attr, clock_id)
++ pthread_condattr_t *attr;
++ clockid_t clock_id;
++{
++ /* Only a few clocks are allowed. CLOCK_REALTIME is always allowed.
++ CLOCK_MONOTONIC only if the kernel has the necessary support. */
++ if (clock_id == CLOCK_MONOTONIC)
++ {
++#ifndef __ASSUME_POSIX_TIMERS
++# ifdef __NR_clock_getres
++ /* Check whether the clock is available. */
++ static int avail;
++
++ if (avail == 0)
++ {
++ struct timespec ts;
++
++ INTERNAL_SYSCALL_DECL (err);
++ int val;
++ val = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts);
++ avail = INTERNAL_SYSCALL_ERROR_P (val, err) ? -1 : 1;
++ }
++
++ if (avail < 0)
++# endif
++ /* Not available. */
++ return EINVAL;
++#endif
++ }
++ else if (clock_id != CLOCK_REALTIME)
++ /* If more clocks are allowed some day the storing of the clock ID
++ in the pthread_cond_t structure needs to be adjusted. */
++ return EINVAL;
++
++ /* Make sure the value fits in the bits we reserved. */
++ assert (clock_id < (1 << COND_CLOCK_BITS));
++
++ int *valuep = &((struct pthread_condattr *) attr)->value;
++
++ *valuep = (*valuep & ~(1 << (COND_CLOCK_BITS + 1)) & ~1) | (clock_id << 1);
++
++ return 0;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/pthread_create.c libc/nptl/sysdeps/unix/sysv/linux/pthread_create.c
+--- libc/nptl/sysdeps/unix/sysv/linux/pthread_create.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/pthread_create.c 2005-01-23 20:07:20.000000000 +0100
+@@ -0,0 +1,522 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include "pthreadP.h"
++#include <hp-timing.h>
++#include <ldsodefs.h>
++#include <atomic.h>
++#include <libc-internal.h>
++#include <resolv.h>
++
++#include <shlib-compat.h>
++
++
++/* Local function to start thread and handle cleanup. */
++static int start_thread (void *arg);
++
++
++/* Nozero if debugging mode is enabled. */
++int __pthread_debug;
++
++/* Globally enabled events. */
++static td_thr_events_t __nptl_threads_events;
++
++/* Pointer to descriptor with the last event. */
++static struct pthread *__nptl_last_event;
++
++/* Number of threads running. */
++unsigned int __nptl_nthreads = 1;
++
++
++/* Code to allocate and deallocate a stack. */
++#include "allocatestack.c"
++
++/* Code to create the thread. */
++#include "createthread.c"
++
++
++struct pthread *
++internal_function
++__find_in_stack_list (pd)
++ struct pthread *pd;
++{
++ list_t *entry;
++ struct pthread *result = NULL;
++
++ lll_lock (stack_cache_lock);
++
++ list_for_each (entry, &stack_used)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (entry, struct pthread, list);
++ if (curp == pd)
++ {
++ result = curp;
++ break;
++ }
++ }
++
++ if (result == NULL)
++ list_for_each (entry, &__stack_user)
++ {
++ struct pthread *curp;
++
++ curp = list_entry (entry, struct pthread, list);
++ if (curp == pd)
++ {
++ result = curp;
++ break;
++ }
++ }
++
++ lll_unlock (stack_cache_lock);
++
++ return result;
++}
++
++
++/* Deallocate POSIX thread-local-storage. */
++void
++attribute_hidden
++__nptl_deallocate_tsd (void)
++{
++ struct pthread *self = THREAD_SELF;
++
++ /* Maybe no data was ever allocated. This happens often so we have
++ a flag for this. */
++ if (THREAD_GETMEM (self, specific_used))
++ {
++ size_t round;
++ size_t cnt;
++
++ round = 0;
++ do
++ {
++ size_t idx;
++
++ /* So far no new nonzero data entry. */
++ THREAD_SETMEM (self, specific_used, false);
++
++ for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
++ {
++ struct pthread_key_data *level2;
++
++ level2 = THREAD_GETMEM_NC (self, specific, cnt);
++
++ if (level2 != NULL)
++ {
++ size_t inner;
++
++ for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
++ ++inner, ++idx)
++ {
++ void *data = level2[inner].data;
++
++ if (data != NULL)
++ {
++ /* Always clear the data. */
++ level2[inner].data = NULL;
++
++ /* Make sure the data corresponds to a valid
++ key. This test fails if the key was
++ deallocated and also if it was
++ re-allocated. It is the user's
++ responsibility to free the memory in this
++ case. */
++ if (level2[inner].seq
++ == __pthread_keys[idx].seq
++ /* It is not necessary to register a destructor
++ function. */
++ && __pthread_keys[idx].destr != NULL)
++ /* Call the user-provided destructor. */
++ __pthread_keys[idx].destr (data);
++ }
++ }
++ }
++ else
++ idx += PTHREAD_KEY_1STLEVEL_SIZE;
++ }
++
++ if (THREAD_GETMEM (self, specific_used) == 0)
++ /* No data has been modified. */
++ goto just_free;
++ }
++ /* We only repeat the process a fixed number of times. */
++ while (__builtin_expect (++round < PTHREAD_DESTRUCTOR_ITERATIONS, 0));
++
++ /* Just clear the memory of the first block for reuse. */
++ memset (&THREAD_SELF->specific_1stblock, '\0',
++ sizeof (self->specific_1stblock));
++
++ just_free:
++ /* Free the memory for the other blocks. */
++ for (cnt = 1; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
++ {
++ struct pthread_key_data *level2;
++
++ level2 = THREAD_GETMEM_NC (self, specific, cnt);
++ if (level2 != NULL)
++ {
++ /* The first block is allocated as part of the thread
++ descriptor. */
++ free (level2);
++ THREAD_SETMEM_NC (self, specific, cnt, NULL);
++ }
++ }
++
++ THREAD_SETMEM (self, specific_used, false);
++ }
++}
++
++
++/* Deallocate a thread's stack after optionally making sure the thread
++ descriptor is still valid. */
++void
++internal_function
++__free_tcb (struct pthread *pd)
++{
++ /* The thread is exiting now. */
++ if (__builtin_expect (atomic_bit_test_set (&pd->cancelhandling,
++ TERMINATED_BIT) == 0, 1))
++ {
++ /* Remove the descriptor from the list. */
++ if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
++ /* Something is really wrong. The descriptor for a still
++ running thread is gone. */
++ abort ();
++
++ /* Queue the stack memory block for reuse and exit the process. The
++ kernel will signal via writing to the address returned by
++ QUEUE-STACK when the stack is available. */
++ __deallocate_stack (pd);
++ }
++}
++
++
++static int
++start_thread (void *arg)
++{
++ struct pthread *pd = (struct pthread *) arg;
++
++#if HP_TIMING_AVAIL
++ /* Remember the time when the thread was started. */
++ hp_timing_t now;
++ HP_TIMING_NOW (now);
++ THREAD_SETMEM (pd, cpuclock_offset, now);
++#endif
++
++ /* Initialize resolver state pointer. */
++ __resp = &pd->res;
++
++ /* This is where the try/finally block should be created. For
++ compilers without that support we do use setjmp. */
++ struct pthread_unwind_buf unwind_buf;
++
++ /* No previous handlers. */
++ unwind_buf.priv.data.prev = NULL;
++ unwind_buf.priv.data.cleanup = NULL;
++
++ int not_first_call;
++ not_first_call = setjmp ((struct __jmp_buf_tag *) unwind_buf.cancel_jmp_buf);
++ if (__builtin_expect (! not_first_call, 1))
++ {
++ /* Store the new cleanup handler info. */
++ THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
++
++ if (__builtin_expect (pd->stopped_start, 0))
++ {
++ int oldtype = CANCEL_ASYNC ();
++
++ /* Get the lock the parent locked to force synchronization. */
++ lll_lock (pd->lock);
++ /* And give it up right away. */
++ lll_unlock (pd->lock);
++
++ CANCEL_RESET (oldtype);
++ }
++
++ /* Run the code the user provided. */
++#ifdef CALL_THREAD_FCT
++ THREAD_SETMEM (pd, result, CALL_THREAD_FCT (pd));
++#else
++ THREAD_SETMEM (pd, result, pd->start_routine (pd->arg));
++#endif
++ }
++
++ /* Run the destructor for the thread-local data. */
++ __nptl_deallocate_tsd ();
++
++ /* Clean up any state libc stored in thread-local variables. */
++ __libc_thread_freeres ();
++
++ /* If this is the last thread we terminate the process now. We
++ do not notify the debugger, it might just irritate it if there
++ is no thread left. */
++ if (__builtin_expect (atomic_decrement_and_test (&__nptl_nthreads), 0))
++ /* This was the last thread. */
++ exit (0);
++
++ /* Report the death of the thread if this is wanted. */
++ if (__builtin_expect (pd->report_events, 0))
++ {
++ /* See whether TD_DEATH is in any of the mask. */
++ const int idx = __td_eventword (TD_DEATH);
++ const uint32_t mask = __td_eventmask (TD_DEATH);
++
++ if ((mask & (__nptl_threads_events.event_bits[idx]
++ | pd->eventbuf.eventmask.event_bits[idx])) != 0)
++ {
++ /* Yep, we have to signal the death. Add the descriptor to
++ the list but only if it is not already on it. */
++ if (pd->nextevent == NULL)
++ {
++ pd->eventbuf.eventnum = TD_DEATH;
++ pd->eventbuf.eventdata = pd;
++
++ do
++ pd->nextevent = __nptl_last_event;
++ while (atomic_compare_and_exchange_bool_acq (&__nptl_last_event,
++ pd, pd->nextevent));
++ }
++
++ /* Now call the function to signal the event. */
++ __nptl_death_event ();
++ }
++ }
++
++ /* The thread is exiting now. Don't set this bit until after we've hit
++ the event-reporting breakpoint, so that td_thr_get_info on us while at
++ the breakpoint reports TD_THR_RUN state rather than TD_THR_ZOMBIE. */
++ atomic_bit_set (&pd->cancelhandling, EXITING_BIT);
++
++ /* If the thread is detached free the TCB. */
++ if (IS_DETACHED (pd))
++ /* Free the TCB. */
++ __free_tcb (pd);
++
++ /* We cannot call '_exit' here. '_exit' will terminate the process.
++
++ The 'exit' implementation in the kernel will signal when the
++ process is really dead since 'clone' got passed the CLONE_CLEARTID
++ flag. The 'tid' field in the TCB will be set to zero.
++
++ The exit code is zero since in case all threads exit by calling
++ 'pthread_exit' the exit status must be 0 (zero). */
++ __exit_thread_inline (0);
++
++ /* NOTREACHED */
++ return 0;
++}
++
++
++/* Default thread attributes for the case when the user does not
++ provide any. */
++static const struct pthread_attr default_attr =
++ {
++ /* Just some value > 0 which gets rounded to the nearest page size. */
++ .guardsize = 1,
++ };
++
++
++int
++__pthread_create_2_1 (newthread, attr, start_routine, arg)
++ pthread_t *newthread;
++ const pthread_attr_t *attr;
++ void *(*start_routine) (void *);
++ void *arg;
++{
++ STACK_VARIABLES;
++ const struct pthread_attr *iattr;
++ struct pthread *pd;
++ int err;
++
++ iattr = (struct pthread_attr *) attr;
++ if (iattr == NULL)
++ /* Is this the best idea? On NUMA machines this could mean
++ accessing far-away memory. */
++ iattr = &default_attr;
++
++ err = ALLOCATE_STACK (iattr, &pd);
++ if (__builtin_expect (err != 0, 0))
++ /* Something went wrong. Maybe a parameter of the attributes is
++ invalid or we could not allocate memory. */
++ return err;
++
++
++ /* Initialize the TCB. All initializations with zero should be
++ performed in 'get_cached_stack'. This way we avoid doing this if
++ the stack freshly allocated with 'mmap'. */
++
++#ifdef TLS_TCB_AT_TP
++ /* Reference to the TCB itself. */
++ pd->header.self = pd;
++
++ /* Self-reference for TLS. */
++ pd->header.tcb = pd;
++#endif
++
++ /* Store the address of the start routine and the parameter. Since
++ we do not start the function directly the stillborn thread will
++ get the information from its thread descriptor. */
++ pd->start_routine = start_routine;
++ pd->arg = arg;
++
++ /* Copy the thread attribute flags. */
++ struct pthread *self = THREAD_SELF;
++ pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
++ | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
++
++ /* Initialize the field for the ID of the thread which is waiting
++ for us. This is a self-reference in case the thread is created
++ detached. */
++ pd->joinid = iattr->flags & ATTR_FLAG_DETACHSTATE ? pd : NULL;
++
++ /* The debug events are inherited from the parent. */
++ pd->eventbuf = self->eventbuf;
++
++
++ /* Copy the parent's scheduling parameters. The flags will say what
++ is valid and what is not. */
++ pd->schedpolicy = self->schedpolicy;
++ pd->schedparam = self->schedparam;
++
++ /* Determine scheduling parameters for the thread. */
++ if (attr != NULL
++ && __builtin_expect ((iattr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0, 0)
++ && (iattr->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)) != 0)
++ {
++ INTERNAL_SYSCALL_DECL (err);
++
++ /* Use the scheduling parameters the user provided. */
++ if (iattr->flags & ATTR_FLAG_POLICY_SET)
++ pd->schedpolicy = iattr->schedpolicy;
++ else if ((pd->flags & ATTR_FLAG_POLICY_SET) == 0)
++ {
++ pd->schedpolicy = INTERNAL_SYSCALL (sched_getscheduler, err, 1, 0);
++ pd->flags |= ATTR_FLAG_POLICY_SET;
++ }
++
++ if (iattr->flags & ATTR_FLAG_SCHED_SET)
++ memcpy (&pd->schedparam, &iattr->schedparam,
++ sizeof (struct sched_param));
++ else if ((pd->flags & ATTR_FLAG_SCHED_SET) == 0)
++ {
++ INTERNAL_SYSCALL (sched_getparam, err, 2, 0, &pd->schedparam);
++ pd->flags |= ATTR_FLAG_SCHED_SET;
++ }
++
++ /* Check for valid priorities. */
++ int minprio = INTERNAL_SYSCALL (sched_get_priority_min, err, 1,
++ iattr->schedpolicy);
++ int maxprio = INTERNAL_SYSCALL (sched_get_priority_max, err, 1,
++ iattr->schedpolicy);
++ if (pd->schedparam.sched_priority < minprio
++ || pd->schedparam.sched_priority > maxprio)
++ {
++ err = EINVAL;
++ goto errout;
++ }
++ }
++
++ /* Pass the descriptor to the caller. */
++ *newthread = (pthread_t) pd;
++
++ /* Remember whether the thread is detached or not. In case of an
++ error we have to free the stacks of non-detached stillborn
++ threads. */
++ bool is_detached = IS_DETACHED (pd);
++
++ /* Start the thread. */
++ err = create_thread (pd, iattr, STACK_VARIABLES_ARGS);
++ if (err != 0)
++ {
++ /* Something went wrong. Free the resources. */
++ if (!is_detached)
++ {
++ errout:
++ __deallocate_stack (pd);
++ }
++ return err;
++ }
++
++ return 0;
++}
++versioned_symbol (libpthread, __pthread_create_2_1, pthread_create, GLIBC_2_1);
++
++
++#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
++int
++__pthread_create_2_0 (newthread, attr, start_routine, arg)
++ pthread_t *newthread;
++ const pthread_attr_t *attr;
++ void *(*start_routine) (void *);
++ void *arg;
++{
++ /* The ATTR attribute is not really of type `pthread_attr_t *'. It has
++ the old size and access to the new members might crash the program.
++ We convert the struct now. */
++ struct pthread_attr new_attr;
++
++ if (attr != NULL)
++ {
++ struct pthread_attr *iattr = (struct pthread_attr *) attr;
++ size_t ps = __getpagesize ();
++
++ /* Copy values from the user-provided attributes. */
++ new_attr.schedparam = iattr->schedparam;
++ new_attr.schedpolicy = iattr->schedpolicy;
++ new_attr.flags = iattr->flags;
++
++ /* Fill in default values for the fields not present in the old
++ implementation. */
++ new_attr.guardsize = ps;
++ new_attr.stackaddr = NULL;
++ new_attr.stacksize = 0;
++ new_attr.cpuset = NULL;
++
++ /* We will pass this value on to the real implementation. */
++ attr = (pthread_attr_t *) &new_attr;
++ }
++
++ return __pthread_create_2_1 (newthread, attr, start_routine, arg);
++}
++compat_symbol (libpthread, __pthread_create_2_0, pthread_create,
++ GLIBC_2_0);
++#endif
++
++/* Information for libthread_db. */
++
++#include "../nptl_db/db_info.c"
++
++/* If pthread_create is present, libgcc_eh.a and libsupc++.a expects some other POSIX thread
++ functions to be present as well. */
++PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_lock)
++PTHREAD_STATIC_FN_REQUIRE (pthread_mutex_unlock)
++
++PTHREAD_STATIC_FN_REQUIRE (pthread_once)
++PTHREAD_STATIC_FN_REQUIRE (pthread_cancel)
++
++PTHREAD_STATIC_FN_REQUIRE (pthread_key_create)
++PTHREAD_STATIC_FN_REQUIRE (pthread_setspecific)
++PTHREAD_STATIC_FN_REQUIRE (pthread_getspecific)
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/pthread_sigmask.c libc/nptl/sysdeps/unix/sysv/linux/pthread_sigmask.c
+--- libc/nptl/sysdeps/unix/sysv/linux/pthread_sigmask.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/pthread_sigmask.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,58 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <signal.h>
++#include <pthreadP.h>
++#include <sysdep.h>
++
++
++int
++pthread_sigmask (how, newmask, oldmask)
++ int how;
++ const sigset_t *newmask;
++ sigset_t *oldmask;
++{
++ sigset_t local_newmask;
++
++ /* The only thing we have to make sure here is that SIGCANCEL and
++ SIGSETXID is not blocked. */
++ if (newmask != NULL
++ && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0)
++ || __builtin_expect (__sigismember (newmask, SIGSETXID), 0)))
++ {
++ local_newmask = *newmask;
++ __sigdelset (&local_newmask, SIGCANCEL);
++ __sigdelset (&local_newmask, SIGSETXID);
++ newmask = &local_newmask;
++ }
++
++#ifdef INTERNAL_SYSCALL
++ /* We know that realtime signals are available if NPTL is used. */
++ INTERNAL_SYSCALL_DECL (err);
++ int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask,
++ oldmask, _NSIG / 8);
++
++ return (INTERNAL_SYSCALL_ERROR_P (result, err)
++ ? INTERNAL_SYSCALL_ERRNO (result, err)
++ : 0);
++#else
++ return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0;
++#endif
++}
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/sem_open.c libc/nptl/sysdeps/unix/sysv/linux/sem_open.c
+--- libc/nptl/sysdeps/unix/sysv/linux/sem_open.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/sem_open.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,404 @@
++/* 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 <errno.h>
++#include <fcntl.h>
++#include <mntent.h>
++#include <paths.h>
++#include <pthread.h>
++#include <search.h>
++#include <semaphore.h>
++#include <stdarg.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/mman.h>
++#include <sys/stat.h>
++#include <sys/statfs.h>
++#include <linux_fsinfo.h>
++#include "semaphoreP.h"
++
++
++
++/* Information about the mount point. */
++struct mountpoint_info mountpoint attribute_hidden;
++
++/* This is the default mount point. */
++static const char defaultmount[] = "/dev/shm";
++/* This is the default directory. */
++static const char defaultdir[] = "/dev/shm/sem.";
++
++/* Protect the `mountpoint' variable above. */
++pthread_once_t __namedsem_once attribute_hidden = PTHREAD_ONCE_INIT;
++
++
++/* Determine where the shmfs is mounted (if at all). */
++void
++attribute_hidden
++__where_is_shmfs (void)
++{
++ char buf[512];
++ struct statfs f;
++ struct mntent resmem;
++ struct mntent *mp;
++ FILE *fp;
++
++ /* The canonical place is /dev/shm. This is at least what the
++ documentation tells everybody to do. */
++ if (__statfs (defaultmount, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC)
++ {
++ /* It is in the normal place. */
++ mountpoint.dir = (char *) defaultdir;
++ mountpoint.dirlen = sizeof (defaultdir) - 1;
++
++ return;
++ }
++
++ /* OK, do it the hard way. Look through the /proc/mounts file and if
++ this does not exist through /etc/fstab to find the mount point. */
++ fp = __setmntent ("/proc/mounts", "r");
++ if (__builtin_expect (fp == NULL, 0))
++ {
++ fp = __setmntent (_PATH_MNTTAB, "r");
++ if (__builtin_expect (fp == NULL, 0))
++ /* There is nothing we can do. Blind guesses are not helpful. */
++ return;
++ }
++
++ /* Now read the entries. */
++ while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL)
++ /* The original name is "shm" but this got changed in early Linux
++ 2.4.x to "tmpfs". */
++ if (strcmp (mp->mnt_type, "tmpfs") == 0
++ || strcmp (mp->mnt_type, "shm") == 0)
++ {
++ /* Found it. There might be more than one place where the
++ filesystem is mounted but one is enough for us. */
++ size_t namelen;
++
++ /* First make sure this really is the correct entry. At least
++ some versions of the kernel give wrong information because
++ of the implicit mount of the shmfs for SysV IPC. */
++ if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC)
++ continue;
++
++ namelen = strlen (mp->mnt_dir);
++
++ if (namelen == 0)
++ /* Hum, maybe some crippled entry. Keep on searching. */
++ continue;
++
++ mountpoint.dir = (char *) malloc (namelen + 4 + 2);
++ if (mountpoint.dir != NULL)
++ {
++ char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen);
++ if (cp[-1] != '/')
++ *cp++ = '/';
++ cp = stpcpy (cp, "sem.");
++ mountpoint.dirlen = cp - mountpoint.dir;
++ }
++
++ break;
++ }
++
++ /* Close the stream. */
++ __endmntent (fp);
++}
++
++
++/* Comparison function for search of existing mapping. */
++int
++attribute_hidden
++__sem_search (const void *a, const void *b)
++{
++ const struct inuse_sem *as = (const struct inuse_sem *) a;
++ const struct inuse_sem *bs = (const struct inuse_sem *) b;
++
++ if (as->ino != bs->ino)
++ /* Cannot return the difference the type is larger than int. */
++ return as->ino < bs->ino ? -1 : (as->ino == bs->ino ? 0 : 1);
++
++ if (as->dev != bs->dev)
++ /* Cannot return the difference the type is larger than int. */
++ return as->dev < bs->dev ? -1 : (as->dev == bs->dev ? 0 : 1);
++
++ return strcmp (as->name, bs->name);
++}
++
++
++/* The search tree for existing mappings. */
++void *__sem_mappings attribute_hidden;
++
++/* Lock to protect the search tree. */
++lll_lock_t __sem_mappings_lock = LLL_LOCK_INITIALIZER;
++
++
++/* Search for existing mapping and if possible add the one provided. */
++static sem_t *
++check_add_mapping (const char *name, size_t namelen, int fd, sem_t *existing)
++{
++ sem_t *result = SEM_FAILED;
++
++ /* Get the information about the file. */
++ struct stat64 st;
++ if (__fxstat64 (_STAT_VER, fd, &st) == 0)
++ {
++ /* Get the lock. */
++ lll_lock (__sem_mappings_lock);
++
++ /* Search for an existing mapping given the information we have. */
++ struct inuse_sem *fake;
++ fake = (struct inuse_sem *) alloca (sizeof (*fake) + namelen);
++ memcpy (fake->name, name, namelen);
++ fake->dev = st.st_dev;
++ fake->ino = st.st_ino;
++
++ struct inuse_sem **foundp = tfind (fake, &__sem_mappings, __sem_search);
++ if (foundp != NULL)
++ {
++ /* There is already a mapping. Use it. */
++ result = (*foundp)->sem;
++ ++(*foundp)->refcnt;
++ }
++ else
++ {
++ /* We haven't found a mapping. Install ione. */
++ struct inuse_sem *newp;
++
++ newp = (struct inuse_sem *) malloc (sizeof (*newp) + namelen);
++ if (newp != NULL)
++ {
++ /* If the caller hasn't provided any map it now. */
++ if (existing == SEM_FAILED)
++ existing = (sem_t *) mmap (NULL, sizeof (sem_t),
++ PROT_READ | PROT_WRITE, MAP_SHARED,
++ fd, 0);
++
++ newp->dev = st.st_dev;
++ newp->ino = st.st_ino;
++ newp->refcnt = 1;
++ newp->sem = existing;
++ memcpy (newp->name, name, namelen);
++
++ /* Insert the new value. */
++ if (existing != MAP_FAILED
++ && tsearch (newp, &__sem_mappings, __sem_search) != NULL)
++ /* Successful. */
++ result = existing;
++ else
++ /* Something went wrong while inserting the new
++ value. We fail completely. */
++ free (newp);
++ }
++ }
++
++ /* Release the lock. */
++ lll_unlock (__sem_mappings_lock);
++ }
++
++ if (result != existing && existing != SEM_FAILED && existing != MAP_FAILED)
++ {
++ /* Do not disturb errno. */
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (munmap, err, 2, existing, sizeof (sem_t));
++ }
++
++ return result;
++}
++
++
++sem_t *
++sem_open (const char *name, int oflag, ...)
++{
++ char *finalname;
++ sem_t *result = SEM_FAILED;
++ int fd;
++
++ /* Determine where the shmfs is mounted. */
++ INTUSE(__pthread_once) (&__namedsem_once, __where_is_shmfs);
++
++ /* If we don't know the mount points there is nothing we can do. Ever. */
++ if (mountpoint.dir == NULL)
++ {
++ __set_errno (ENOSYS);
++ return SEM_FAILED;
++ }
++
++ /* Construct the filename. */
++ while (name[0] == '/')
++ ++name;
++
++ if (name[0] == '\0')
++ {
++ /* The name "/" is not supported. */
++ __set_errno (EINVAL);
++ return SEM_FAILED;
++ }
++ size_t namelen = strlen (name) + 1;
++
++ /* Create the name of the final file. */
++ finalname = (char *) alloca (mountpoint.dirlen + namelen);
++ __mempcpy (__mempcpy (finalname, mountpoint.dir, mountpoint.dirlen),
++ name, namelen);
++
++ /* If the semaphore object has to exist simply open it. */
++ if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0)
++ {
++ try_again:
++ fd = __libc_open (finalname,
++ (oflag & ~(O_CREAT|O_ACCMODE)) | O_NOFOLLOW | O_RDWR);
++
++ if (fd == -1)
++ {
++ /* If we are supposed to create the file try this next. */
++ if ((oflag & O_CREAT) != 0 && errno == ENOENT)
++ goto try_create;
++
++ /* Return. errno is already set. */
++ }
++ else
++ /* Check whether we already have this semaphore mapped and
++ create one if necessary. */
++ result = check_add_mapping (name, namelen, fd, SEM_FAILED);
++ }
++ else
++ {
++ /* We have to open a temporary file first since it must have the
++ correct form before we can start using it. */
++ char *tmpfname;
++ mode_t mode;
++ unsigned int value;
++ va_list ap;
++
++ try_create:
++ va_start (ap, oflag);
++
++ mode = va_arg (ap, mode_t);
++ value = va_arg (ap, unsigned int);
++
++ va_end (ap);
++
++ if (value > SEM_VALUE_MAX)
++ {
++ __set_errno (EINVAL);
++ return SEM_FAILED;
++ }
++
++ /* Create the initial file content. */
++ sem_t initsem;
++
++ struct sem *iinitsem = (struct sem *) &initsem;
++ iinitsem->count = value;
++
++ /* Initialize the remaining bytes as well. */
++ memset ((char *) &initsem + sizeof (struct sem), '\0',
++ sizeof (sem_t) - sizeof (struct sem));
++
++ tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
++ char *xxxxxx = __mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen);
++
++ int retries = 0;
++#define NRETRIES 50
++ while (1)
++ {
++ /* Add the suffix for mktemp. */
++ strcpy (xxxxxx, "XXXXXX");
++
++ /* We really want to use mktemp here. We cannot use mkstemp
++ since the file must be opened with a specific mode. The
++ mode cannot later be set since then we cannot apply the
++ file create mask. */
++ if (mktemp (tmpfname) == NULL)
++ return SEM_FAILED;
++
++ /* Open the file. Make sure we do not overwrite anything. */
++ fd = __libc_open (tmpfname, O_RDWR | O_CREAT | O_EXCL, mode);
++ if (fd == -1)
++ {
++ if (errno == EEXIST)
++ {
++ if (++retries < NRETRIES)
++ continue;
++
++ __set_errno (EAGAIN);
++ }
++
++ return SEM_FAILED;
++ }
++
++ /* We got a file. */
++ break;
++ }
++
++ if (TEMP_FAILURE_RETRY (__libc_write (fd, &initsem, sizeof (sem_t)))
++ == sizeof (sem_t)
++ /* Map the sem_t structure from the file. */
++ && (result = (sem_t *) mmap (NULL, sizeof (sem_t),
++ PROT_READ | PROT_WRITE, MAP_SHARED,
++ fd, 0)) != MAP_FAILED)
++ {
++ /* Create the file. Don't overwrite an existing file. */
++ if (link (tmpfname, finalname) != 0)
++ {
++ /* Undo the mapping. */
++ (void) munmap (result, sizeof (sem_t));
++
++ /* Reinitialize 'result'. */
++ result = SEM_FAILED;
++
++ /* This failed. If O_EXCL is not set and the problem was
++ that the file exists, try again. */
++ if ((oflag & O_EXCL) == 0 && errno == EEXIST)
++ {
++ /* Remove the file. */
++ (void) unlink (tmpfname);
++
++ /* Close the file. */
++ (void) __libc_close (fd);
++
++ goto try_again;
++ }
++ }
++ else
++ /* Insert the mapping into the search tree. This also
++ determines whether another thread sneaked by and already
++ added such a mapping despite the fact that we created it. */
++ result = check_add_mapping (name, namelen, fd, result);
++ }
++
++ /* Now remove the temporary name. This should never fail. If
++ it fails we leak a file name. Better fix the kernel. */
++ (void) unlink (tmpfname);
++ }
++
++ /* Map the mmap error to the error we need. */
++ if (MAP_FAILED != (void *) SEM_FAILED && result == MAP_FAILED)
++ result = SEM_FAILED;
++
++ /* We don't need the file descriptor anymore. */
++ if (fd != -1)
++ {
++ /* Do not disturb errno. */
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (close, err, 1, fd);
++ }
++
++ return result;
++}
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/sigaction.c libc/nptl/sysdeps/unix/sysv/linux/sigaction.c
+--- libc/nptl/sysdeps/unix/sysv/linux/sigaction.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/sigaction.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,54 @@
++/* Copyright (C) 2002, 2003, 2004 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. */
++
++/* This is tricky. GCC doesn't like #include_next in the primary
++ source file and even if it did, the first #include_next is this
++ exact file anyway. */
++#ifndef LIBC_SIGACTION
++
++#include <nptl/pthreadP.h>
++
++/* We use the libc implementation but we tell it to not allow
++ SIGCANCEL or SIGTIMER to be handled. */
++# define LIBC_SIGACTION 1
++
++# include <nptl/sysdeps/pthread/sigaction.c>
++
++int
++__sigaction (sig, act, oact)
++ int sig;
++ const struct sigaction *act;
++ struct sigaction *oact;
++{
++ if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0))
++ {
++ __set_errno (EINVAL);
++ return -1;
++ }
++
++ return __libc_sigaction (sig, act, oact);
++}
++libc_hidden_weak (__sigaction)
++weak_alias (__sigaction, sigaction)
++
++#else
++
++# include_next <sigaction.c>
++
++#endif /* LIBC_SIGACTION */
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/sigfillset.c libc/nptl/sysdeps/unix/sysv/linux/sigfillset.c
+--- libc/nptl/sysdeps/unix/sysv/linux/sigfillset.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/sigfillset.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,21 @@
++/* Copyright (C) 2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <nptl/pthreadP.h>
++
++#include <sysdeps/generic/sigfillset.c>
+diff -x CVS -rupN libc/nptl/sysdeps/unix/sysv/linux/sigprocmask.c libc/nptl/sysdeps/unix/sysv/linux/sigprocmask.c
+--- libc/nptl/sysdeps/unix/sysv/linux/sigprocmask.c 1970-01-01 01:00:00.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/sigprocmask.c 2005-01-23 19:35:29.000000000 +0100
+@@ -0,0 +1,20 @@
++/* Copyright (C) 1997,1998,1999,2000,2001,2003 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <nptl/pthreadP.h>
++#include <sysdeps/unix/sysv/linux/sigprocmask.c>
+diff -x CVS -rupN libc/nptl/unwind.c libc/nptl/unwind.c
+--- libc/nptl/unwind.c 2004-10-10 12:41:05.000000000 +0200
++++ libc/nptl/unwind.c 2005-01-23 19:35:29.000000000 +0100
+@@ -105,9 +105,11 @@ unwind_cleanup (_Unwind_Reason_Code reas
+ /* When we get here a C++ catch block didn't rethrow the object. We
+ cannot handle this case and therefore abort. */
+ # define STR_N_LEN(str) str, strlen (str)
++#if 0
+ INTERNAL_SYSCALL_DECL (err);
+ INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO,
+ STR_N_LEN ("FATAL: exception not rethrown\n"));
++#endif
+ abort ();
+ }
+