diff options
author | marcus <marcus> | 2005-01-23 21:30:40 +0000 |
---|---|---|
committer | marcus <marcus> | 2005-01-23 21:30:40 +0000 |
commit | f4ee3163dc1cc58ce13cdef64541ffe66f5a06a9 (patch) | |
tree | 71e7d8fbe453312d4760659ae62d3bfd2dd42e1f /libc | |
parent | b31c52a9116b976a6f919ec045462807851f5988 (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')
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 (); + } + |