Initial revision
authordrepper <drepper>
Tue, 26 Nov 2002 22:49:10 +0000 (22:49 +0000)
committerdrepper <drepper>
Tue, 26 Nov 2002 22:49:10 +0000 (22:49 +0000)
166 files changed:
nptl/ANNOUNCE [new file with mode: 0644]
nptl/Makeconfig [new file with mode: 0644]
nptl/Makefile [new file with mode: 0644]
nptl/TODO [new file with mode: 0644]
nptl/Versions [new file with mode: 0644]
nptl/allocatestack.c [new file with mode: 0644]
nptl/atomic.h [new file with mode: 0644]
nptl/configure [new file with mode: 0644]
nptl/descr.h [new file with mode: 0644]
nptl/flockfile.c [new file with mode: 0644]
nptl/init.c [new file with mode: 0644]
nptl/perf.c [new file with mode: 0644]
nptl/pt-longjmp.c [new file with mode: 0644]
nptl/pt-sigsuspend.c [new file with mode: 0644]
nptl/pthreadP.h [new file with mode: 0644]
nptl/pthread_attr_destroy.c [new file with mode: 0644]
nptl/pthread_attr_getdetachstate.c [new file with mode: 0644]
nptl/pthread_attr_getguardsize.c [new file with mode: 0644]
nptl/pthread_attr_getschedparam.c [new file with mode: 0644]
nptl/pthread_attr_getschedpolicy.c [new file with mode: 0644]
nptl/pthread_attr_getscope.c [new file with mode: 0644]
nptl/pthread_attr_getstack.c [new file with mode: 0644]
nptl/pthread_attr_getstackaddr.c [new file with mode: 0644]
nptl/pthread_attr_getstacksize.c [new file with mode: 0644]
nptl/pthread_attr_init.c [new file with mode: 0644]
nptl/pthread_attr_setdetachstate.c [new file with mode: 0644]
nptl/pthread_attr_setguardsize.c [new file with mode: 0644]
nptl/pthread_attr_setinheritsched.c [new file with mode: 0644]
nptl/pthread_attr_setschedparam.c [new file with mode: 0644]
nptl/pthread_attr_setschedpolicy.c [new file with mode: 0644]
nptl/pthread_attr_setscope.c [new file with mode: 0644]
nptl/pthread_attr_setstack.c [new file with mode: 0644]
nptl/pthread_attr_setstackaddr.c [new file with mode: 0644]
nptl/pthread_attr_setstacksize.c [new file with mode: 0644]
nptl/pthread_cancel.c [new file with mode: 0644]
nptl/pthread_cond_broadcast.c [new file with mode: 0644]
nptl/pthread_cond_destroy.c [new file with mode: 0644]
nptl/pthread_cond_init.c [new file with mode: 0644]
nptl/pthread_cond_signal.c [new file with mode: 0644]
nptl/pthread_cond_timedwait.c [new file with mode: 0644]
nptl/pthread_cond_wait.c [new file with mode: 0644]
nptl/pthread_condattr_destroy.c [new file with mode: 0644]
nptl/pthread_condattr_getpshared.c [new file with mode: 0644]
nptl/pthread_condattr_init.c [new file with mode: 0644]
nptl/pthread_condattr_setpshared.c [new file with mode: 0644]
nptl/pthread_create.c [new file with mode: 0644]
nptl/pthread_detach.c [new file with mode: 0644]
nptl/pthread_equal.c [new file with mode: 0644]
nptl/pthread_exit.c [new file with mode: 0644]
nptl/pthread_getattr_np.c [new file with mode: 0644]
nptl/pthread_getconcurrency.c [new file with mode: 0644]
nptl/pthread_getschedparam.c [new file with mode: 0644]
nptl/pthread_getspecific.c [new file with mode: 0644]
nptl/pthread_join.c [new file with mode: 0644]
nptl/pthread_key_create.c [new file with mode: 0644]
nptl/pthread_key_delete.c [new file with mode: 0644]
nptl/pthread_kill_other_threads.c [new file with mode: 0644]
nptl/pthread_mutex_destroy.c [new file with mode: 0644]
nptl/pthread_mutex_init.c [new file with mode: 0644]
nptl/pthread_mutex_lock.c [new file with mode: 0644]
nptl/pthread_mutex_timedlock.c [new file with mode: 0644]
nptl/pthread_mutex_trylock.c [new file with mode: 0644]
nptl/pthread_mutex_unlock.c [new file with mode: 0644]
nptl/pthread_mutexattr_destroy.c [new file with mode: 0644]
nptl/pthread_mutexattr_getpshared.c [new file with mode: 0644]
nptl/pthread_mutexattr_gettype.c [new file with mode: 0644]
nptl/pthread_mutexattr_init.c [new file with mode: 0644]
nptl/pthread_mutexattr_setpshared.c [new file with mode: 0644]
nptl/pthread_mutexattr_settype.c [new file with mode: 0644]
nptl/pthread_rwlock_destroy.c [new file with mode: 0644]
nptl/pthread_rwlock_init.c [new file with mode: 0644]
nptl/pthread_rwlock_tryrdlock.c [new file with mode: 0644]
nptl/pthread_rwlock_trywrlock.c [new file with mode: 0644]
nptl/pthread_rwlockattr_destroy.c [new file with mode: 0644]
nptl/pthread_rwlockattr_getkind_np.c [new file with mode: 0644]
nptl/pthread_rwlockattr_getpshared.c [new file with mode: 0644]
nptl/pthread_rwlockattr_init.c [new file with mode: 0644]
nptl/pthread_rwlockattr_setkind_np.c [new file with mode: 0644]
nptl/pthread_rwlockattr_setpshared.c [new file with mode: 0644]
nptl/pthread_self.c [new file with mode: 0644]
nptl/pthread_setcancelstate.c [new file with mode: 0644]
nptl/pthread_setcanceltype.c [new file with mode: 0644]
nptl/pthread_setconcurrency.c [new file with mode: 0644]
nptl/pthread_setschedparam.c [new file with mode: 0644]
nptl/pthread_setspecific.c [new file with mode: 0644]
nptl/pthread_testcancel.c [new file with mode: 0644]
nptl/pthread_timedjoin.c [new file with mode: 0644]
nptl/pthread_tryjoin.c [new file with mode: 0644]
nptl/res.c [new file with mode: 0644]
nptl/sem_close.c [new file with mode: 0644]
nptl/sem_destroy.c [new file with mode: 0644]
nptl/sem_getvalue.c [new file with mode: 0644]
nptl/sem_init.c [new file with mode: 0644]
nptl/sem_open.c [new file with mode: 0644]
nptl/sem_unlink.c [new file with mode: 0644]
nptl/semaphore.h [new file with mode: 0644]
nptl/semaphoreP.h [new file with mode: 0644]
nptl/shlib-versions [new file with mode: 0644]
nptl/sockperf.c [new file with mode: 0644]
nptl/sysdeps/i386/i686/pthread_spin_trylock.S [new file with mode: 0644]
nptl/sysdeps/i386/i686/tls.h [new file with mode: 0644]
nptl/sysdeps/i386/pthread_sigmask.c [new file with mode: 0644]
nptl/sysdeps/i386/pthread_spin_lock.c [new file with mode: 0644]
nptl/sysdeps/i386/pthread_spin_unlock.S [new file with mode: 0644]
nptl/sysdeps/i386/pthreaddef.h [new file with mode: 0644]
nptl/sysdeps/i386/tls.h [new file with mode: 0644]
nptl/tst-atfork1.c [new file with mode: 0644]
nptl/tst-barrier1.c [new file with mode: 0644]
nptl/tst-barrier2.c [new file with mode: 0644]
nptl/tst-barrier3.c [new file with mode: 0644]
nptl/tst-basic1.c [new file with mode: 0644]
nptl/tst-basic2.c [new file with mode: 0644]
nptl/tst-cancel1.c [new file with mode: 0644]
nptl/tst-cancel2.c [new file with mode: 0644]
nptl/tst-cancel3.c [new file with mode: 0644]
nptl/tst-cancel4.c [new file with mode: 0644]
nptl/tst-cond1.c [new file with mode: 0644]
nptl/tst-cond2.c [new file with mode: 0644]
nptl/tst-cond3.c [new file with mode: 0644]
nptl/tst-cond4.c [new file with mode: 0644]
nptl/tst-cond5.c [new file with mode: 0644]
nptl/tst-cond6.c [new file with mode: 0644]
nptl/tst-exec1.c [new file with mode: 0644]
nptl/tst-exec2.c [new file with mode: 0644]
nptl/tst-exec3.c [new file with mode: 0644]
nptl/tst-exit1.c [new file with mode: 0644]
nptl/tst-flock1.c [new file with mode: 0644]
nptl/tst-flock2.c [new file with mode: 0644]
nptl/tst-fork1.c [new file with mode: 0644]
nptl/tst-join1.c [new file with mode: 0644]
nptl/tst-join2.c [new file with mode: 0644]
nptl/tst-join3.c [new file with mode: 0644]
nptl/tst-key1.c [new file with mode: 0644]
nptl/tst-key2.c [new file with mode: 0644]
nptl/tst-key3.c [new file with mode: 0644]
nptl/tst-mutex1.c [new file with mode: 0644]
nptl/tst-mutex2.c [new file with mode: 0644]
nptl/tst-mutex3.c [new file with mode: 0644]
nptl/tst-mutex4.c [new file with mode: 0644]
nptl/tst-mutex5.c [new file with mode: 0644]
nptl/tst-mutex6.c [new file with mode: 0644]
nptl/tst-mutex7.c [new file with mode: 0644]
nptl/tst-once1.c [new file with mode: 0644]
nptl/tst-once2.c [new file with mode: 0644]
nptl/tst-rwlock1.c [new file with mode: 0644]
nptl/tst-rwlock2.c [new file with mode: 0644]
nptl/tst-rwlock3.c [new file with mode: 0644]
nptl/tst-rwlock4.c [new file with mode: 0644]
nptl/tst-rwlock5.c [new file with mode: 0644]
nptl/tst-rwlock6.c [new file with mode: 0644]
nptl/tst-rwlock7.c [new file with mode: 0644]
nptl/tst-sem1.c [new file with mode: 0644]
nptl/tst-sem2.c [new file with mode: 0644]
nptl/tst-sem3.c [new file with mode: 0644]
nptl/tst-sem4.c [new file with mode: 0644]
nptl/tst-sem5.c [new file with mode: 0644]
nptl/tst-signal1.c [new file with mode: 0644]
nptl/tst-signal2.c [new file with mode: 0644]
nptl/tst-signal3.c [new file with mode: 0644]
nptl/tst-spin1.c [new file with mode: 0644]
nptl/tst-spin2.c [new file with mode: 0644]
nptl/tst-spin3.c [new file with mode: 0644]
nptl/tst-stack1.c [new file with mode: 0644]
nptl/tst-tsd1.c [new file with mode: 0644]
nptl/tst-tsd2.c [new file with mode: 0644]
nptl/tst-unload.c [new file with mode: 0644]

diff --git a/nptl/ANNOUNCE b/nptl/ANNOUNCE
new file mode 100644 (file)
index 0000000..b63c657
--- /dev/null
@@ -0,0 +1,92 @@
+Now that the Linux kernel is once again able to run all the tests we
+have and since glibc 2.3 was released it was time for a new code drop.
+I've uploaded the second code drop for the Native POSIX Thread
+Library:
+
+  ftp://people.redhat.com/drepper/nptl/nptl-0.2.tar.bz2
+
+You need
+
+- the latest of Linus' kernel from BitKeeper (or 2.5.41 when it
+  is released);
+
+- glibc 2.3
+
+- the very latest in tools such as
+
+  + gcc either from the current development branch or the gcc 3.2
+    from Red Hat Linux 8;
+
+  + binutils preferrably from CVS, from H.J. Lu's latest release for
+    Linux, or from RHL 8.
+
+
+Compiling glibc should proceed smoothly.  But there are a number of
+tests which fail, mostly because some functionality is missing in
+glibc.  Ignore those errors.  It is only important that all tests in
+nptl/ are passing.  Run
+
+  make subdirs=nptl check
+
+to run all thread tests.
+
+
+This version features several improvements:
+
+- all APIs are now implemented;
+
+- fork handling has been improved; stacks in the child are freed;
+  atfork handlers are removed if they were registered from a module
+  which gets unloaded.
+
+- pthread_tryjoin_np and pthread_timedjoin_np are implemented
+
+- TSD handling corrected and optimized.
+
+- many more tests which also test the underlying kernel implementation.
+
+- the build infrastructure has been implemented so that the DSO and
+  archives are built in usable form and with correct named.
+
+- libthread_db has been implemented.  This is the library which is
+  needed by all program which need to get access to internals of
+  libpthread (mainly debuggers).
+
+- the CPU clock functions are implemented
+
+
+
+The white paper hasn't yet been updated.  It's still available at
+
+  http://people.redhat.com/drepper/nptl-design.pdf
+
+
+This release should be ready for some serious testing.  I know it is
+hard to compile which I why I'm looking into providing binary RPMs.
+They can be used on non-critical systems.  I'll only be able to
+provide binaries for RHL8 based systems, though, and the kernel still
+must be installed separately.
+
+
+The next steps will include:
+
+- write more tests and fix the bugs which are discovered this way
+
+- update the white paper
+
+- write and run more performance tests
+
+- port to IA-64
+
+
+Interested parties are once again invited to join the mailing we
+created:
+
+
+  phil-list@redhat.com
+
+Go to
+
+  https://listman.redhat.com/mailman/listinfo/phil-list
+
+to subscribe, unsubscribe, or review the archive.
diff --git a/nptl/Makeconfig b/nptl/Makeconfig
new file mode 100644 (file)
index 0000000..61015d2
--- /dev/null
@@ -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.
+
+# Makeconfig fragment for linuxthreads add-on.
+# This gets included at the end of the main glibc Makeconfig.
+
+have-thread-library = yes
+
+shared-thread-library = $(common-objpfx)nptl/libpthread.so \
+                       $(common-objpfx)nptl/libpthread_nonshared.a
+static-thread-library = $(common-objpfx)nptl/libpthread.a
+bounded-thread-library = $(common-objpfx)nptl/libpthread_b.a
+
+rpath-dirs += nptl
diff --git a/nptl/Makefile b/nptl/Makefile
new file mode 100644 (file)
index 0000000..e596803
--- /dev/null
@@ -0,0 +1,226 @@
+# Copyright (C) 2002 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+#
+#      Sub-makefile for NPTL portion of the library.
+#
+subdir := nptl
+
+nptl-version := $(shell sed -n 's/^.*$(subdir) \([0-9.]*\).*$$/\1/p' Banner)
+
+headers := pthread.h semaphore.h
+
+extra-libs := libpthread
+extra-libs-others := $(extra-libs)
+
+routines = alloca_cutoff forward
+shared-only-routines = forward
+
+libpthread-routines = init events \
+                     pthread_create pthread_exit pthread_detach \
+                     pthread_join pthread_tryjoin pthread_timedjoin \
+                     pthread_self pthread_equal pthread_yield \
+                     pthread_getconcurrency pthread_setconcurrency \
+                     pthread_getschedparam pthread_setschedparam \
+                     pthread_attr_init pthread_attr_destroy \
+                     pthread_attr_getdetachstate pthread_attr_setdetachstate \
+                     pthread_attr_getguardsize pthread_attr_setguardsize \
+                     pthread_attr_getschedparam pthread_attr_setschedparam \
+                     pthread_attr_getschedpolicy pthread_attr_setschedpolicy \
+                     pthread_attr_getinheritsched \
+                     pthread_attr_setinheritsched \
+                     pthread_attr_getscope pthread_attr_setscope \
+                     pthread_attr_getstackaddr pthread_attr_setstackaddr \
+                     pthread_attr_getstacksize pthread_attr_setstacksize \
+                     pthread_attr_getstack pthread_attr_setstack \
+                     pthread_getattr_np \
+                     pthread_mutex_init pthread_mutex_destroy \
+                     pthread_mutex_lock pthread_mutex_trylock \
+                     pthread_mutex_timedlock pthread_mutex_unlock \
+                     pthread_mutexattr_init pthread_mutexattr_destroy \
+                     pthread_mutexattr_getpshared \
+                     pthread_mutexattr_setpshared \
+                     pthread_mutexattr_gettype pthread_mutexattr_settype \
+                     pthread_rwlock_init pthread_rwlock_destroy \
+                     pthread_rwlock_tryrdlock pthread_rwlock_trywrlock \
+                     pthread_rwlockattr_init pthread_rwlockattr_destroy \
+                     pthread_rwlockattr_getpshared \
+                     pthread_rwlockattr_setpshared \
+                     pthread_rwlockattr_getkind_np \
+                     pthread_rwlockattr_setkind_np \
+                     pthread_cond_init pthread_cond_destroy \
+                     pthread_cond_wait pthread_cond_timedwait \
+                     pthread_cond_signal pthread_cond_broadcast \
+                     pthread_condattr_init pthread_condattr_destroy \
+                     pthread_condattr_getpshared pthread_condattr_setpshared \
+                     pthread_spin_init pthread_spin_destroy \
+                     pthread_spin_lock pthread_spin_trylock \
+                     pthread_spin_unlock \
+                     pthread_barrier_init pthread_barrier_destroy \
+                     pthread_barrier_wait \
+                     pthread_barrierattr_init pthread_barrierattr_destroy \
+                     pthread_barrierattr_getpshared \
+                     pthread_barrierattr_setpshared \
+                     pthread_key_create pthread_key_delete \
+                     pthread_getspecific pthread_setspecific \
+                     pthread_sigmask pthread_kill \
+                     pthread_cancel pthread_testcancel \
+                     pthread_setcancelstate pthread_setcanceltype \
+                     pthread_once \
+                     old_pthread_atfork\
+                     pthread_getcpuclockid \
+                     pthread_clock_gettime pthread_clock_settime \
+                     sem_init sem_destroy \
+                     sem_open sem_close sem_unlink \
+                     sem_getvalue \
+                     cleanup cleanup_defer \
+                     pt-longjmp \
+                     cancellation \
+                     lowlevellock lowlevelmutex lowlevelcond lowlevelrwlock \
+                     lowlevelsem \
+                     pt-vfork \
+                     pt-write pt-read pt-close pt-fcntl pt-accept pt-connect \
+                     pt-recv pt-recvfrom pt-recvmsg pt-send pt-sendmsg \
+                     pt-sendto pt-fsync pt-lseek pt-lseek64 pt-msync \
+                     pt-nanosleep pt-open pt-open64 pt-pause pt-pread \
+                     pt-pread64 pt-pwrite pt-pwrite64 pt-tcdrain pt-system \
+                     pt-wait pt-waitpid pt-readv pt-writev pt-creat \
+                     pt-msgrcv pt-msgsnd pt-poll pt-select pt-sigpause \
+                     pt-sigsuspend pt-sigwait pt-sigwaitinfo pt-waitid \
+                     pt-pselect pt-raise \
+                     flockfile ftrylockfile funlockfile \
+                     sigaction \
+                     herrno res pt-allocrtsig \
+                     pthread_kill_other_threads
+
+libpthread-nonshared = pthread_atfork
+
+
+tests = tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
+       tst-mutex7 \
+       tst-spin1 tst-spin2 tst-spin3 \
+       tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 \
+       tst-rwlock1 tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 \
+       tst-rwlock6 tst-rwlock7 \
+       tst-once1 tst-once2 \
+       tst-key1 tst-key2 tst-key3 \
+       tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 \
+       tst-barrier1 tst-barrier2 tst-barrier3 \
+       tst-basic1 tst-basic2 \
+       tst-join1 tst-join2 tst-join3 \
+       tst-tsd1 tst-tsd2 \
+       tst-fork1 \
+       tst-atfork1 \
+       tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 \
+       tst-flock1 tst-flock2 \
+       tst-signal1 tst-signal2 tst-signal3 \
+       tst-exec1 tst-exec2 tst-exec3 \
+       tst-exit1 \
+       tst-stack1 \
+       tst-unload
+
+LDFLAGS-pthread.so = -Wl,--enable-new-dtags,-z,nodelete,-z,initfirst
+
+
+include ../Makeconfig
+
+ifeq ($(build-shared),yes)
+others: $(objpfx)libpthread_nonshared.a
+endif
+
+$(objpfx)libpthread_nonshared.a: $(addprefix $(objpfx),$(addsuffix .os,$(libpthread-nonshared)))
+       $(AR) $(ARFLAGS) $@ $^
+
+ifeq ($(build-shared),yes)
+extra-objs += crti.o
+omit-deps += crti
+
+CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions
+endif
+
+include ../Rules
+
+# What we install as libc.so for programs to link against is in fact a
+# link script.  It contains references for the various libraries we need.
+# The libc.so object is not complete since some functions are only defined
+# in libc_nonshared.a.
+# We need to use absolute paths since otherwise local copies (if they exist)
+# of the files are taken by the linker.
+install: $(inst_libdir)/libpthread.so
+$(inst_libdir)/libpthread.so: $(objpfx)libpthread.so$(libpthread.so-version) \
+                             $(inst_libdir)/$(patsubst %,$(libtype.oS),\
+                                                       $(libprefix)pthread) \
+                             $(+force)
+       (echo '/* GNU ld script';\
+        echo '   Use the shared library, but some functions are only in';\
+        echo '   the static library, so try that secondarily.  */';\
+        echo 'GROUP ( $(slibdir)/libpthread.so$(libpthread.so-version)' \
+             '$(libdir)/$(patsubst %,$(libtype.oS),$(libprefix)pthread)'\
+             ')' \
+       ) > $@.new
+       mv -f $@.new $@
+$(inst_libdir)/libpthread_nonshared.a: $(objpfx)libpthread_nonshared.a
+       $(do-install)
+
+
+CFLAGS-tst-unload.c += -DPREFIX=\"$(objpfx)\"
+
+extra-B-pthread.so = -B$(common-objpfx)linuxthreads/
+$(objpfx)libpthread.so: $(objpfx)crti.o
+$(objpfx)libpthread.so: +preinit += $(objpfx)crti.o
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(objpfx)libpthread.so: $(common-objpfx)libc.so \
+                       $(common-objpfx)libc_nonshared.a
+
+# Make sure we link with the thread library.
+ifeq ($(build-shared),yes)
+$(addprefix $(objpfx), \
+  $(filter-out $(tests-static), \
+    $(tests) $(test-srcs))): $(objpfx)libpthread.so \
+                            $(objpfx)libpthread_nonshared.a
+$(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so
+else
+$(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
+endif
+
+ifeq ($(build-shared),yes)
+vpath pt-initfini.c $(full_config_sysdirs)
+
+$(objpfx)pt-initfini.s: pt-initfini.c
+       $(compile.c) -S $(CFLAGS-pt-initfini.s) -finhibit-size-directive \
+               $(patsubst -f%,-fno-%,$(exceptions)) -o $@
+
+# We only have one kind of startup code files.  Static binaries and
+# shared libraries are build using the PIC version.
+$(objpfx)crti.S: $(objpfx)pt-initfini.s
+       sed -n -e '1,/@HEADER_ENDS/p' \
+              -e '/@_.*_PROLOG_BEGINS/,/@_.*_PROLOG_ENDS/p' \
+              -e '/@TRAILER_BEGINS/,$$p' $< > $@
+
+$(objpfx)defs.h: $(objpfx)pt-initfini.s
+       sed -n -e '/@TESTS_BEGIN/,/@TESTS_END/p' $< | \
+               $(AWK) -f ../csu/defs.awk > $@
+
+$(objpfx)crti.o: $(objpfx)crti.S $(objpfx)defs.h
+       $(compile.S) -g0 $(ASFLAGS-.os) -o $@
+
+generated += crti.S defs.h pt-initfini.s
+endif
diff --git a/nptl/TODO b/nptl/TODO
new file mode 100644 (file)
index 0000000..09392b1
--- /dev/null
+++ b/nptl/TODO
@@ -0,0 +1,24 @@
+- we should probably extend pthread_mutexattr_t with a field to create a
+  single linked list of all instances.  This requires changing the
+  pthread_mutexattr_* functions.
+
+
+- a new attribute for mutexes: number of times we spin before calling
+sys_futex
+
+
+
+- in case a thread calls 'fork' the stacks of all the other threads in
+  the child process are currently list.  Instead they should be recovered
+  and added to the stack cache.  This can be done by adding another global
+  list (maybe one per cluster) which lists all running threads and which
+  is processed by the child branch of fork.  All the stacks are simply
+  added to the stack cache.
+
+
+
+- test with threaded process terminating and semadj (?) being applied
+  only after all threads are gone
+
+
+- raise sends the signal to calling thread or process?
diff --git a/nptl/Versions b/nptl/Versions
new file mode 100644 (file)
index 0000000..ce11c67
--- /dev/null
@@ -0,0 +1,205 @@
+libc {
+  GLIBC_2.0 {
+    pthread_attr_destroy;
+    pthread_attr_getdetachstate; pthread_attr_setdetachstate;
+    pthread_attr_getinheritsched; pthread_attr_setinheritsched;
+    pthread_attr_getschedparam; pthread_attr_setschedparam;
+    pthread_attr_getschedpolicy;  pthread_attr_setschedpolicy;
+    pthread_attr_getscope; pthread_attr_setscope;
+    pthread_condattr_destroy; pthread_condattr_init;
+    pthread_cond_broadcast; pthread_cond_destroy;
+    pthread_cond_init; pthread_cond_signal; pthread_cond_wait;
+    pthread_equal; pthread_exit;
+    pthread_getschedparam; pthread_setschedparam;
+    pthread_mutex_destroy; pthread_mutex_init;
+    pthread_mutex_lock; pthread_mutex_unlock;
+    pthread_self;
+    pthread_setcancelstate; pthread_setcanceltype;
+  }
+  GLIBC_2.1 {
+    pthread_attr_init;
+  }
+}
+
+libpthread {
+  GLIBC_2.0 {
+    pthread_create; pthread_join; pthread_self; pthread_equal;
+    pthread_exit; pthread_detach;
+
+    pthread_getschedparam; pthread_setschedparam;
+
+    pthread_attr_init; pthread_attr_destroy;
+    pthread_attr_getdetachstate; pthread_attr_setdetachstate;
+    pthread_attr_getschedparam; pthread_attr_setschedparam;
+    pthread_attr_getschedpolicy; pthread_attr_setschedpolicy;
+    pthread_attr_getinheritsched; pthread_attr_setinheritsched;
+    pthread_attr_getscope; pthread_attr_setscope;
+
+    pthread_mutex_init; pthread_mutex_destroy;
+    pthread_mutex_lock; pthread_mutex_trylock; pthread_mutex_unlock;
+
+    pthread_mutexattr_init; pthread_mutexattr_destroy;
+
+    pthread_cond_init; pthread_cond_destroy;
+    pthread_cond_wait; pthread_cond_timedwait;
+    pthread_cond_signal; pthread_cond_broadcast;
+
+    pthread_condattr_destroy; pthread_condattr_init;
+
+    pthread_cancel; pthread_testcancel;
+    pthread_setcancelstate; pthread_setcanceltype;
+
+    pthread_sigmask; pthread_kill;
+
+    pthread_key_create; pthread_key_delete;
+    pthread_getspecific; pthread_setspecific;
+
+    pthread_once;
+
+    pthread_atfork;
+
+    flockfile; funlockfile; ftrylockfile;
+
+    # Non-standard POSIX1.x functions.
+    pthread_mutexattr_getkind_np; pthread_mutexattr_setkind_np;
+
+    # Protected names for functions used in other shared objects.
+    __pthread_mutex_init; __pthread_mutex_destroy;
+    __pthread_mutex_lock; __pthread_mutex_trylock; __pthread_mutex_unlock;
+    __pthread_mutexattr_init; __pthread_mutexattr_destroy;
+    __pthread_mutexattr_settype;
+    __pthread_key_create; __pthread_getspecific; __pthread_setspecific;
+    __pthread_once; __pthread_atfork;
+    _IO_flockfile; _IO_ftrylockfile; _IO_funlockfile;
+
+    # Hidden entry point (through macros).
+    #_pthread_cleanup_pop; _pthread_cleanup_pop_restore; _pthread_cleanup_push;
+    #_pthread_cleanup_push_defer;
+
+    # Semaphores.
+    sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
+
+    # Special fork handling.
+    fork; __fork; vfork;
+
+    # Cancellation points.
+    close; __close; fcntl; __fcntl; read; __read; write; __write; accept;
+    connect; __connect; recv; recvfrom; recvmsg; send; __send; sendmsg; sendto;
+    fsync; lseek; __lseek; msync; nanosleep; open; __open; pause; tcdrain;
+    system; wait; __wait; waitpid;
+
+    # Hidden entry point (through macros).
+    _pthread_cleanup_push; _pthread_cleanup_pop;
+    _pthread_cleanup_push_defer; _pthread_cleanup_pop_restore;
+
+    pthread_kill_other_threads_np;
+
+    # The error functions.
+    __errno_location; __h_errno_location;
+
+    # Functions which previously have been overwritten.
+    sigwait; sigaction; __sigaction; _exit; _Exit; longjmp; siglongjmp;
+    raise;
+  }
+
+  GLIBC_2.1 {
+    pthread_create;
+    pthread_attr_init;
+
+    pthread_attr_getguardsize; pthread_attr_setguardsize;
+    pthread_attr_getstackaddr; pthread_attr_setstackaddr;
+    pthread_attr_getstacksize; pthread_attr_setstacksize;
+
+    pthread_mutexattr_gettype; pthread_mutexattr_settype;
+
+    pthread_rwlock_init; pthread_rwlock_destroy;
+    pthread_rwlock_rdlock; pthread_rwlock_wrlock; pthread_rwlock_unlock;
+    pthread_rwlock_tryrdlock; pthread_rwlock_trywrlock;
+
+    __pthread_rwlock_init; __pthread_rwlock_destroy;
+    __pthread_rwlock_rdlock; __pthread_rwlock_wrlock; __pthread_rwlock_unlock;
+    __pthread_rwlock_tryrdlock; __pthread_rwlock_trywrlock;
+
+    pthread_rwlockattr_init; pthread_rwlockattr_destroy;
+    pthread_rwlockattr_getpshared; pthread_rwlockattr_setpshared;
+    pthread_rwlockattr_getkind_np; pthread_rwlockattr_setkind_np;
+
+    pthread_getconcurrency; pthread_setconcurrency;
+
+    # Semaphores.
+    sem_destroy; sem_getvalue; sem_init; sem_post; sem_trywait; sem_wait;
+
+    __libc_current_sigrtmin; __libc_current_sigrtmax;
+    __libc_allocate_rtsig;
+  }
+
+  GLIBC_2.1.1 {
+    sem_close; sem_open; sem_unlink;
+  }
+
+  GLIBC_2.1.2 {
+    __vfork;
+  }
+
+  GLIBC_2.2 {
+    pthread_mutexattr_getpshared; pthread_mutexattr_setpshared;
+
+    pthread_condattr_getpshared; pthread_condattr_setpshared;
+
+    # New functions from IEEE Std. 1003.1-2001.
+    pthread_mutex_timedlock;
+
+    pthread_rwlock_timedrdlock; pthread_rwlock_timedwrlock;
+
+    pthread_attr_getstack; pthread_attr_setstack;
+
+    pthread_spin_destroy; pthread_spin_init; pthread_spin_lock;
+    pthread_spin_trylock; pthread_spin_unlock;
+
+    pthread_barrier_init; pthread_barrier_destroy; pthread_barrier_wait;
+    pthread_barrierattr_destroy; pthread_barrierattr_init;
+    pthread_barrierattr_getpshared; pthread_barrierattr_setpshared;
+
+    sem_timedwait;
+
+    pthread_yield;
+
+    pthread_getcpuclockid;
+
+    # Cancellation points.
+    lseek64; open64; __open64; pread; pread64; __pread64; pwrite; pwrite64;
+    __pwrite64;
+
+    # Names used internally.
+    __pthread_rwlock_init; __pthread_rwlock_destroy;
+    __pthread_rwlock_rdlock; __pthread_rwlock_tryrdlock;
+    __pthread_rwlock_wrlock; __pthread_rwlock_trywrlock;
+    __pthread_rwlock_unlock;
+
+    __res_state;
+  }
+
+  GLIBC_2.2.3 {
+    # Extensions.
+    pthread_getattr_np;
+  }
+
+  GLIBC_2.2.6 {
+    # Cancellation wrapper
+    __nanosleep;
+  }
+
+  # XXX Adjust number for final release.
+  GLIBC_2.3.1 {
+    # Proposed API extensions.
+    pthread_tryjoin_np; pthread_timedjoin_np;
+
+    creat; poll; pselect; readv; select; sigpause; sigsuspend; sigwait;
+    sigwaitinfo; waitid; writev;
+  }
+
+  GLIBC_PRIVATE {
+    __pthread_initialize_minimal; __pthread_cleanup_upto;
+    __pthread_clock_gettime; __pthread_clock_settime;
+  }
+}
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
new file mode 100644 (file)
index 0000000..2aaaaec
--- /dev/null
@@ -0,0 +1,507 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <tls.h>
+
+
+
+
+/* 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
+
+
+/* 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
+
+
+
+
+/* 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.  */
+LIST_HEAD (__stack_user);
+
+/* Number of threads running.  */
+static unsigned int nptl_nthreads = 1;
+
+
+/* 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, header.data.list);
+      if (FREE_P (curr) && curr->stackblock_size >= size)
+       {
+         if (curr->stackblock_size == size)
+           {
+             result = curr;
+             break;
+           }
+
+         if (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->header.data.list);
+
+  /* And add to the list of stacks in use.  */
+  list_add (&result->header.data.list, &stack_used);
+
+  /* One more thread.  */
+  ++nptl_nthreads;
+
+  /* And decrease the cache size.  */
+  stack_cache_actsize -= result->stackblock_size;
+
+  /* Release the lock early.  */
+  lll_unlock (stack_cache_lock);
+
+
+  *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 (result);
+  memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+
+  /* Re-initialize the TLS.  */
+  return _dl_allocate_tls_init (result);
+}
+
+
+/* Add a stack frame which is not used anymore to the stack.  Must be
+   called with the cache lock held.  */
+static void
+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->header.data.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, header.data.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 (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
+allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
+               void **stack)
+{
+  struct pthread *pd;
+  size_t size;
+  size_t pagesize = __sysconf (_SC_PAGESIZE);
+
+  assert (attr != NULL);
+  assert (powerof2 (pagesize));
+  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.  */
+      adj = ((uintptr_t) attr->stackaddr) & (__static_tls_align - 1);
+      assert (size > adj);
+
+      /* 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.  */
+      pd = (struct pthread *) (((uintptr_t) attr->stackaddr - adj)
+                              & ~(__alignof (struct pthread) - 1)) - 1;
+
+      /* The user provided stack memory need not be cleared.  */
+      memset (pd, '\0', sizeof (struct pthread));
+
+      /* The first TSD block is included in the TCB.  */
+      pd->specific[0] = pd->specific_1stblock;
+
+      /* Initialize the lock.  */
+      pd->lock = LLL_LOCK_INITIALIZER;
+
+      /* Remember the stack-related values.  Signal that this stack
+        must not be put into the stack cache.  */
+      pd->stackblock = (char *) attr->stackaddr - size;
+      pd->stackblock_size = size - adj;
+
+      /* This is a user-provided stack.  */
+      pd->user_stack = true;
+
+      /* Allocate the DTV for this thread.  */
+      if (_dl_allocate_tls (pd) == NULL)
+       /* Something went wrong.  */
+       return errno;
+
+
+      lll_lock (stack_cache_lock);
+
+      /* And add to the list of stacks in use.  */
+      list_add (&pd->header.data.list, &__stack_user);
+
+      /* One more thread.  */
+      ++nptl_nthreads;
+
+      lll_unlock (stack_cache_lock);
+    }
+  else
+    {
+      /* Allocate some anonymous memory.  If possible use the
+        cache.  */
+      size_t guardsize;
+      size_t reqsize;
+      void *mem;
+
+      /* Adjust the stack size for alignment.  */
+      size &= ~(__static_tls_align - 1);
+      assert (size != 0);
+
+      /* Make sure the size of the stack is enough for the guard and
+        eventually the thread descriptor.  */
+      guardsize = (attr->guardsize + pagesize - 1) & ~(pagesize - 1);
+      if (__builtin_expect (size < (guardsize + __static_tls_size
+                                   + MINIMAL_REST_STACK), 0))
+       /* The stack is too small (or the guard too large).  */
+       return EINVAL;
+
+      reqsize = size;
+      pd = get_cached_stack (&size, &mem);
+      if (pd == NULL)
+       {
+         mem = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+         if (__builtin_expect (mem == MAP_FAILED, 0))
+           return errno;
+
+         /* 'size' is guaranteed to be greater than zero.  So we can
+            never get a NULL pointer back from MMAP.  */
+         assert (mem != NULL);
+
+         /* Place the thread descriptor at the end of the stack.  */
+         pd = (struct pthread *) ((char *) mem + size) - 1;
+
+         /* 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;
+
+         /* Initialize the lock.  */
+         pd->lock = LLL_LOCK_INITIALIZER;
+
+         /* Allocate the DTV for this thread.  */
+         if (_dl_allocate_tls (pd) == NULL)
+           {
+             /* Something went wrong.  */
+             int err = errno;
+
+             /* Free the stack memory we just allocated.  */
+             munmap (mem, size);
+
+             return err;
+           }
+
+
+         lll_lock (stack_cache_lock);
+
+         /* And add to the list of stacks in use.  */
+         list_add (&pd->header.data.list, &stack_used);
+
+         /* One more thread.  */
+         ++nptl_nthreads;
+
+         lll_unlock (stack_cache_lock);
+
+
+         /* 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))
+       {
+         if (mprotect (mem, guardsize, PROT_NONE) != 0)
+           {
+             int err;
+           mprot_error:
+             err = errno;
+
+             lll_lock (stack_cache_lock);
+
+             /* Remove the thread from the list.  */
+             list_del (&pd->header.data.list);
+
+             /* The thread is gone.  */
+             --nptl_nthreads;
+
+             lll_unlock (stack_cache_lock);
+
+             /* Free the 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.  */
+         if (mprotect ((char *) mem + guardsize,
+                       pd->guardsize - guardsize,
+                       PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
+           goto mprot_error;
+
+         pd->guardsize = guardsize;
+       }
+    }
+
+  /* We place the thread descriptor at the end of the stack.  */
+  *pdp = pd;
+
+#if TLS_TCB_AT_TP
+  /* The stack begin before the TCB and the static TLS block.  */
+  *stack = ((char *) (pd + 1) - __static_tls_size);
+#else
+# error "Implement me"
+#endif
+
+  return 0;
+}
+
+/* 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)
+
+
+void
+__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->header.data.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 (pd, false);
+
+  /* One less thread.  */
+  --nptl_nthreads;
+
+  lll_unlock (stack_cache_lock);
+}
+
+
+/* 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, header.data.list);
+      if (curp != self)
+       {
+         /* This marks the stack as free.  */
+         curp->tid = 0;
+
+         /* 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->header.data.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->header.data.list, &__stack_user);
+  else
+    list_add (&self->header.data.list, &stack_used);
+
+  /* There is one thread running.  */
+  nptl_nthreads = 1;
+
+  /* Initialize the lock.  */
+  stack_cache_lock = LLL_LOCK_INITIALIZER;
+}
diff --git a/nptl/atomic.h b/nptl/atomic.h
new file mode 100644 (file)
index 0000000..927e0fe
--- /dev/null
@@ -0,0 +1,109 @@
+/* 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 _ATOMIC_H
+#define _ATOMIC_H      1
+
+#include <stdlib.h>
+
+#include <bits/atomic.h>
+
+
+#ifndef atomic_compare_and_exchange_acq
+# define atomic_compare_and_exchange_acq(mem, newval, oldval) \
+  ({ __typeof (__arch_compare_and_exchange_8_acq (mem, newval, oldval))              \
+        __result;                                                            \
+     if (sizeof (*mem) == 1)                                                 \
+       __result = __arch_compare_and_exchange_8_acq (mem, newval, oldval);    \
+     else if (sizeof (*mem) == 2)                                            \
+       __result = __arch_compare_and_exchange_16_acq (mem, newval, oldval);   \
+     else if (sizeof (*mem) == 4)                                            \
+       __result = __arch_compare_and_exchange_32_acq (mem, newval, oldval);   \
+     else if (sizeof (*mem) == 8)                                            \
+       __result = __arch_compare_and_exchange_64_acq (mem, newval, oldval);   \
+     else                                                                    \
+       abort ();                                                             \
+     __result; })
+#endif
+
+
+#ifndef atomic_compare_and_exchange_rel
+# define atomic_compare_and_exchange_rel(mem, oldval, newval) \
+  compare_and_exchange_acq (mem, oldval, newval)
+#endif
+
+
+#ifndef atomic_exchange_and_add
+# define atomic_exchange_and_add(mem, value) \
+  ({ __typeof (*mem) __oldval;                                               \
+     __typeof (mem) __memp = (mem);                                          \
+     __typeof (*mem) __value = (value);                                              \
+                                                                             \
+     do                                                                              \
+       __oldval = (*__memp);                                                 \
+     while (compare_and_exchange_acq (__memp, __oldval + __value, __oldval)); \
+                                                                             \
+     __value; })
+#endif
+
+
+#ifndef atomic_add
+# define atomic_add(mem, value) (void) exchange_and_add (mem, value)
+#endif
+
+
+#ifndef atomic_increment
+# define atomic_increment(mem) atomic_add (mem, 1)
+#endif
+
+
+#ifndef atomic_decrement
+# define atomic_decrement(mem) atomic_add (mem, -1)
+#endif
+
+
+#ifndef atomic_set_bit
+# define atomic_set_bit(mem, bit) \
+  (void) ({ __typeof (mem) __memp = (mem);                                   \
+           while (1)                                                         \
+             {                                                               \
+               __typeof (*mem) __oldval = *__memp;                           \
+                                                                             \
+               if (compare_and_exchange_acq (__memp, __oldval | 1 << bit,    \
+                                             __oldval) == 0)                 \
+                 break;                                                      \
+             }})
+#endif
+
+
+#ifndef atomic_full_barrier
+# define full_barrier() __asm ("" ::: "memory")
+#endif
+
+
+#ifndef atomic_read_barrier
+# define read_barrier() full_barrier()
+#endif
+
+
+#ifndef atomic_write_barrier
+# define write_barrier() full_barrier()
+#endif
+
+#endif /* atomic.h */
diff --git a/nptl/configure b/nptl/configure
new file mode 100644 (file)
index 0000000..3eafc93
--- /dev/null
@@ -0,0 +1,5 @@
+# This is only to keep the GNU C library configure mechanism happy.
+#
+# Perhaps some day we need a real configuration script for different
+# kernel versions or so.
+exit 0
diff --git a/nptl/descr.h b/nptl/descr.h
new file mode 100644 (file)
index 0000000..f3a9620
--- /dev/null
@@ -0,0 +1,179 @@
+/* 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 _DESCR_H
+#define _DESCR_H       1
+
+#include <limits.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <hp-timing.h>
+#include <list.h>
+#include <lowlevellock.h>
+#include <pthreaddef.h>
+#include "../nptl_db/thread_db.h"
+
+
+#ifndef TCB_ALIGNMENT
+# define TCB_ALIGNMENT sizeof (double)
+#endif
+
+
+/* We keep thread specific data in a special data structure, a two-level
+   array.  The top-level array contains pointers to dynamically allocated
+   arrays of a certain number of data pointers.  So we can implement a
+   sparse array.  Each dynamic second-level array has
+        PTHREAD_KEY_2NDLEVEL_SIZE
+   entries.  This value shouldn't be too large.  */
+#define PTHREAD_KEY_2NDLEVEL_SIZE       32
+
+/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE
+   keys in each subarray.  */
+#define PTHREAD_KEY_1STLEVEL_SIZE \
+  ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \
+   / PTHREAD_KEY_2NDLEVEL_SIZE)
+
+
+/* Thread descriptor data structure.  */
+struct pthread
+{
+  /* XXX Remove this union for IA-64 style TLS module */
+  union
+  {
+    struct
+    {
+      void *tcb;                /* Pointer to the TCB.  This is not always
+                                   the address of this thread descriptor.  */
+      union dtv *dtvp;
+      struct pthread *self;       /* Pointer to this structure */
+      list_t list;
+    } data;
+    void *__padding[16];
+  } header;
+
+  /* Two-level array for the thread-specific data.  */
+  struct pthread_key_data
+  {
+    /* Sequence number.  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;
+
+    /* Data pointer.  */
+    void *data;
+  } *specific[PTHREAD_KEY_1STLEVEL_SIZE];
+  /* We allocate one block of references here.  This should be enough
+     to avoid allocating any memory dynamically for most applications.  */
+  struct pthread_key_data specific_1stblock[PTHREAD_KEY_2NDLEVEL_SIZE];
+  /* Flag which is set when specific data is set.  */
+  bool specific_used;
+
+  /* True if the user provided the stack.  */
+  bool user_stack;
+
+  /* True if events must be reported.  */
+  bool report_events;
+
+  /* Lock to syncronize access to the descriptor.  */
+  lll_lock_t lock;
+
+#if HP_TIMING_AVAIL
+  /* Offset of the CPU clock at start thread start time.  */
+  hp_timing_t cpuclock_offset;
+#endif
+
+  /* If the thread waits to join another one the ID of the latter is
+     stored here.
+
+     In case a thread is detached this field contains a pointer of the
+     TCB if the thread itself.  This is something which cannot happen
+     in normal operation.  */
+  struct pthread *joinid;
+  /* Check whether a thread is detached.  */
+#define IS_DETACHED(pd) ((pd)->joinid == (pd))
+
+  /* List of cleanup buffers.  */
+  struct _pthread_cleanup_buffer *cleanup;
+  /* Flags determining processing of cancellation.  */
+  int cancelhandling;
+  /* Bit set if cancellation is disabled.  */
+#define CANCELSTATE_BIT                0
+#define CANCELSTATE_BITMASK    0x01
+  /* Bit set if asynchronous cancellation mode is selected.  */
+#define CANCELTYPE_BIT         1
+#define CANCELTYPE_BITMASK     0x02
+  /* Bit set if canceled.  */
+#define CANCELED_BIT           2
+#define CANCELED_BITMASK       0x04
+  /* Bit set if thread is exiting.  */
+#define EXITING_BIT            3
+#define EXITING_BITMASK                0x08
+  /* Bit set if thread terminated and TCB is freed.  */
+#define TERMINATED_BIT         4
+#define TERMINATED_BITMASK     0x10
+  /* Mask for the rest.  Helps the compiler to optimize.  */
+#define CANCEL_RESTMASK                0xffffffe0
+
+#define CANCEL_ENABLED_AND_CANCELED(value) \
+  (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK              \
+              | CANCEL_RESTMASK | TERMINATED_BITMASK)) == CANCELED_BITMASK)
+#define CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS(value) \
+  (((value) & (CANCELSTATE_BITMASK | CANCELTYPE_BITMASK | CANCELED_BITMASK    \
+              | EXITING_BITMASK | CANCEL_RESTMASK | TERMINATED_BITMASK))     \
+   == (CANCELTYPE_BITMASK | CANCELED_BITMASK))
+  /* Setjmp buffer to be used if try/finally is not available.  */
+  sigjmp_buf cancelbuf;
+#define HAVE_CANCELBUF 1
+
+  /* Thread ID - which is also a 'is this thread descriptor (and
+     therefore stack) used' flag.  */
+  pid_t tid;
+
+  /* Flags.  Including those copied from the thread attribute.  */
+  int flags;
+
+  /* The result of the thread function.  */
+  void *result;
+
+  /* Scheduling parameters for the new thread.  */
+  struct sched_param schedparam;
+  int schedpolicy;
+
+  /* Start position of the code to be executed and the argument passed
+     to the function.  */
+  void *(*start_routine) (void *);
+  void *arg;
+
+  /* Debug state.  */
+  td_eventbuf_t eventbuf;
+  /* Next descriptor with a pending event.  */
+  struct pthread *nextevent;
+
+  /* If nonzero pointer to area allocated for the stack and its
+     size.  */
+  void *stackblock;
+  size_t stackblock_size;
+  /* Size of the included guard area.  */
+  size_t guardsize;
+} __attribute ((aligned (TCB_ALIGNMENT)));
+
+
+#endif /* descr.h */
diff --git a/nptl/flockfile.c b/nptl/flockfile.c
new file mode 100644 (file)
index 0000000..a82059f
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <libio.h>
+
+
+void
+flockfile (stream)
+     FILE *stream;
+{
+  pthread_mutex_lock (stream->_lock);
+}
+strong_alias (flockfile, _IO_flockfile)
diff --git a/nptl/init.c b/nptl/init.c
new file mode 100644 (file)
index 0000000..395ede7
--- /dev/null
@@ -0,0 +1,172 @@
+/* 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 <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>
+
+
+/* XXX For the time being...  */
+#define __NR_set_tid_address   258
+
+
+/* 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;
+
+/* Version of the library, used in libthread_db to detect mismatches.  */
+static const char nptl_version[] = VERSION;
+
+
+#if defined USE_TLS && !defined SHARED
+extern void __libc_setup_tls (size_t tcbsize, size_t tcbalign);
+#endif
+
+
+/* For asynchronous cancellation we use a signal.  This is the handler.  */
+static void
+sigcancel_handler (int sig __attribute ((unused)))
+{
+  struct pthread *self = THREAD_SELF;
+
+  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 oldval = THREAD_GETMEM (self, cancelhandling);
+      int newval = oldval | CANCELED_BITMASK;
+
+      if (oldval == newval || (oldval & EXITING_BITMASK) != 0)
+       /* Already canceled or exiting.  */
+       break;
+
+      if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+                                          oldval) == 0)
+       {
+         /* Set the return value.  */
+         THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+
+         /* Make sure asynchronous cancellation is still enabled.  */
+         if ((newval & CANCELTYPE_BITMASK) != 0)
+           {
+             /* The thread is exiting now.  */
+             atomic_bit_set (&self->cancelhandling, EXITING_BIT);
+
+             /* Run the registered destructors and terminate the
+                thread.  */
+             __do_cancel (CURRENT_STACK_FRAME);
+           }
+
+         break;
+       }
+    }
+}
+
+
+
+void
+#ifdef SHARED
+__attribute ((constructor))
+#endif
+__pthread_initialize_minimal (void)
+{
+  struct sigaction sa;
+  struct rlimit limit;
+#ifdef USE_TLS
+  struct pthread *pd;
+#endif
+
+#ifndef SHARED
+  /* Unlike in the dynamically linked case the dynamic linker has not
+     taken care of initializing the TLS data structures.  */
+  __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);
+#endif
+
+  /* Minimal initialization of the thread descriptor.  */
+  pd = THREAD_SELF;
+  pd->tid = INTERNAL_SYSCALL (set_tid_address, 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
+
+  /* Add the main thread to the list of all running threads.  No need
+     to get the lock we are alone so far.  */
+  list_add (&pd->header.data.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.  */
+  sa.sa_handler = sigcancel_handler;
+  sa.sa_flags = 0;
+
+  /* Avoid another cancellation signal when we process one.  */
+  sigemptyset (&sa.sa_mask);
+  sigaddset (&sa.sa_mask, SIGCANCEL);
+
+  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
+
+
+  /* Determine the default allowed stack size.  This is the size used
+     in case the user does not specify one.  */
+  if (getrlimit (RLIMIT_STACK, &limit) != 0
+      || limit.rlim_cur == RLIM_INFINITY)
+    /* The system limit is not usable.  Use an architecture-specific
+       default.  */
+    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
+
+#ifdef NEED_SEPARATE_REGISTER_STACK
+  __default_stacksize = MAX (limit.rlim_cur / 2, PTHREAD_STACK_MIN);
+#else
+  __default_stacksize = MAX (limit.rlim_cur, PTHREAD_STACK_MIN);
+#endif
+  /* The maximum page size better should be a multiple of the page
+     size.  */
+  assert (__default_stacksize % __sysconf (_SC_PAGESIZE) == 0);
+
+  /* Get the size of the static and alignment requirements for the TLS
+     block.  */
+  _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_size = roundup (__static_tls_size, __static_tls_align);
+
+  /* Register the fork generation counter with the libc.  */
+  __register_pthread_fork_handler (&__fork_generation, __reclaim_stacks);
+}
diff --git a/nptl/perf.c b/nptl/perf.c
new file mode 100644 (file)
index 0000000..e94ccf8
--- /dev/null
@@ -0,0 +1,749 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _GNU_SOURCE    1
+#include <argp.h>
+#include <error.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#ifndef MAX_THREADS
+# define MAX_THREADS           100000
+#endif
+#ifndef DEFAULT_THREADS
+# define DEFAULT_THREADS       50
+#endif
+
+
+#define OPT_TO_THREAD          300
+#define OPT_TO_PROCESS         301
+#define OPT_SYNC_SIGNAL                302
+#define OPT_SYNC_JOIN          303
+#define OPT_TOPLEVEL           304
+
+
+static const struct argp_option options[] =
+  {
+    { NULL, 0, NULL, 0, "\
+This is a test for threads so we allow ther user to selection the number of \
+threads which are used at any one time.  Independently the total number of \
+rounds can be selected.  This is the total number of threads which will have \
+run when the process terminates:" },
+    { "threads", 't', "NUMBER", 0, "Number of threads used at once" },
+    { "starts", 's', "NUMBER", 0, "Total number of working threads" },
+    { "toplevel", OPT_TOPLEVEL, "NUMBER", 0,
+      "Number of toplevel threads which start the other threads; this \
+implies --sync-join" },
+
+    { NULL, 0, NULL, 0, "\
+Each thread can do one of two things: sleep or do work.  The latter is 100% \
+CPU bound.  The work load is the probability a thread does work.  All values \
+from zero to 100 (inclusive) are valid.  How often each thread repeats this \
+can be determined by the number of rounds.  The work cost determines how long \
+each work session (not sleeping) takes.  If it is zero a thread would \
+effectively nothing.  By setting the number of rounds to zero the thread \
+does no work at all and pure thread creation times can be measured." },
+    { "workload", 'w', "PERCENT", 0, "Percentage of time spent working" },
+    { "workcost", 'c', "NUMBER", 0,
+      "Factor in the cost of each round of working" },
+    { "rounds", 'r', "NUMBER", 0, "Number of rounds each thread runs" },
+
+    { NULL, 0, NULL, 0, "\
+There are a number of different methods how thread creation can be \
+synchronized.  Synchronization is necessary since the number of concurrently \
+running threads is limited." },
+    { "sync-signal", OPT_SYNC_SIGNAL, NULL, 0,
+      "Synchronize using a signal (default)" },
+    { "sync-join", OPT_SYNC_JOIN, NULL, 0, "Synchronize using pthread_join" },
+
+    { NULL, 0, NULL, 0, "\
+One parameter for each threads execution is the size of the stack.  If this \
+parameter is not used the system's default stack size is used.  If many \
+threads are used the stack size should be chosen quite small." },
+    { "stacksize", 'S', "BYTES", 0, "Size of threads stack" },
+    { "guardsize", 'g', "BYTES", 0,
+      "Size of stack guard area; must fit into the stack" },
+
+    { NULL, 0, NULL, 0, "Signal options:" },
+    { "to-thread", OPT_TO_THREAD, NULL, 0, "Send signal to main thread" },
+    { "to-process", OPT_TO_PROCESS, NULL, 0,
+      "Send signal to process (default)" },
+
+    { NULL, 0, NULL, 0, "Administrative options:" },
+    { "progress", 'p', NULL, 0, "Show signs of progress" },
+    { "timing", 'T', NULL, 0,
+      "Measure time from startup to the last thread finishing" },
+    { NULL, 0, NULL, 0, NULL }
+  };
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt
+};
+
+
+static unsigned long int threads = DEFAULT_THREADS;
+static unsigned long int workload = 75;
+static unsigned long int workcost = 20;
+static unsigned long int rounds = 10;
+static long int starts = 5000;
+static unsigned long int stacksize;
+static long int guardsize = -1;
+static bool progress;
+static bool timing;
+static bool to_thread;
+static unsigned long int toplevel = 1;
+
+
+static long int running;
+static pthread_mutex_t running_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static pid_t pid;
+static pthread_t tmain;
+
+static clockid_t cl;
+static struct timespec start_time;
+
+
+static pthread_mutex_t sum_mutex = PTHREAD_MUTEX_INITIALIZER;
+unsigned int sum;
+
+static enum
+  {
+    sync_signal,
+    sync_join
+  }
+sync_method;
+
+
+/* We use 64bit values for the times.  */
+typedef unsigned long long int hp_timing_t;
+
+
+/* Attributes for all created threads.  */
+static pthread_attr_t attr;
+
+
+static void *
+work (void *arg)
+{
+  unsigned long int i;
+  unsigned int state = (unsigned long int) arg;
+
+  for (i = 0; i < rounds; ++i)
+    {
+      /* Determine what to do.  */
+      unsigned int rnum;
+
+      /* Equal distribution.  */
+      do
+       rnum = rand_r (&state);
+      while (rnum >= UINT_MAX - (UINT_MAX % 100));
+
+      rnum %= 100;
+
+      if (rnum < workload)
+       {
+         int j;
+         int a[4] = { i, rnum, i + rnum, rnum - i };
+
+         if (progress)
+           write (STDERR_FILENO, "c", 1);
+
+         for (j = 0; j < workcost; ++j)
+           {
+             a[0] += a[3] >> 12;
+             a[1] += a[2] >> 20;
+             a[2] += a[1] ^ 0x3423423;
+             a[3] += a[0] - a[1];
+           }
+
+         pthread_mutex_lock (&sum_mutex);
+         sum += a[0] + a[1] + a[2] + a[3];
+         pthread_mutex_unlock (&sum_mutex);
+       }
+      else
+       {
+         /* Just sleep.  */
+         struct timespec tv;
+
+         tv.tv_sec = 0;
+         tv.tv_nsec = 10000000;
+
+         if (progress)
+           write (STDERR_FILENO, "w", 1);
+
+         nanosleep (&tv, NULL);
+       }
+    }
+
+  return NULL;
+}
+
+
+static void *
+thread_function (void *arg)
+{
+  work (arg);
+
+  pthread_mutex_lock (&running_mutex);
+  if (--running <= 0 && starts <= 0)
+    {
+      /* We are done.  */
+      if (progress)
+       write (STDERR_FILENO, "\n", 1);
+
+      if (timing)
+       {
+         struct timespec end_time;
+
+         if (clock_gettime (cl, &end_time) == 0)
+           {
+             end_time.tv_sec -= start_time.tv_sec;
+             end_time.tv_nsec -= start_time.tv_nsec;
+             if (end_time.tv_nsec < 0)
+               {
+                 end_time.tv_nsec += 1000000000;
+                 --end_time.tv_sec;
+               }
+
+             printf ("\nRuntime: %lu.%09lu seconds\n",
+                     (unsigned long int) end_time.tv_sec,
+                     (unsigned long int) end_time.tv_nsec);
+           }
+       }
+
+      printf ("Result: %08x\n", sum);
+
+      exit (0);
+    }
+  pthread_mutex_unlock (&running_mutex);
+
+  if (sync_method == sync_signal)
+    {
+      if (to_thread)
+       /* This code sends a signal to the main thread.  */
+       pthread_kill (tmain, SIGUSR1);
+      else
+       /* Use this code to test sending a signal to the process.  */
+       kill (pid, SIGUSR1);
+    }
+
+  if (progress)
+    write (STDERR_FILENO, "f", 1);
+
+  return NULL;
+}
+
+
+struct start_info
+{
+  unsigned int starts;
+  unsigned int threads;
+};
+
+
+static void *
+start_threads (void *arg)
+{
+  struct start_info *si = arg;
+  unsigned int starts = si->starts;
+  pthread_t ths[si->threads];
+  unsigned int state = starts;
+  unsigned int n;
+  unsigned int i = 0;
+  int err;
+
+  if (progress)
+    write (STDERR_FILENO, "T", 1);
+
+  memset (ths, '\0', sizeof (pthread_t) * si->threads);
+
+  while (starts-- > 0)
+    {
+      if (ths[i] != 0)
+       {
+         /* Wait for the threads in the order they were created.  */
+         err = pthread_join (ths[i], NULL);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot join thread");
+
+         if (progress)
+           write (STDERR_FILENO, "f", 1);
+       }
+
+      err = pthread_create (&ths[i], &attr, work,
+                           (void *) (rand_r (&state) + starts + i));
+
+      if (err != 0)
+       error (EXIT_FAILURE, err, "cannot start thread");
+
+      if (progress)
+       write (STDERR_FILENO, "t", 1);
+
+      if (++i == si->threads)
+       i = 0;
+    }
+
+  n = i;
+  do
+    {
+      if (ths[i] != 0)
+       {
+         err = pthread_join (ths[i], NULL);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot join thread");
+
+         if (progress)
+           write (STDERR_FILENO, "f", 1);
+       }
+
+      if (++i == si->threads)
+       i = 0;
+    }
+  while (i != n);
+
+  if (progress)
+    write (STDERR_FILENO, "F", 1);
+
+  return NULL;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int remaining;
+  sigset_t ss;
+  pthread_t th;
+  pthread_t *ths = NULL;
+  int empty = 0;
+  int last;
+  bool cont = true;
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  if (sync_method == sync_join)
+    {
+      ths = (pthread_t *) calloc (threads, sizeof (pthread_t));
+      if (ths == NULL)
+       error (EXIT_FAILURE, errno,
+              "cannot allocate memory for thread descriptor array");
+
+      last = threads;
+    }
+  else
+    {
+      ths = &th;
+      last = 1;
+    }
+
+  if (toplevel > threads)
+    {
+      printf ("resetting number of toplevel threads to %lu to not surpass number to concurrent threads\n",
+             threads);
+      toplevel = threads;
+    }
+
+  if (timing)
+    {
+      if (clock_getcpuclockid (0, &cl) != 0
+         || clock_gettime (cl, &start_time) != 0)
+       timing = false;
+    }
+
+  /* We need this later.  */
+  pid = getpid ();
+  tmain = pthread_self ();
+
+  /* We use signal SIGUSR1 for communication between the threads and
+     the main thread.  We only want sychronous notification.  */
+  if (sync_method == sync_signal)
+    {
+      sigemptyset (&ss);
+      sigaddset (&ss, SIGUSR1);
+      if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
+       error (EXIT_FAILURE, errno, "cannot set signal mask");
+    }
+
+  /* Create the thread attributes.  */
+  pthread_attr_init (&attr);
+
+  /* If the user provided a stack size use it.  */
+  if (stacksize != 0
+      && pthread_attr_setstacksize (&attr, stacksize) != 0)
+    puts ("could not set stack size; will use default");
+  /* And stack guard size.  */
+  if (guardsize != -1
+      && pthread_attr_setguardsize (&attr, guardsize) != 0)
+    puts ("invalid stack guard size; will use default");
+
+  /* All threads are created detached if we are not using pthread_join
+     to synchronize.  */
+  if (sync_method != sync_join)
+    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+  if (sync_method == sync_signal)
+    {
+      while (1)
+       {
+         int err;
+         bool do_wait = false;
+
+         pthread_mutex_lock (&running_mutex);
+         if (starts-- < 0)
+           cont = false;
+         else
+           do_wait = ++running >= threads && starts > 0;
+
+         pthread_mutex_unlock (&running_mutex);
+
+         if (! cont)
+           break;
+
+         if (progress)
+           write (STDERR_FILENO, "t", 1);
+
+         err = pthread_create (&ths[empty], &attr, thread_function,
+                               (void *) starts);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot start thread %lu", starts);
+
+         if (++empty == last)
+           empty = 0;
+
+         if (do_wait)
+           sigwaitinfo (&ss, NULL);
+       }
+
+      /* Do nothing anymore.  On of the threads will terminate the program.  */
+      sigfillset (&ss);
+      sigdelset (&ss, SIGINT);
+      while (1)
+       sigsuspend (&ss);
+    }
+  else
+    {
+      pthread_t ths[toplevel];
+      struct start_info si[toplevel];
+      unsigned int i;
+
+      for (i = 0; i < toplevel; ++i)
+       {
+         unsigned int child_starts = starts / (toplevel - i);
+         unsigned int child_threads = threads / (toplevel - i);
+         int err;
+
+         si[i].starts = child_starts;
+         si[i].threads = child_threads;
+
+         err = pthread_create (&ths[i], &attr, start_threads, &si[i]);
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot start thread");
+
+         starts -= child_starts;
+         threads -= child_threads;
+       }
+
+      for (i = 0; i < toplevel; ++i)
+       {
+         int err = pthread_join (ths[i], NULL);
+
+         if (err != 0)
+           error (EXIT_FAILURE, err, "cannot join thread");
+       }
+
+      /* We are done.  */
+      if (progress)
+       write (STDERR_FILENO, "\n", 1);
+
+      if (timing)
+       {
+         struct timespec end_time;
+
+         if (clock_gettime (cl, &end_time) == 0)
+           {
+             end_time.tv_sec -= start_time.tv_sec;
+             end_time.tv_nsec -= start_time.tv_nsec;
+             if (end_time.tv_nsec < 0)
+               {
+                 end_time.tv_nsec += 1000000000;
+                 --end_time.tv_sec;
+               }
+
+             printf ("\nRuntime: %lu.%09lu seconds\n",
+                     (unsigned long int) end_time.tv_sec,
+                     (unsigned long int) end_time.tv_nsec);
+           }
+       }
+
+      printf ("Result: %08x\n", sum);
+
+      exit (0);
+    }
+
+  /* NOTREACHED */
+  return 0;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  unsigned long int num;
+  long int snum;
+
+  switch (key)
+    {
+    case 't':
+      num = strtoul (arg, NULL, 0);
+      if (num < MAX_THREADS)
+       threads = num;
+      else
+       printf ("\
+number of threads limited to %u; recompile with a higher limit if necessary",
+               MAX_THREADS);
+      break;
+
+    case 'w':
+      num = strtoul (arg, NULL, 0);
+      if (num <= 100)
+       workload = num;
+      else
+       puts ("workload must be between 0 and 100 percent");
+      break;
+
+    case 'c':
+      workcost = strtoul (arg, NULL, 0);
+      break;
+
+    case 'r':
+      rounds = strtoul (arg, NULL, 0);
+      break;
+
+    case 's':
+      starts = strtoul (arg, NULL, 0);
+      break;
+
+    case 'S':
+      num = strtoul (arg, NULL, 0);
+      if (num >= PTHREAD_STACK_MIN)
+       stacksize = num;
+      else
+       printf ("minimum stack size is %d\n", PTHREAD_STACK_MIN);
+      break;
+
+    case 'g':
+      snum = strtol (arg, NULL, 0);
+      if (snum < 0)
+       printf ("invalid guard size %s\n", arg);
+      else
+       guardsize = snum;
+      break;
+
+    case 'p':
+      progress = true;
+      break;
+
+    case 'T':
+      timing = true;
+      break;
+
+    case OPT_TO_THREAD:
+      to_thread = true;
+      break;
+
+    case OPT_TO_PROCESS:
+      to_thread = false;
+      break;
+
+    case OPT_SYNC_SIGNAL:
+      sync_method = sync_signal;
+      break;
+
+    case OPT_SYNC_JOIN:
+      sync_method = sync_join;
+      break;
+
+    case OPT_TOPLEVEL:
+      num = strtoul (arg, NULL, 0);
+      if (num < MAX_THREADS)
+       toplevel = num;
+      else
+       printf ("\
+number of threads limited to %u; recompile with a higher limit if necessary",
+               MAX_THREADS);
+      sync_method = sync_join;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  return 0;
+}
+
+
+static hp_timing_t
+get_clockfreq (void)
+{
+  /* We read the information from the /proc filesystem.  It contains at
+     least one line like
+       cpu MHz         : 497.840237
+     or also
+       cpu MHz         : 497.841
+     We search for this line and convert the number in an integer.  */
+  static hp_timing_t result;
+  int fd;
+
+  /* If this function was called before, we know the result.  */
+  if (result != 0)
+    return result;
+
+  fd = open ("/proc/cpuinfo", O_RDONLY);
+  if (__builtin_expect (fd != -1, 1))
+    {
+      /* XXX AFAIK the /proc filesystem can generate "files" only up
+         to a size of 4096 bytes.  */
+      char buf[4096];
+      ssize_t n;
+
+      n = read (fd, buf, sizeof buf);
+      if (__builtin_expect (n, 1) > 0)
+       {
+         char *mhz = memmem (buf, n, "cpu MHz", 7);
+
+         if (__builtin_expect (mhz != NULL, 1))
+           {
+             char *endp = buf + n;
+             int seen_decpoint = 0;
+             int ndigits = 0;
+
+             /* Search for the beginning of the string.  */
+             while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n')
+               ++mhz;
+
+             while (mhz < endp && *mhz != '\n')
+               {
+                 if (*mhz >= '0' && *mhz <= '9')
+                   {
+                     result *= 10;
+                     result += *mhz - '0';
+                     if (seen_decpoint)
+                       ++ndigits;
+                   }
+                 else if (*mhz == '.')
+                   seen_decpoint = 1;
+
+                 ++mhz;
+               }
+
+             /* Compensate for missing digits at the end.  */
+             while (ndigits++ < 6)
+               result *= 10;
+           }
+       }
+
+      close (fd);
+    }
+
+  return result;
+}
+
+
+int
+clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
+{
+  /* We don't allow any process ID but our own.  */
+  if (pid != 0 && pid != getpid ())
+    return EPERM;
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+  /* Store the number.  */
+  *clock_id = CLOCK_PROCESS_CPUTIME_ID;
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
+
+
+#define HP_TIMING_NOW(Var)     __asm__ __volatile__ ("rdtsc" : "=A" (Var))
+
+/* Get current value of CLOCK and store it in TP.  */
+int
+clock_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  int retval = -1;
+
+  switch (clock_id)
+    {
+    case CLOCK_PROCESS_CPUTIME_ID:
+      {
+
+       static hp_timing_t freq;
+       hp_timing_t tsc;
+
+       /* Get the current counter.  */
+       HP_TIMING_NOW (tsc);
+
+       if (freq == 0)
+         {
+           freq = get_clockfreq ();
+           if (freq == 0)
+             return EINVAL;
+         }
+
+       /* Compute the seconds.  */
+       tp->tv_sec = tsc / freq;
+
+       /* And the nanoseconds.  This computation should be stable until
+          we get machines with about 16GHz frequency.  */
+       tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
+
+       retval = 0;
+      }
+    break;
+
+    default:
+      errno = EINVAL;
+      break;
+    }
+
+  return retval;
+}
diff --git a/nptl/pt-longjmp.c b/nptl/pt-longjmp.c
new file mode 100644 (file)
index 0000000..f333b8d
--- /dev/null
@@ -0,0 +1,65 @@
+/* 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 <setjmp.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+__pthread_cleanup_upto (__jmp_buf target, char *targetframe)
+{
+  struct pthread *self = THREAD_SELF;
+  struct _pthread_cleanup_buffer *cbuf;
+
+  for (cbuf = THREAD_GETMEM (self, cleanup);
+       cbuf != NULL && _JMPBUF_UNWINDS (target, cbuf);
+       cbuf = cbuf->__prev)
+    {
+#if _STACK_GROWS_DOWN
+      if ((char *) cbuf <= targetframe)
+        {
+          cbuf = NULL;
+          break;
+        }
+#elif _STACK_GROWS_UP
+      if ((char *) cbuf >= targetframe)
+        {
+          cbuf = NULL;
+          break;
+        }
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
+      /* Call the cleanup code.  */
+      cbuf->__routine (cbuf->__arg);
+    }
+
+  THREAD_SETMEM (self, cleanup, cbuf);
+}
+
+
+
+void
+longjmp (jmp_buf env, int val)
+{
+  __libc_longjmp (env, val);
+}
+weak_alias (longjmp, siglongjmp)
diff --git a/nptl/pt-sigsuspend.c b/nptl/pt-sigsuspend.c
new file mode 100644 (file)
index 0000000..d345b5d
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sysdep.h>
+#include "pthreadP.h"
+
+
+int
+sigsuspend (const sigset_t *set)
+{
+  int result;
+  int oldtype;
+
+  CANCEL_ASYNC (oldtype);
+
+#ifdef INLINE_SYSCALL
+  result = INLINE_SYSCALL (rt_sigsuspend, 2, set, _NSIG / 8);
+#else
+  result = __sigsuspend (set);
+#endif
+
+  CANCEL_RESET (oldtype);
+
+  return result;
+}
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
new file mode 100644 (file)
index 0000000..adca051
--- /dev/null
@@ -0,0 +1,182 @@
+/* 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 _PTHREADP_H
+#define _PTHREADP_H    1
+
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include "descr.h"
+#include <tls.h>
+#include <lowlevellock.h>
+#include <stackinfo.h>
+#include <internaltypes.h>
+
+
+/* Internal variables.  */
+
+
+/* Default stack size.  */
+extern size_t __default_stacksize attribute_hidden;
+
+/* Size and alignment of static TLS block.  */
+extern size_t __static_tls_size attribute_hidden;
+extern size_t __static_tls_align attribute_hidden;
+
+/* Thread descriptor handling.  */
+extern list_t __stack_user attribute_hidden;
+
+/* Attribute handling.  */
+extern struct pthread_attr *__attr_list attribute_hidden;
+extern lll_lock_t __attr_list_lock attribute_hidden;
+
+/* First available RT signal.  */
+extern int __current_sigrtmin attribute_hidden;
+/* Last available RT signal.  */
+extern int __current_sigrtmax attribute_hidden;
+
+/* Concurrency handling.  */
+extern int __concurrency_level attribute_hidden;
+
+/* Thread-local data key handling.  */
+extern struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX]
+     attribute_hidden;
+
+/* The library can run in debugging mode where it performs a lot more
+   tests.  */
+extern int __pthread_debug attribute_hidden;
+#define DEBUGGING_P __builtin_expect (__pthread_debug, 0)
+
+
+/* Cancellation test.  */
+#define CANCELLATION_P(self) \
+  do {                                                                       \
+    int cancelhandling = THREAD_GETMEM (self, cancelhandling);               \
+    if (CANCEL_ENABLED_AND_CANCELED (cancelhandling))                        \
+      {                                                                              \
+       THREAD_SETMEM (self, result, PTHREAD_CANCELED);                       \
+       __do_cancel (CURRENT_STACK_FRAME);                                    \
+      }                                                                              \
+  } while (0)
+
+/* Set cancellation mode to asynchronous.  */
+#define CANCEL_ASYNC(oldtype) \
+  pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype)
+/* Reset to previous cancellation mode.  */
+#define CANCEL_RESET(oldtype) \
+  pthread_setcanceltype (oldtype, NULL)
+
+/* Function performing the cancellation.  */
+extern void __do_cancel (char *currentframe)
+     __attribute ((visibility ("hidden"), noreturn, regparm (1)));
+extern void __cleanup_thread (struct pthread *self, char *currentframe)
+     __attribute ((visibility ("hidden"), regparm (2)));
+
+
+/* Test whether stackframe is still active.  */
+#ifdef _STACK_GROWS_DOWN
+# define FRAME_LEFT(frame, other) ((char *) frame >= (char *) other)
+#elif _STACK_GROWS_UP
+# define FRAME_LEFT(frame, other) ((char *) frame <= (char *) other)
+#else
+# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+
+
+/* Internal prototypes.  */
+
+/* Thread list handling.  */
+extern struct pthread *__find_in_stack_list (struct pthread *pd)
+     attribute_hidden;
+
+/* Deallocate a thread's stack after optionally making sure the thread
+   descriptor is still valid.  */
+extern void __free_tcb (struct pthread *pd) attribute_hidden;
+
+/* Free allocated stack.  */
+extern void __deallocate_stack (struct pthread *pd) attribute_hidden;
+
+/* Mark all the stacks except for the current one as available.  This
+   function also re-initializes the lock for the stack cache.  */
+extern void __reclaim_stacks (void) attribute_hidden;
+
+/* longjmp handling.  */
+extern void __pthread_cleanup_upto (__jmp_buf target, char *targetframe);
+
+
+/* Functions with versioned interfaces.  */
+extern int __pthread_create_2_1 (pthread_t *newthread,
+                                const pthread_attr_t *attr,
+                                void *(*start_routine) (void *), void *arg);
+extern int __pthread_create_2_0 (pthread_t *newthread,
+                                const pthread_attr_t *attr,
+                                void *(*start_routine) (void *), void *arg);
+extern int __pthread_attr_init_2_1 (pthread_attr_t *attr);
+extern int __pthread_attr_init_2_0 (pthread_attr_t *attr);
+
+
+/* Event handlers for libthread_db interface.  */
+extern void __nptl_create_event (void) attribute_hidden;
+extern void __nptl_death_event (void) attribute_hidden;
+
+
+/* Namespace save aliases.  */
+extern int __pthread_mutex_init (pthread_mutex_t *__mutex,
+                                __const pthread_mutexattr_t *__mutexattr);
+extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_trylock (pthread_mutex_t *_mutex);
+extern int __pthread_mutex_lock (pthread_mutex_t *__mutex);
+extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex);
+extern int __pthread_mutexattr_init (pthread_mutexattr_t *attr);
+extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr);
+extern int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int kind);
+extern int __pthread_attr_getstackaddr (__const pthread_attr_t *__restrict
+                                       __attr, void **__restrict __stackaddr);
+extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr,
+                                       void *__stackaddr);
+extern int __pthread_attr_getstacksize (__const pthread_attr_t *__restrict
+                                       __attr,
+                                       size_t *__restrict __stacksize);
+extern int __pthread_attr_setstacksize (pthread_attr_t *__attr,
+                                       size_t __stacksize);
+extern int __pthread_attr_getstack (__const pthread_attr_t *__restrict __attr,
+                                   void **__restrict __stackaddr,
+                                   size_t *__restrict __stacksize);
+extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr,
+                                   size_t __stacksize);
+extern int __pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
+                                 __const pthread_rwlockattr_t *__restrict
+                                 __attr);
+extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock);
+extern int __pthread_key_create (pthread_key_t *key, void (*destr) (void *));
+extern void *__pthread_getspecific (pthread_key_t key);
+extern int __pthread_setspecific (pthread_key_t key, const void *value);
+extern int __pthread_once (pthread_once_t *once_control,
+                          void (*init_routine) (void));
+extern int __pthread_atfork (void (*prepare) (void), void (*parent) (void),
+                            void (*child) (void));
+
+#endif /* pthreadP.h */
diff --git a/nptl/pthread_attr_destroy.c b/nptl/pthread_attr_destroy.c
new file mode 100644 (file)
index 0000000..088800c
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_destroy (attr)
+     pthread_attr_t *attr;
+{
+  /* Enqueue the attributes to the list of all known variables.  */
+  if (DEBUGGING_P)
+    {
+      struct pthread_attr *iattr;
+      struct pthread_attr *prevp = NULL;
+      struct pthread_attr *runp;
+
+      assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+      iattr = (struct pthread_attr *) attr;
+
+      lll_lock (__attr_list_lock);
+
+      runp = __attr_list;
+      while (runp != NULL && runp != iattr)
+       {
+         prevp = runp;
+         runp = runp->next;
+       }
+
+      if (runp != NULL)
+       {
+         if (prevp == NULL)
+           __attr_list = iattr->next;
+         else
+           prevp->next = iattr->next;
+       }
+
+      lll_unlock (__attr_list_lock);
+
+      if (runp == NULL)
+       /* Not a valid attribute.  */
+       return EINVAL;
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getdetachstate.c b/nptl/pthread_attr_getdetachstate.c
new file mode 100644 (file)
index 0000000..a1a0549
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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 <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getdetachstate (attr, detachstate)
+     const pthread_attr_t *attr;
+     int *detachstate;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  *detachstate = (iattr->flags & ATTR_FLAG_DETACHSTATE
+                 ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getguardsize.c b/nptl/pthread_attr_getguardsize.c
new file mode 100644 (file)
index 0000000..e1d0ed6
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getguardsize (attr, guardsize)
+     const pthread_attr_t *attr;
+     size_t *guardsize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  *guardsize = iattr->guardsize;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getschedparam.c b/nptl/pthread_attr_getschedparam.c
new file mode 100644 (file)
index 0000000..93961d5
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <string.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getschedparam (attr, param)
+     const pthread_attr_t *attr;
+     struct sched_param *param;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Copy the current values.  */
+  memcpy (param, &iattr->schedparam, sizeof (struct sched_param));
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getschedpolicy.c b/nptl/pthread_attr_getschedpolicy.c
new file mode 100644 (file)
index 0000000..18293f2
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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 <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getschedpolicy (attr, policy)
+     const pthread_attr_t *attr;
+     int *policy;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the current values.  */
+  *policy = iattr->schedpolicy;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getscope.c b/nptl/pthread_attr_getscope.c
new file mode 100644 (file)
index 0000000..1b97ef3
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_getscope (attr, scope)
+     const pthread_attr_t *attr;
+     int *scope;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the current values.  */
+  *scope = (iattr->flags & ATTR_FLAG_SCOPEPROCESS
+             ? PTHREAD_SCOPE_PROCESS : PTHREAD_SCOPE_SYSTEM);
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_getstack.c b/nptl/pthread_attr_getstack.c
new file mode 100644 (file)
index 0000000..1db135e
--- /dev/null
@@ -0,0 +1,41 @@
+/* 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 <assert.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstack (attr, stackaddr, stacksize)
+     const pthread_attr_t *attr;
+     void **stackaddr;
+     size_t *stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Store the result.  */
+  *stackaddr = (char *) iattr->stackaddr - iattr->stacksize;
+  *stacksize = iattr->stacksize;
+
+  return 0;
+}
+strong_alias (__pthread_attr_getstack, pthread_attr_getstack)
diff --git a/nptl/pthread_attr_getstackaddr.c b/nptl/pthread_attr_getstackaddr.c
new file mode 100644 (file)
index 0000000..f483dc8
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstackaddr (attr, stackaddr)
+     const pthread_attr_t *attr;
+     void **stackaddr;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* XXX This function has a stupid definition.  The standard
+     specifies no error value but what is if no stack address was set?
+     We return an error anyway.  */
+  if ((iattr->flags & ATTR_FLAG_STACKADDR) == 0)
+    return EINVAL;
+
+  /* Store the result.  */
+  *stackaddr = iattr->stackaddr;
+
+  return 0;
+}
+strong_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr)
+
+link_warning (pthread_attr_getstackaddr,
+              "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'")
diff --git a/nptl/pthread_attr_getstacksize.c b/nptl/pthread_attr_getstacksize.c
new file mode 100644 (file)
index 0000000..d4ff54f
--- /dev/null
@@ -0,0 +1,40 @@
+/* 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 <assert.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_getstacksize (attr, stacksize)
+     const pthread_attr_t *attr;
+     size_t *stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* If the user has not set a stack size we return what the system
+     will use as the default.  */
+  *stacksize = iattr->stacksize ?: __default_stacksize;
+
+  return 0;
+}
+strong_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize)
diff --git a/nptl/pthread_attr_init.c b/nptl/pthread_attr_init.c
new file mode 100644 (file)
index 0000000..90c8dc2
--- /dev/null
@@ -0,0 +1,97 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include "pthreadP.h"
+
+#include <shlib-compat.h>
+
+
+struct pthread_attr *__attr_list;
+lll_lock_t __attr_list_lock = LLL_LOCK_INITIALIZER;
+
+
+int
+__pthread_attr_init_2_1 (attr)
+     pthread_attr_t *attr;
+{
+  struct pthread_attr *iattr;
+
+  /* Many elements are initialized to zero so let us do it all at
+     once.  This also takes care of clearing the bytes which are not
+     internally used.  */
+  memset (attr, '\0', __SIZEOF_PTHREAD_ATTR_T);
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Default guard size specified by the standard.  */
+  iattr->guardsize = __getpagesize ();
+
+  /* Enqueue the attributes to the list of all known variables.  */
+  if (DEBUGGING_P)
+    {
+      lll_lock (__attr_list_lock);
+
+      iattr->next = __attr_list;
+      __attr_list = iattr;
+
+      lll_unlock (__attr_list_lock);
+    }
+
+  return 0;
+}
+versioned_symbol (libpthread, __pthread_attr_init_2_1, pthread_attr_init,
+                 GLIBC_2_1);
+
+
+#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_1)
+int
+__pthread_attr_init_2_0 (attr)
+     pthread_attr_t *attr;
+{
+  /* This code is specific to the old LinuxThread code which has a too
+     small pthread_attr_t definition.  The struct looked like
+     this:  */
+  struct old_attr
+  {
+    int detachstate;
+    int schedpolicy;
+    struct sched_param schedparam;
+    int inheritsched;
+    int scope;
+  } *iattr;
+
+  /* Many elements are initialized to zero so let us do it all at
+     once.  This also takes care of clearing the bytes which are not
+     internally used.  */
+  memset (attr, '\0', sizeof (struct old_attr));
+
+  iattr = (struct old_attr *) attr;
+
+  /* We cannot enqueue the attribute because that member is not in the
+     old attribute structure.  */
+  return 0;
+}
+compat_symbol (libpthread, __pthread_attr_init_2_0, pthread_attr_init,
+              GLIBC_2_0);
+#endif
diff --git a/nptl/pthread_attr_setdetachstate.c b/nptl/pthread_attr_setdetachstate.c
new file mode 100644 (file)
index 0000000..3f247cf
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setdetachstate (attr, detachstate)
+     pthread_attr_t *attr;
+     int detachstate;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  if (detachstate != PTHREAD_CREATE_DETACHED
+      && __builtin_expect (detachstate != PTHREAD_CREATE_JOINABLE, 0))
+    return EINVAL;
+
+  /* Set the flag.  It is nonzero if threads are created detached.  */
+  if (detachstate == PTHREAD_CREATE_DETACHED)
+    iattr->flags |= ATTR_FLAG_DETACHSTATE;
+  else
+    iattr->flags &= ~ATTR_FLAG_DETACHSTATE;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setguardsize.c b/nptl/pthread_attr_setguardsize.c
new file mode 100644 (file)
index 0000000..4c674f4
--- /dev/null
@@ -0,0 +1,40 @@
+/* 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 <assert.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setguardsize (attr, guardsize)
+     pthread_attr_t *attr;
+     size_t guardsize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Note that we don't round the value here.  The standard requires
+     that subsequent pthread_attr_getguardsize calls return the value
+     set by the user.  */
+  iattr->guardsize = guardsize;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setinheritsched.c b/nptl/pthread_attr_setinheritsched.c
new file mode 100644 (file)
index 0000000..f724396
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setinheritsched (attr, inherit)
+     pthread_attr_t *attr;
+     int inherit;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED)
+    return EINVAL;
+
+  /* Store the new values.  */
+  if (inherit != PTHREAD_INHERIT_SCHED)
+    iattr->flags |= ATTR_FLAG_NOTINHERITSCHED;
+  else
+    iattr->flags &= ~ATTR_FLAG_NOTINHERITSCHED;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setschedparam.c b/nptl/pthread_attr_setschedparam.c
new file mode 100644 (file)
index 0000000..2ffba99
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setschedparam (attr, param)
+     pthread_attr_t *attr;
+     const struct sched_param *param;
+{
+  struct pthread_attr *iattr;
+  int max_prio;
+  int min_prio;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  max_prio = __sched_get_priority_max (iattr->schedpolicy);
+  min_prio = __sched_get_priority_min (iattr->schedpolicy);
+
+  /* Catch invalid values.  */
+  if (param->sched_priority < min_prio || param->sched_priority > max_prio)
+    return EINVAL;
+
+  /* Copy the new values.  */
+  memcpy (&iattr->schedparam, param, sizeof (struct sched_param));
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setschedpolicy.c b/nptl/pthread_attr_setschedpolicy.c
new file mode 100644 (file)
index 0000000..65bf155
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setschedpolicy (attr, policy)
+     pthread_attr_t *attr;
+     int policy;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
+    return EINVAL;
+
+  /* Store the new values.  */
+  iattr->schedpolicy = policy;
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setscope.c b/nptl/pthread_attr_setscope.c
new file mode 100644 (file)
index 0000000..1435afb
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_attr_setscope (attr, scope)
+     pthread_attr_t *attr;
+     int scope;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid values.  */
+  switch (scope)
+    {
+    case PTHREAD_SCOPE_SYSTEM:
+      iattr->flags &= ~ATTR_FLAG_SCOPEPROCESS;
+      break;
+
+    case PTHREAD_SCOPE_PROCESS:
+      return ENOTSUP;
+
+    default:
+      return EINVAL;
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_attr_setstack.c b/nptl/pthread_attr_setstack.c
new file mode 100644 (file)
index 0000000..811ab69
--- /dev/null
@@ -0,0 +1,47 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstack (attr, stackaddr, stacksize)
+     pthread_attr_t *attr;
+     void *stackaddr;
+     size_t stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid sizes.  */
+  if (stacksize < PTHREAD_STACK_MIN)
+    return EINVAL;
+
+  iattr->stacksize = stacksize;
+  iattr->stackaddr = (char *) stackaddr + stacksize;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setstack, pthread_attr_setstack)
diff --git a/nptl/pthread_attr_setstackaddr.c b/nptl/pthread_attr_setstackaddr.c
new file mode 100644 (file)
index 0000000..a725112
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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 <assert.h>
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstackaddr (attr, stackaddr)
+     pthread_attr_t *attr;
+     void *stackaddr;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  iattr->stackaddr = stackaddr;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr)
+
+link_warning (pthread_attr_setstackaddr,
+              "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'")
diff --git a/nptl/pthread_attr_setstacksize.c b/nptl/pthread_attr_setstacksize.c
new file mode 100644 (file)
index 0000000..508cc3f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_attr_setstacksize (attr, stacksize)
+     pthread_attr_t *attr;
+     size_t stacksize;
+{
+  struct pthread_attr *iattr;
+
+  assert (sizeof (*attr) >= sizeof (struct pthread_attr));
+  iattr = (struct pthread_attr *) attr;
+
+  /* Catch invalid sizes.  */
+  if (stacksize < PTHREAD_STACK_MIN)
+    return EINVAL;
+
+  iattr->stacksize = stacksize;
+
+  return 0;
+}
+strong_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize)
diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
new file mode 100644 (file)
index 0000000..1fa20e0
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <signal.h>
+#include "pthreadP.h"
+#include "atomic.h"
+
+
+int
+pthread_cancel (th)
+     pthread_t th;
+{
+  volatile struct pthread *pd = (volatile struct pthread *) th;
+
+  while (1)
+    {
+      int oldval = pd->cancelhandling;
+      int newval = oldval | 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))
+       {
+         /* The cancellation handler will take care of marking the
+            thread as canceled.  */
+         pthread_kill (th, SIGCANCEL);
+
+         break;
+       }
+
+      /* Mark the thread as canceled.  This has to be done
+        atomically since other bits could be modified as well.  */
+      if (atomic_compare_and_exchange_acq (&pd->cancelhandling, newval,
+                                          oldval) == 0)
+       break;
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_broadcast.c b/nptl/pthread_cond_broadcast.c
new file mode 100644 (file)
index 0000000..20cc39f
--- /dev/null
@@ -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 "pthreadP.h"
+
+
+int
+pthread_cond_broadcast (cond)
+     pthread_cond_t *cond;
+{
+  lll_cond_broadcast (cond);
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_destroy.c b/nptl/pthread_cond_destroy.c
new file mode 100644 (file)
index 0000000..05299fc
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_cond_destroy (cond)
+     pthread_cond_t *cond;
+{
+  return 0;
+}
diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c
new file mode 100644 (file)
index 0000000..309fc6a
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_cond_init (cond, cond_attr)
+     pthread_cond_t *cond;
+     const pthread_condattr_t *cond_attr;
+{
+  /* Note that we don't need the COND-ATTR.  It contains only the
+     PSHARED flag which is unimportant here since conditional
+     variables are always usable in multiple processes.  */
+
+  cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER;
+  cond->__data.__nr_wakers = 0;
+  cond->__data.__nr_sleepers = 0;
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_signal.c b/nptl/pthread_cond_signal.c
new file mode 100644 (file)
index 0000000..58573d3
--- /dev/null
@@ -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 "pthreadP.h"
+
+
+int
+pthread_cond_signal (cond)
+     pthread_cond_t *cond;
+{
+  lll_cond_wake (cond);
+
+  return 0;
+}
diff --git a/nptl/pthread_cond_timedwait.c b/nptl/pthread_cond_timedwait.c
new file mode 100644 (file)
index 0000000..792dbdc
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_cond_timedwait (cond, mutex, abstime)
+     pthread_cond_t *cond;
+     pthread_mutex_t *mutex;
+     const struct timespec *abstime;
+{
+  int result;
+  int err;
+
+  /* This function is a cancellation point.  Test before we potentially
+     go to sleep.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  /* Make sure the condition is modified atomically.  */
+  lll_mutex_lock (cond->__data.__lock);
+
+  /* Release the mutex.  This might fail.  */
+  err = pthread_mutex_unlock (mutex);
+  if (__builtin_expect (err != 0, 0))
+    {
+      lll_mutex_unlock (cond->__data.__lock);
+      return err;
+    }
+
+  /* One more tread waiting.  */
+  ++cond->__data.__nr_sleepers;
+
+  /* The actual conditional variable implementation.  */
+  result = lll_cond_timedwait (cond, abstime);
+
+  if (--cond->__data.__nr_sleepers == 0)
+    /* Forget about the current wakeups now that they are done.  */
+    cond->__data.__nr_wakers = 0;
+
+  /* Lose the condvar lock.  */
+  lll_mutex_unlock (cond->__data.__lock);
+
+  /* We have to get the mutex before returning.  */
+  err = pthread_mutex_lock (mutex);
+  if (err != 0)
+    /* XXX Unconditionally overwrite the result of the wait?  */
+    result = err;
+
+  /* Cancellation handling.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  return result;
+}
diff --git a/nptl/pthread_cond_wait.c b/nptl/pthread_cond_wait.c
new file mode 100644 (file)
index 0000000..37c5ffe
--- /dev/null
@@ -0,0 +1,66 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_cond_wait (cond, mutex)
+     pthread_cond_t *cond;
+     pthread_mutex_t *mutex;
+{
+  int err;
+
+  /* This function is a cancellation point.  Test before we potentially
+     go to sleep.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  /* Make sure the condition is modified atomically.  */
+  lll_mutex_lock (cond->__data.__lock);
+
+  /* Release the mutex.  This might fail.  */
+  err = pthread_mutex_unlock (mutex);
+  if (__builtin_expect (err != 0, 0))
+    {
+      lll_mutex_unlock (cond->__data.__lock);
+      return err;
+    }
+
+  /* One more tread waiting.  */
+  ++cond->__data.__nr_sleepers;
+
+  /* The actual conditional variable implementation.  */
+  lll_cond_wait (cond);
+
+  if (--cond->__data.__nr_sleepers == 0)
+    /* Forget about the current wakeups now that they are done.  */
+    cond->__data.__nr_wakers = 0;
+
+  /* Lose the condvar lock.  */
+  lll_mutex_unlock (cond->__data.__lock);
+
+  /* We have to get the mutex before returning.  */
+  err = pthread_mutex_lock (mutex);
+
+  /* Cancellation handling.  */
+  CANCELLATION_P (THREAD_SELF);
+
+  return err;
+}
diff --git a/nptl/pthread_condattr_destroy.c b/nptl/pthread_condattr_destroy.c
new file mode 100644 (file)
index 0000000..4bce09d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_destroy (attr)
+     pthread_condattr_t *attr;
+{
+  /* Nothing to be done.  */
+  return 0;
+}
diff --git a/nptl/pthread_condattr_getpshared.c b/nptl/pthread_condattr_getpshared.c
new file mode 100644 (file)
index 0000000..7b91f14
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_getpshared (attr, pshared)
+     const pthread_condattr_t *attr;
+     int *pshared;
+{
+  *pshared = ((const struct pthread_condattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_condattr_init.c b/nptl/pthread_condattr_init.c
new file mode 100644 (file)
index 0000000..4e8aaf9
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include "pthreadP.h"
+
+
+int
+pthread_condattr_init (attr)
+     pthread_condattr_t *attr;
+{
+  memset (attr, '\0', sizeof (*attr));
+
+  return 0;
+}
diff --git a/nptl/pthread_condattr_setpshared.c b/nptl/pthread_condattr_setpshared.c
new file mode 100644 (file)
index 0000000..518c1c7
--- /dev/null
@@ -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 "pthreadP.h"
+
+int
+pthread_condattr_setpshared (attr, pshared)
+     pthread_condattr_t *attr;
+     int pshared;
+{
+  ((struct pthread_condattr *) attr)->pshared = pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
new file mode 100644 (file)
index 0000000..451a9b3
--- /dev/null
@@ -0,0 +1,419 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pthreadP.h"
+#include <hp-timing.h>
+#include <ldsodefs.h>
+
+#include <shlib-compat.h>
+
+
+/* Local function to start thread and handle cleanup.  */
+static int start_thread (void *arg);
+/* Similar version used when debugging.  */
+static int start_thread_debug (void *arg);
+
+
+/* Nozero if debugging mode is enabled.  */
+int __pthread_debug;
+
+/* Globally enabled events.  */
+td_thr_events_t __nptl_threads_events attribute_hidden;
+
+/* Pointer to descriptor with the last event.  */
+struct pthread *__nptl_last_event attribute_hidden;
+
+
+/* Code to allocate and deallocate a stack.  */
+#define DEFINE_DEALLOC
+#include "allocatestack.c"
+
+/* Code to create the thread.  */
+#include "createthread.c"
+
+
+/* Table of the key information.  */
+struct pthread_key_struct __pthread_keys[PTHREAD_KEYS_MAX];
+
+
+struct pthread *
+__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, header.data.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, header.data.list);
+       if (curp == pd)
+         {
+           result = curp;
+           break;
+         }
+      }
+
+  lll_unlock (stack_cache_lock);
+
+  return result;
+}
+
+
+/* Deallocate POSIX thread-local-storage.  */
+static void
+deallocate_tsd (struct pthread *pd)
+{
+  /* Maybe no data was ever allocated.  This happens often so we have
+     a flag for this.  */
+  if (pd->specific_used)
+    {
+      size_t round;
+      bool found_nonzero;
+
+      for (round = 0, found_nonzero = true;
+          found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS;
+          ++round)
+       {
+         size_t cnt;
+         size_t idx;
+
+         for (cnt = idx = 0; cnt < PTHREAD_KEY_1STLEVEL_SIZE; ++cnt)
+           if (pd->specific[cnt] != NULL)
+             {
+               size_t inner;
+
+               for (inner = 0; inner < PTHREAD_KEY_2NDLEVEL_SIZE;
+                    ++inner, ++idx)
+                 {
+                   void *data = pd->specific[cnt][inner].data;
+
+                   if (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.  */
+                       && (pd->specific[cnt][inner].seq
+                           == __pthread_keys[idx].seq)
+                       /* It is not necessary to register a destructor
+                          function.  */
+                       && __pthread_keys[idx].destr != NULL)
+                     {
+                       pd->specific[cnt][inner].data = NULL;
+                       __pthread_keys[idx].destr (data);
+                       found_nonzero = true;
+                     }
+                 }
+
+               if (cnt != 0)
+                 {
+                   /* The first block is allocated as part of the thread
+                      descriptor.  */
+                   free (pd->specific[cnt]);
+                   pd->specific[cnt] = NULL;
+                 }
+               else
+                 /* Clear the memory of the first block for reuse.  */
+                 memset (pd->specific[0], '\0',
+                         sizeof (struct pthread_key_data));
+             }
+           else
+             idx += PTHREAD_KEY_1STLEVEL_SIZE;
+       }
+
+      pd->specific_used = false;
+    }
+}
+
+
+/* Deallocate a thread's stack after optionally making sure the thread
+   descriptor is still valid.  */
+void
+__free_tcb (struct pthread *pd)
+{
+  /* The thread is exiting now.  */
+  if (atomic_bit_test_set (&pd->cancelhandling, TERMINATED_BIT) == 0)
+    {
+      /* 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 ();
+
+      /* Run the destructor for the thread-local data.  */
+      deallocate_tsd (pd);
+
+      /* 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
+
+  /* This is where the try/finally block should be created.  For
+     compilers without that support we do use setjmp.  */
+  if (setjmp (pd->cancelbuf) == 0)
+    {
+      /* Run the code the user provided.  */
+      pd->result = pd->start_routine (pd->arg);
+    }
+
+
+  /* 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_acq (__nptl_last_event, pd,
+                                                     pd->nextevent) != 0);
+           }
+
+         /* Now call the function to signal the event.  */
+         __nptl_death_event ();
+       }
+    }
+
+
+  /* The thread is exiting now.  */
+  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;
+}
+
+
+/* Just list start_thread but we do some more things needed for a run
+   with a debugger attached.  */
+static int
+start_thread_debug (void *arg)
+{
+  struct pthread *pd = (struct pthread *) arg;
+
+  /* Get the lock the parent locked to force synchronization.  */
+  lll_lock (pd->lock);
+  /* And give it up right away.  */
+  lll_unlock (pd->lock);
+
+  /* Now do the actual startup.  */
+  return start_thread (arg);
+}
+
+
+/* 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 (err != 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'.  */
+
+  /* Reference to the TCB itself.  */
+  pd->header.data.self = pd;
+
+#ifdef TLS_TCB_AT_TP
+  /* Self-reference.  */
+  pd->header.data.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.  */
+  pd->flags = iattr->flags;
+
+  /* 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 = THREAD_SELF->eventbuf;
+
+
+  /* Determine scheduling parameters for the thread.
+     XXX How to determine whether scheduling handling is needed?  */
+  if (0 && attr != NULL)
+    {
+      if (iattr->flags & ATTR_FLAG_NOTINHERITSCHED)
+       {
+         /* Use the scheduling parameters the user provided.  */
+         pd->schedpolicy = iattr->schedpolicy;
+         memcpy (&pd->schedparam, &iattr->schedparam,
+                 sizeof (struct sched_param));
+       }
+      else
+       {
+         /* Just store the scheduling attributes of the parent.  */
+         pd->schedpolicy = __sched_getscheduler (0);
+         __sched_getparam (0, &pd->schedparam);
+       }
+    }
+
+  /* Pass the descriptor to the caller.  */
+  *newthread = (pthread_t) pd;
+
+  /* Start the thread.  */
+  err = create_thread (pd, STACK_VARIABLES_ARGS);
+  if (err != 0)
+    {
+      /* Something went wrong.  Free the resources.  */
+      __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;
+
+      /* 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
diff --git a/nptl/pthread_detach.c b/nptl/pthread_detach.c
new file mode 100644 (file)
index 0000000..2ba9f49
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_detach (th)
+     pthread_t th;
+{
+  struct pthread *pd = (struct pthread *) th;
+  int result = 0;
+
+  /* Mark the thread as detached.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, pd, NULL) != 0)
+    {
+      /* There are two possibilities here.  First, the thread might
+        already be detached.  In this case we return EINVAL.
+        Otherwise there might already be a waiter.  The standard does
+        not mention what happens in this case.  */
+      if (IS_DETACHED (pd))
+       result = EINVAL;
+    }
+  else
+    /* Check whether the thread terminated meanwhile.  In this case we
+       will just free the TCB.  */
+    if ((pd->cancelhandling & EXITING_BITMASK) != 0)
+      /* Note that the code in __free_tcb makes sure each thread
+        control block is freed only once.  */
+      __free_tcb (pd);
+
+  return result;
+}
diff --git a/nptl/pthread_equal.c b/nptl/pthread_equal.c
new file mode 100644 (file)
index 0000000..f2ef2b4
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+
+
+int
+pthread_equal (thread1, thread2)
+     pthread_t thread1;
+     pthread_t thread2;
+{
+  return thread1 == thread2;
+}
diff --git a/nptl/pthread_exit.c b/nptl/pthread_exit.c
new file mode 100644 (file)
index 0000000..5822a2e
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+pthread_exit (value)
+     void *value;
+{
+  THREAD_SETMEM (THREAD_SELF, result, value);
+
+  __do_cancel (CURRENT_STACK_FRAME);
+}
diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c
new file mode 100644 (file)
index 0000000..4e58043
--- /dev/null
@@ -0,0 +1,65 @@
+/* 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 <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_getattr_np (thread_id, attr)
+     pthread_t thread_id;
+     pthread_attr_t *attr;
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+  struct pthread_attr *iattr = (struct pthread_attr *) attr;
+
+  /* We have to handle cancellation in the following code since we are
+     locking another threads desriptor.  */
+  pthread_cleanup_push ((void (*) (void *)) lll_unlock_wake_cb, &thread->lock);
+
+  lll_lock (thread->lock);
+
+  /* The thread library is responsible for keeping the values in the
+     thread desriptor up-to-date in case the user changes them.  */
+  memcpy (&iattr->schedparam, &thread->schedparam,
+         sizeof (struct sched_param));
+  iattr->schedpolicy = thread->schedpolicy;
+
+  /* Clear the flags work.  */
+  iattr->flags = thread->flags;
+
+  /* The thread might be detached by now.  */
+  if (IS_DETACHED (thread))
+    iattr->flags |= ATTR_FLAG_DETACHSTATE;
+
+  /* This is the guardsize after adjusting it.  */
+  iattr->guardsize = thread->guardsize;
+
+  /* The sizes are subject to alignment.  */
+  iattr->stacksize = thread->stackblock_size;
+  iattr->stackaddr = (char *) thread->stackblock + iattr->stacksize;
+  iattr->flags |= ATTR_FLAG_STACKADDR;
+
+  lll_unlock (thread->lock);
+
+  pthread_cleanup_pop (0);
+
+  return 0;
+}
diff --git a/nptl/pthread_getconcurrency.c b/nptl/pthread_getconcurrency.c
new file mode 100644 (file)
index 0000000..52c0c7c
--- /dev/null
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_getconcurrency (void)
+{
+  return __concurrency_level;
+}
diff --git a/nptl/pthread_getschedparam.c b/nptl/pthread_getschedparam.c
new file mode 100644 (file)
index 0000000..3e23ffa
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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 <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_getschedparam (thread_id, policy, param)
+     pthread_t thread_id;
+     int *policy;
+     struct sched_param *param;
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+
+  /* We have to handle cancellation in the following code since we are
+     locking another threads desriptor.  */
+  pthread_cleanup_push ((void (*) (void *)) lll_unlock_wake_cb, &thread->lock);
+
+  lll_lock (thread->lock);
+
+  /* The library is responsible for maintaining the values at all
+     times.  If the user uses a interface other than
+     pthread_setschedparam to modify the scheduler setting it is not
+     the library's problem.  */
+  *policy = thread->schedpolicy;
+  memcpy (param, &thread->schedparam, sizeof (struct sched_param));
+
+  lll_unlock (thread->lock);
+
+  pthread_cleanup_pop (0);
+
+  return 0;
+}
diff --git a/nptl/pthread_getspecific.c b/nptl/pthread_getspecific.c
new file mode 100644 (file)
index 0000000..9e3b694
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+void *
+__pthread_getspecific (key)
+     pthread_key_t key;
+{
+  struct pthread_key_data *data;
+
+  /* Special case access to the first 2nd-level block.  This is the
+     usual case.  */
+  if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1))
+    data = &THREAD_SELF->specific_1stblock[key];
+  else
+    {
+      /* Verify the key is sane.  */
+      if (key >= PTHREAD_KEYS_MAX)
+       /* Not valid.  */
+       return NULL;
+
+      unsigned int idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+      unsigned int idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+
+      /* If the sequence number doesn't match or the key cannot be defined
+        for this thread since the second level array is not allocated
+        return NULL, too.  */
+      struct pthread_key_data *level2 = THREAD_GETMEM_NC (THREAD_SELF,
+                                                         specific[idx1st]);
+      if (level2 == NULL)
+       /* Not allocated, therefore no data.  */
+       return NULL;
+
+      /* There is data.  */
+      data = &level2[idx2nd];
+    }
+
+  void *result = data->data;
+  if (result != NULL)
+    {
+      uintptr_t seq = data->seq;
+
+      if (seq != __pthread_keys[key].seq)
+       result = data = NULL;
+    }
+
+  return result;
+}
+strong_alias (__pthread_getspecific, pthread_getspecific)
diff --git a/nptl/pthread_join.c b/nptl/pthread_join.c
new file mode 100644 (file)
index 0000000..a223a7d
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "atomic.h"
+#include "pthreadP.h"
+
+
+static void
+cleanup (void *arg)
+{
+  *(void **) arg = NULL;
+}
+
+
+int
+pthread_join (threadid, thread_return)
+     pthread_t threadid;
+     void **thread_return;
+{
+  struct pthread *self;
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  self = THREAD_SELF;
+  if (pd == self || self->joinid == pd)
+    /* This is a deadlock situation.  The threads are waiting for each
+       other to finish.  Note that this is a "may" error.  To be 100%
+       sure we catch this error we would have to lock the data
+       structures but it is not necessary.  In the unlikely case that
+       two threads are really caught in this situation they will
+       deadlock.  It is the programmer's problem to figure this
+       out.  */
+    return EDEADLK;
+
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, self, NULL) != 0)
+    /* There is already somebody waiting for the thread.  */
+    return EINVAL;
+
+
+  /* During the wait we change to asynchronous cancellation.  If we
+     are cancelled the thread we are waiting for must be marked as
+     un-wait-ed for again.  */
+  pthread_cleanup_push (cleanup, &pd->joinid);
+
+  /* Switch to asynchronous cancellation.  */
+  int oldtype;
+  CANCEL_ASYNC (oldtype);
+
+
+  /* Wait for the child.  */
+  lll_wait_tid (pd->tid);
+
+
+  /* Restore cancellation mode.  */
+  CANCEL_RESET (oldtype);
+
+  /* Remove the handler.  */
+  pthread_cleanup_pop (0);
+
+
+  /* Store the return value if the caller is interested.  */
+  if (thread_return != NULL)
+    *thread_return = pd->result;
+
+
+  /* Free the TCB.  */
+  __free_tcb (pd);
+
+  return 0;
+}
diff --git a/nptl/pthread_key_create.c b/nptl/pthread_key_create.c
new file mode 100644 (file)
index 0000000..7a073f2
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+/* Internal mutex for __pthread_kyes table handling.  */
+lll_lock_t __pthread_keys_lock = LLL_LOCK_INITIALIZER;
+
+
+/* For debugging purposes put the maximum number of keys in a variable.  */
+const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX;
+const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE;
+
+
+int
+__pthread_key_create (key, destr)
+     pthread_key_t *key;
+     void (*destr) (void *);
+{
+  int result = EAGAIN;
+  size_t cnt;
+
+  lll_lock (__pthread_keys_lock);
+
+  /* Find a slot in __pthread_kyes which is unused.  */
+  for (cnt = 0; cnt < PTHREAD_KEYS_MAX; ++cnt)
+    if (KEY_UNUSED (__pthread_keys[cnt].seq)
+       && KEY_USABLE (__pthread_keys[cnt].seq))
+      {
+       /* We found an unused slot.  */
+       ++__pthread_keys[cnt].seq;
+
+       /* Remember the destructor.  */
+       __pthread_keys[cnt].destr = destr;
+
+       /* Return the key to the caller.  */
+       *key = cnt;
+
+       /* The call succeeded.  */
+       result = 0;
+
+       /* We found a key and can stop now.  */
+       break;
+      }
+
+  lll_unlock (__pthread_keys_lock);
+
+  return result;
+}
+strong_alias (__pthread_key_create, pthread_key_create)
diff --git a/nptl/pthread_key_delete.c b/nptl/pthread_key_delete.c
new file mode 100644 (file)
index 0000000..a0145f8
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_key_delete (key)
+     pthread_key_t key;
+{
+  int result = EINVAL;
+
+  if (__builtin_expect (key < PTHREAD_KEYS_MAX, 1))
+    {
+      unsigned int seq = __pthread_keys[key].seq;
+
+      if (__builtin_expect (! KEY_UNUSED (seq), 1)
+         && atomic_compare_and_exchange_acq (&__pthread_keys[key].seq,
+                                             seq + 1, seq) == 0)
+       /* We deleted a valid key.  */
+       result = 0;
+    }
+
+  return result;
+}
diff --git a/nptl/pthread_kill_other_threads.c b/nptl/pthread_kill_other_threads.c
new file mode 100644 (file)
index 0000000..a446423
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <shlib-compat.h>
+
+
+#ifdef SHARED
+/* This function does not serve a useful purpose in the thread library
+   implementation anymore.  It used to be necessary when then kernel
+   could not shut down "processes" but this is not the case anymore.
+
+   We could theoretically provide an equivalent implementation but
+   this is not necessary since the kernel already does a much better
+   job than we ever could.  */
+void
+__pthread_kill_other_threads_np (void)
+{
+}
+compat_symbol (libpthread, __pthread_kill_other_threads_np,
+              pthread_kill_other_threads_np, GLIBC_2_0);
+#endif
diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c
new file mode 100644 (file)
index 0000000..e3dba37
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+__pthread_mutex_destroy (mutex)
+     pthread_mutex_t *mutex;
+{
+  return 0;
+}
+strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy)
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
new file mode 100644 (file)
index 0000000..3a783d7
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <assert.h>
+#include <string.h>
+#include "pthreadP.h"
+
+
+static const struct pthread_mutexattr default_attr =
+  {
+    /* Default is a normal mutex, not shared between processes.  */
+    .mutexkind = PTHREAD_MUTEX_NORMAL
+  };
+
+
+int
+__pthread_mutex_init (mutex, mutexattr)
+     pthread_mutex_t *mutex;
+     const pthread_mutexattr_t *mutexattr;
+{
+  const struct pthread_mutexattr *imutexattr;
+
+  assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T);
+
+  imutexattr = (const struct pthread_mutexattr *) mutexattr ?: &default_attr;
+
+  /* Clear the whole variable.  */
+  memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T);
+
+  /* Copy the values from the attribute.  */
+  mutex->__data.__kind = imutexattr->mutexkind & ~0x80000000;
+
+  /* Default values: mutex not used yet.  */
+  // mutex->__count = 0;       already done by memset
+  // mutex->__owner = NULL;    already done by memset
+
+  return 0;
+}
+strong_alias (__pthread_mutex_init, pthread_mutex_init)
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
new file mode 100644 (file)
index 0000000..8398003
--- /dev/null
@@ -0,0 +1,77 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_lock (mutex)
+     pthread_mutex_t *mutex;
+{
+  struct pthread *pd = THREAD_SELF;
+
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+       }
+      else
+       {
+         /* We have to get the mutex.  */
+         lll_mutex_lock (mutex->__data.__lock);
+
+         /* Record the ownership.  */
+         mutex->__data.__owner = pd;
+         mutex->__data.__count = 1;
+       }
+      break;
+
+      /* Error checking mutex.  */
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      lll_mutex_lock (mutex->__data.__lock);
+      /* Record the ownership.  */
+      mutex->__data.__owner = pd;
+      break;
+    }
+
+  return 0;
+}
+strong_alias (__pthread_mutex_lock, pthread_mutex_lock)
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
new file mode 100644 (file)
index 0000000..a63b204
--- /dev/null
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_mutex_timedlock (mutex, abstime)
+     pthread_mutex_t *mutex;
+     const struct timespec *abstime;
+{
+  struct pthread *pd = THREAD_SELF;
+  int result = 0;
+
+  /* We must not check ABSTIME here.  If the thread does not block
+     abstime must not be checked for a valid value.  */
+
+  switch (mutex->__data.__kind)
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       {
+         /* Just bump the counter.  */
+         if (__builtin_expect (mutex->__data.__count + 1 == 0, 0))
+           /* Overflow of the counter.  */
+           return EAGAIN;
+
+         ++mutex->__data.__count;
+
+         goto out;
+       }
+      else
+       {
+         /* We have to get the mutex.  */
+         result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+
+         if (result != 0)
+           goto out;
+
+         /* Only locked once so far.  */
+         mutex->__data.__count = 1;
+       }
+      break;
+
+      /* Error checking mutex.  */
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       return EDEADLK;
+
+      /* FALLTHROUGH */
+
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      result = lll_mutex_timedlock (mutex->__data.__lock, abstime);
+      break;
+    }
+
+  if (result == 0)
+    /* Record the ownership.  */
+    mutex->__data.__owner = pd;
+
+ out:
+  return result;
+}
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
new file mode 100644 (file)
index 0000000..aae5067
--- /dev/null
@@ -0,0 +1,70 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_trylock (mutex)
+     pthread_mutex_t *mutex;
+{
+  struct pthread *pd = THREAD_SELF;
+
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
+    {
+      /* Recursive mutex.  */
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Check whether we already hold the mutex.  */
+      if (mutex->__data.__owner == pd)
+       {
+         /* Just bump the counter.  */
+         ++mutex->__data.__count;
+         return 0;
+       }
+
+      if (lll_mutex_trylock (mutex->__data.__lock) == 0)
+       {
+         /* Record the ownership.  */
+         mutex->__data.__owner = pd;
+         mutex->__data.__count = 1;
+         return 0;
+       }
+      break;
+
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Error checking mutex.  We do not check for deadlocks.  */
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  */
+      if (lll_mutex_trylock (mutex->__data.__lock) == 0)
+       {
+         /* Record the ownership.  */
+         mutex->__data.__owner = pd;
+
+         return 0;
+       }
+    }
+
+  return EBUSY;
+}
+strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock)
diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c
new file mode 100644 (file)
index 0000000..be510cb
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_mutex_unlock (mutex)
+     pthread_mutex_t *mutex;
+{
+  switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP))
+    {
+    case PTHREAD_MUTEX_RECURSIVE_NP:
+      /* Recursive mutex.  */
+      if (mutex->__data.__owner != THREAD_SELF)
+       return EPERM;
+
+      if (--mutex->__data.__count != 0)
+       /* We still hold the mutex.  */
+       return 0;
+
+      mutex->__data.__owner = NULL;
+      break;
+
+    case PTHREAD_MUTEX_ERRORCHECK_NP:
+      /* Error checking mutex.  */
+      if (mutex->__data.__owner != THREAD_SELF
+         || ! lll_mutex_islocked (mutex->__data.__lock))
+       return EPERM;
+
+      mutex->__data.__owner = NULL;
+      break;
+
+    default:
+      /* Correct code cannot set any other type.  */
+    case PTHREAD_MUTEX_TIMED_NP:
+    case PTHREAD_MUTEX_ADAPTIVE_NP:
+      /* Normal mutex.  Nothing special to do.  */
+      break;
+    }
+
+  /* Unlock.  */
+  lll_mutex_unlock (mutex->__data.__lock);
+
+  return 0;
+}
+strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock)
diff --git a/nptl/pthread_mutexattr_destroy.c b/nptl/pthread_mutexattr_destroy.c
new file mode 100644 (file)
index 0000000..eab27d3
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+__pthread_mutexattr_destroy (attr)
+     pthread_mutexattr_t *attr;
+{
+  return 0;
+}
+strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy)
diff --git a/nptl/pthread_mutexattr_getpshared.c b/nptl/pthread_mutexattr_getpshared.c
new file mode 100644 (file)
index 0000000..1769463
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_getpshared (attr, pshared)
+     const pthread_mutexattr_t *attr;
+     int *pshared;
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  *pshared = ((iattr->mutexkind & 0x80000000) != 0
+             ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE);
+
+  return 0;
+}
diff --git a/nptl/pthread_mutexattr_gettype.c b/nptl/pthread_mutexattr_gettype.c
new file mode 100644 (file)
index 0000000..82a938d
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_gettype (attr, kind)
+     const pthread_mutexattr_t *attr;
+     int *kind;
+{
+  const struct pthread_mutexattr *iattr;
+
+  iattr = (const struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  *kind = iattr->mutexkind & ~0x80000000;
+
+  return 0;
+}
+weak_alias (pthread_mutexattr_gettype, pthread_mutexattr_getkind_np)
diff --git a/nptl/pthread_mutexattr_init.c b/nptl/pthread_mutexattr_init.c
new file mode 100644 (file)
index 0000000..3270d53
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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 <string.h>
+#include <pthreadP.h>
+
+
+int
+__pthread_mutexattr_init (attr)
+     pthread_mutexattr_t *attr;
+{
+  if (sizeof (struct pthread_mutexattr) != sizeof (pthread_mutexattr_t))
+    memset (attr, '\0', sizeof (*attr));
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  By default it is zero, i.e., the mutex is
+     not process-shared.  */
+  ((struct pthread_mutexattr *) attr)->mutexkind = PTHREAD_MUTEX_NORMAL;
+
+  return 0;
+}
+strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init)
diff --git a/nptl/pthread_mutexattr_setpshared.c b/nptl/pthread_mutexattr_setpshared.c
new file mode 100644 (file)
index 0000000..9bc5c26
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+pthread_mutexattr_setpshared (attr, pshared)
+     pthread_mutexattr_t *attr;
+     int pshared;
+{
+  struct pthread_mutexattr *iattr;
+
+  if (pshared != PTHREAD_PROCESS_PRIVATE
+      && __builtin_expect (pshared != PTHREAD_PROCESS_SHARED, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  if (pshared == PTHREAD_PROCESS_PRIVATE)
+    iattr->mutexkind &= ~0x80000000;
+  else
+    iattr->mutexkind |= 0x80000000;
+
+  return 0;
+}
diff --git a/nptl/pthread_mutexattr_settype.c b/nptl/pthread_mutexattr_settype.c
new file mode 100644 (file)
index 0000000..54021b3
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthreadP.h>
+
+
+int
+__pthread_mutexattr_settype (attr, kind)
+     pthread_mutexattr_t *attr;
+     int kind;
+{
+  struct pthread_mutexattr *iattr;
+
+  if (kind < PTHREAD_MUTEX_NORMAL || kind > PTHREAD_MUTEX_ADAPTIVE_NP)
+    return EINVAL;
+
+  iattr = (struct pthread_mutexattr *) attr;
+
+  /* We use bit 31 to single whether the mutex is going to be
+     process-shared or not.  */
+  iattr->mutexkind = (iattr->mutexkind & 0x80000000) | kind;
+
+  return 0;
+}
+weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_setkind_np)
+strong_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype)
diff --git a/nptl/pthread_rwlock_destroy.c b/nptl/pthread_rwlock_destroy.c
new file mode 100644 (file)
index 0000000..28fd24b
--- /dev/null
@@ -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 "pthreadP.h"
+
+
+int
+__pthread_rwlock_destroy (rwlock)
+     pthread_rwlock_t *rwlock;
+{
+  /* Nothing to be done.  For now.  */
+  return 0;
+}
+strong_alias (__pthread_rwlock_destroy, pthread_rwlock_destroy)
diff --git a/nptl/pthread_rwlock_init.c b/nptl/pthread_rwlock_init.c
new file mode 100644 (file)
index 0000000..f664dd8
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+static const struct pthread_rwlockattr default_attr =
+  {
+    .lockkind = PTHREAD_RWLOCK_DEFAULT_NP,
+    .pshared = PTHREAD_PROCESS_PRIVATE
+  };
+
+
+int
+__pthread_rwlock_init (rwlock, attr)
+     pthread_rwlock_t *rwlock;
+     const pthread_rwlockattr_t *attr;
+{
+  const struct pthread_rwlockattr *iattr;
+
+  iattr = ((const struct pthread_rwlockattr *) attr) ?: &default_attr;
+
+  rwlock->__data.__lock = 0;
+  rwlock->__data.__flags
+    = iattr->lockkind == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP;
+  rwlock->__data.__nr_readers = 0;
+  rwlock->__data.__writer = 0;
+  rwlock->__data.__readers_wakeup = 0;
+  rwlock->__data.__writer_wakeup = 0;
+  rwlock->__data.__nr_readers_queued = 0;
+  rwlock->__data.__nr_writers_queued = 0;
+
+  return 0;
+}
+strong_alias (__pthread_rwlock_init, pthread_rwlock_init)
diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c
new file mode 100644 (file)
index 0000000..446af05
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_rwlock_tryrdlock (rwlock)
+     pthread_rwlock_t *rwlock;
+{
+  int result = EBUSY;
+
+  lll_mutex_lock (rwlock->__data.__lock);
+
+  if (rwlock->__data.__writer == 0
+      && (rwlock->__data.__nr_writers_queued == 0
+         || rwlock->__data.__flags == 0))
+    {
+      if (__builtin_expect (++rwlock->__data.__nr_readers == 0, 0))
+       {
+         --rwlock->__data.__nr_readers;
+         result = EAGAIN;
+       }
+      else
+       result = 0;
+    }
+
+  lll_mutex_unlock (rwlock->__data.__lock);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock)
diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c
new file mode 100644 (file)
index 0000000..32fcbba
--- /dev/null
@@ -0,0 +1,43 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+__pthread_rwlock_trywrlock (rwlock)
+     pthread_rwlock_t *rwlock;
+{
+  int result = EBUSY;
+
+  lll_mutex_lock (rwlock->__data.__lock);
+
+  if (rwlock->__data.__writer == 0 && rwlock->__data.__nr_readers == 0)
+    {
+      rwlock->__data.__writer = (pthread_t) THREAD_SELF;
+      result = 0;
+    }
+
+  lll_mutex_unlock (rwlock->__data.__lock);
+
+  return result;
+}
+strong_alias (__pthread_rwlock_trywrlock, pthread_rwlock_trywrlock)
diff --git a/nptl/pthread_rwlockattr_destroy.c b/nptl/pthread_rwlockattr_destroy.c
new file mode 100644 (file)
index 0000000..4f0c2c4
--- /dev/null
@@ -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 "pthreadP.h"
+
+
+int
+pthread_rwlockattr_destroy (attr)
+     pthread_rwlockattr_t *attr;
+{
+  /* Nothing to do.  For now.  */
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_getkind_np.c b/nptl/pthread_rwlockattr_getkind_np.c
new file mode 100644 (file)
index 0000000..aad9468
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_getkind_np (attr, pref)
+     const pthread_rwlockattr_t *attr;
+     int *pref;
+{
+  *pref = ((const struct pthread_rwlockattr *) attr)->lockkind;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_getpshared.c b/nptl/pthread_rwlockattr_getpshared.c
new file mode 100644 (file)
index 0000000..3a77683
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_getpshared (attr, pshared)
+     const pthread_rwlockattr_t *attr;
+     int *pshared;
+{
+  *pshared = ((const struct pthread_rwlockattr *) attr)->pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_init.c b/nptl/pthread_rwlockattr_init.c
new file mode 100644 (file)
index 0000000..b299534
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_init (attr)
+     pthread_rwlockattr_t *attr;
+{
+  struct pthread_rwlockattr *iattr;
+
+  iattr = (struct pthread_rwlockattr *) attr;
+
+  iattr->lockkind = PTHREAD_RWLOCK_DEFAULT_NP;
+  iattr->pshared = PTHREAD_PROCESS_PRIVATE;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_setkind_np.c b/nptl/pthread_rwlockattr_setkind_np.c
new file mode 100644 (file)
index 0000000..0311f1b
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_setkind_np (attr, pref)
+     pthread_rwlockattr_t *attr;
+     int pref;
+{
+  struct pthread_rwlockattr *iattr;
+
+  if (pref != PTHREAD_RWLOCK_PREFER_READER_NP
+      && pref != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
+      && __builtin_expect  (pref != PTHREAD_RWLOCK_PREFER_WRITER_NP, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_rwlockattr *) attr;
+
+  iattr->lockkind = pref;
+
+  return 0;
+}
diff --git a/nptl/pthread_rwlockattr_setpshared.c b/nptl/pthread_rwlockattr_setpshared.c
new file mode 100644 (file)
index 0000000..9438d29
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+
+
+int
+pthread_rwlockattr_setpshared (attr, pshared)
+     pthread_rwlockattr_t *attr;
+     int pshared;
+{
+  struct pthread_rwlockattr *iattr;
+
+  if (pshared != PTHREAD_PROCESS_SHARED
+      && __builtin_expect (pshared != PTHREAD_PROCESS_PRIVATE, 0))
+    return EINVAL;
+
+  iattr = (struct pthread_rwlockattr *) attr;
+
+  iattr->pshared = pshared;
+
+  return 0;
+}
diff --git a/nptl/pthread_self.c b/nptl/pthread_self.c
new file mode 100644 (file)
index 0000000..ad231cd
--- /dev/null
@@ -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 "pthreadP.h"
+#include <tls.h>
+
+
+pthread_t
+pthread_self (void)
+{
+  return (pthread_t) THREAD_SELF;
+}
diff --git a/nptl/pthread_setcancelstate.c b/nptl/pthread_setcancelstate.c
new file mode 100644 (file)
index 0000000..3f36df8
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_setcancelstate (state, oldstate)
+     int state;
+     int *oldstate;
+{
+  volatile struct pthread *self;
+
+  if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE)
+    return EINVAL;
+
+  self = THREAD_SELF;
+
+  while (1)
+    {
+      int oldval = THREAD_GETMEM (self, cancelhandling);
+      int newval = (state == PTHREAD_CANCEL_DISABLE
+                   ? oldval | CANCELSTATE_BITMASK
+                   : oldval & ~CANCELSTATE_BITMASK);
+
+      /* Store the old value.  */
+      if (oldstate != NULL)
+       *oldstate = ((oldval & CANCELSTATE_BITMASK)
+                    ? PTHREAD_CANCEL_DISABLE : PTHREAD_CANCEL_ENABLE);
+
+      /* 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;
+
+      /* Update the cancel handling word.  This has to be done
+        atomically since other bits could be modified as well.  */
+      if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+                                          oldval) == 0)
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           __do_cancel (CURRENT_STACK_FRAME);
+
+         break;
+       }
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_setcanceltype.c b/nptl/pthread_setcanceltype.c
new file mode 100644 (file)
index 0000000..8f84634
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include "pthreadP.h"
+#include <atomic.h>
+
+
+int
+pthread_setcanceltype (type, oldtype)
+     int type;
+     int *oldtype;
+{
+  volatile struct pthread *self;
+
+  if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS)
+    return EINVAL;
+
+  self = THREAD_SELF;
+
+  while (1)
+    {
+      int oldval = THREAD_GETMEM (self, cancelhandling);
+      int newval = (type == PTHREAD_CANCEL_ASYNCHRONOUS
+                   ? oldval | CANCELTYPE_BITMASK
+                   : oldval & ~CANCELTYPE_BITMASK);
+
+      /* Store the old value.  */
+      if (oldtype != NULL)
+       *oldtype = ((oldval & CANCELTYPE_BITMASK)
+                   ? PTHREAD_CANCEL_ASYNCHRONOUS : PTHREAD_CANCEL_DEFERRED);
+
+      /* 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;
+
+      /* Update the cancel handling word.  This has to be done
+        atomically since other bits could be modified as well.  */
+      if (atomic_compare_and_exchange_acq (&self->cancelhandling, newval,
+                                          oldval) == 0)
+       {
+         if (CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS (newval))
+           {
+             THREAD_SETMEM (self, result, PTHREAD_CANCELED);
+             __do_cancel (CURRENT_STACK_FRAME);
+           }
+
+         break;
+       }
+    }
+
+  return 0;
+}
diff --git a/nptl/pthread_setconcurrency.c b/nptl/pthread_setconcurrency.c
new file mode 100644 (file)
index 0000000..f65a174
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+/* Global definition.  Needed in pthread_getconcurrency as well.  */
+int __concurrency_level;
+
+
+int
+pthread_setconcurrency (level)
+     int level;
+{
+  __concurrency_level = level;
+
+  /* XXX For ports which actually need to handle the concurrency level
+     some more code is probably needed here.  */
+
+  return 0;
+}
diff --git a/nptl/pthread_setschedparam.c b/nptl/pthread_setschedparam.c
new file mode 100644 (file)
index 0000000..f662405
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include "pthreadP.h"
+#include <lowlevellock.h>
+
+
+int
+pthread_setschedparam (thread_id, policy, param)
+     pthread_t thread_id;
+     int policy;
+     const struct sched_param *param;
+{
+  struct pthread *thread = (struct pthread *) thread_id;
+  int result = 0;
+
+  /* We have to handle cancellation in the following code since we are
+     locking another threads desriptor.  */
+  pthread_cleanup_push ((void (*) (void *)) lll_unlock_wake_cb, &thread->lock);
+
+  lll_lock (thread->lock);
+
+  /* Try to set the scheduler information.  */
+  if (__builtin_expect (__sched_setscheduler (thread->tid, policy,
+                                             param) == -1, 0))
+    result = errno;
+  else
+    {
+      /* We succeeded changing the kernel information.  Reflect this
+        change in the thread descriptor.  */
+      thread->schedpolicy = policy;
+      memcpy (&thread->schedparam, param, sizeof (struct sched_param));
+    }
+
+  lll_unlock (thread->lock);
+
+  pthread_cleanup_pop (0);
+
+  return result;
+}
diff --git a/nptl/pthread_setspecific.c b/nptl/pthread_setspecific.c
new file mode 100644 (file)
index 0000000..5af6cae
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "pthreadP.h"
+
+
+int
+__pthread_setspecific (key, value)
+     pthread_key_t key;
+     const void *value;
+{
+  struct pthread *self;
+  unsigned int idx1st;
+  unsigned int idx2nd;
+  struct pthread_key_data *level2;
+  unsigned int seq;
+
+  self = THREAD_SELF;
+
+  /* Special case access to the first 2nd-level block.  This is the
+     usual case.  */
+  if (__builtin_expect (key < PTHREAD_KEY_2NDLEVEL_SIZE, 1))
+    {
+      /* Verify the key is sane.  */
+      if (KEY_UNUSED ((seq = __pthread_keys[key].seq)))
+       /* Not valid.  */
+       return EINVAL;
+
+      level2 = &self->specific_1stblock[key];
+    }
+  else
+    {
+      if (KEY_UNUSED ((seq = __pthread_keys[key].seq))
+         || key >= PTHREAD_KEYS_MAX)
+       /* Not valid.  */
+       return EINVAL;
+
+      idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
+      idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
+
+      /* This is the second level array.  Allocate it if necessary.  */
+      level2 = THREAD_GETMEM_NC (self, specific[idx1st]);
+      if (level2 == NULL)
+       {
+         if (value == NULL)
+           /* We don't have to do anything.  The value would in any case
+              be NULL.  We can save the memory allocation.  */
+           return 0;
+
+         level2
+           = (struct pthread_key_data *) calloc (PTHREAD_KEY_2NDLEVEL_SIZE,
+                                                 sizeof (*level2));
+         if (level2 == NULL)
+           return ENOMEM;
+
+         THREAD_SETMEM_NC (self, specific[idx1st], level2);
+       }
+
+      /* Pointer to the right array element.  */
+      level2 = &level2[idx2nd];
+    }
+
+  /* Store the data and the sequence number so that we can recognize
+     stale data.  */
+  level2->seq = seq;
+  level2->data = (void *) value;
+
+  /* Remember that we stored at least one set of data.  */
+  THREAD_SETMEM (self, specific_used, true);
+
+  return 0;
+}
+strong_alias (__pthread_setspecific, pthread_setspecific)
diff --git a/nptl/pthread_testcancel.c b/nptl/pthread_testcancel.c
new file mode 100644 (file)
index 0000000..e9b17b4
--- /dev/null
@@ -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 <stdlib.h>
+#include "pthreadP.h"
+
+
+void
+pthread_testcancel (void)
+{
+  CANCELLATION_P (THREAD_SELF);
+}
diff --git a/nptl/pthread_timedjoin.c b/nptl/pthread_timedjoin.c
new file mode 100644 (file)
index 0000000..d3f4a28
--- /dev/null
@@ -0,0 +1,108 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "atomic.h"
+#include "pthreadP.h"
+
+
+static void
+cleanup (void *arg)
+{
+  *(void **) arg = NULL;
+}
+
+
+int
+pthread_timedjoin_np (threadid, thread_return, abstime)
+     pthread_t threadid;
+     void **thread_return;
+     const struct timespec *abstime;
+{
+  struct pthread *self;
+  struct pthread *pd = (struct pthread *) threadid;
+  int result;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  self = THREAD_SELF;
+  if (pd == self || self->joinid == pd)
+    /* This is a deadlock situation.  The threads are waiting for each
+       other to finish.  Note that this is a "may" error.  To be 100%
+       sure we catch this error we would have to lock the data
+       structures but it is not necessary.  In the unlikely case that
+       two threads are really caught in this situation they will
+       deadlock.  It is the programmer's problem to figure this
+       out.  */
+    return EDEADLK;
+
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, self, NULL) != 0)
+    /* There is already somebody waiting for the thread.  */
+    return EINVAL;
+
+
+  /* During the wait we change to asynchronous cancellation.  If we
+     are cancelled the thread we are waiting for must be marked as
+     un-wait-ed for again.  */
+  pthread_cleanup_push (cleanup, &pd->joinid);
+
+  /* Switch to asynchronous cancellation.  */
+  int oldtype;
+  CANCEL_ASYNC (oldtype);
+
+
+  /* Wait for the child.  */
+  result = lll_timedwait_tid (pd->tid, abstime);
+
+
+  /* Restore cancellation mode.  */
+  CANCEL_RESET (oldtype);
+
+  /* Remove the handler.  */
+  pthread_cleanup_pop (0);
+
+
+  /* We might have timed out.  */
+  if (result == 0)
+    {
+      /* Store the return value if the caller is interested.  */
+      if (thread_return != NULL)
+       *thread_return = pd->result;
+
+
+      /* Free the TCB.  */
+      __free_tcb (pd);
+    }
+  else
+    pd->joinid = NULL;
+
+  return result;
+}
diff --git a/nptl/pthread_tryjoin.c b/nptl/pthread_tryjoin.c
new file mode 100644 (file)
index 0000000..88d2e8b
--- /dev/null
@@ -0,0 +1,75 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "atomic.h"
+#include "pthreadP.h"
+
+
+int
+pthread_tryjoin_np (threadid, thread_return)
+     pthread_t threadid;
+     void **thread_return;
+{
+  struct pthread *self;
+  struct pthread *pd = (struct pthread *) threadid;
+
+  /* Make sure the descriptor is valid.  */
+  if (DEBUGGING_P && __find_in_stack_list (pd) == NULL)
+    /* Not a valid thread handle.  */
+    return ESRCH;
+
+  /* Is the thread joinable?.  */
+  if (IS_DETACHED (pd))
+    /* We cannot wait for the thread.  */
+    return EINVAL;
+
+  self = THREAD_SELF;
+  if (pd == self || self->joinid == pd)
+    /* This is a deadlock situation.  The threads are waiting for each
+       other to finish.  Note that this is a "may" error.  To be 100%
+       sure we catch this error we would have to lock the data
+       structures but it is not necessary.  In the unlikely case that
+       two threads are really caught in this situation they will
+       deadlock.  It is the programmer's problem to figure this
+       out.  */
+    return EDEADLK;
+
+  /* Return right away if the thread hasn't terminated yet.  */
+  if (pd->tid != 0)
+    return EBUSY;
+
+  /* Wait for the thread to finish.  If it is already locked something
+     is wrong.  There can only be one waiter.  */
+  if (atomic_compare_and_exchange_acq (&pd->joinid, self, NULL) != 0)
+    /* There is already somebody waiting for the thread.  */
+    return EINVAL;
+
+  /* Store the return value if the caller is interested.  */
+  if (thread_return != NULL)
+    *thread_return = pd->result;
+
+
+  /* Free the TCB.  */
+  __free_tcb (pd);
+
+  return 0;
+}
diff --git a/nptl/res.c b/nptl/res.c
new file mode 100644 (file)
index 0000000..6c2e3f8
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <features.h>
+#include <resolv.h>
+#undef _res
+
+#include <tls.h>
+
+/* With __thread support, this per-thread variable is used in all cases.  */
+extern __thread struct __res_state _res;
+
+
+struct __res_state *
+__res_state (void)
+{
+  return &_res;
+}
diff --git a/nptl/sem_close.c b/nptl/sem_close.c
new file mode 100644 (file)
index 0000000..379565f
--- /dev/null
@@ -0,0 +1,29 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <semaphore.h>
+#include <sys/mman.h>
+
+
+int
+sem_close (sem)
+     sem_t *sem;
+{
+  return munmap (sem, sizeof (sem_t));
+}
diff --git a/nptl/sem_destroy.c b/nptl/sem_destroy.c
new file mode 100644 (file)
index 0000000..790a80e
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <semaphore.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_destroy (sem)
+     sem_t *sem;
+{
+  /* XXX Check for valid parameter.  */
+
+  /* Nothing to do.  */
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_destroy, sem_destroy, GLIBC_2_1);
diff --git a/nptl/sem_getvalue.c b/nptl/sem_getvalue.c
new file mode 100644 (file)
index 0000000..ee976c3
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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 <semaphore.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_getvalue (sem, sval)
+     sem_t *sem;
+     int *sval;
+{
+  struct sem *isem = (struct sem *) sem;
+
+  /* XXX Check for valid SEM parameter.  */
+
+  *sval = isem->count;
+
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_getvalue, sem_getvalue, GLIBC_2_1);
diff --git a/nptl/sem_init.c b/nptl/sem_init.c
new file mode 100644 (file)
index 0000000..c8b80ff
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <lowlevellock.h>
+#include <shlib-compat.h>
+#include "semaphoreP.h"
+
+
+int
+__new_sem_init (sem, pshared, value)
+     sem_t *sem;
+     int pshared;
+     unsigned int value;
+{
+  /* Parameter sanity check.  */
+  if (__builtin_expect (value > SEM_VALUE_MAX, 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Map to the internal type.  */
+  struct sem *isem = (struct sem *) sem;
+
+  /* Use the value the user provided.  */
+  isem->count = value;
+
+  /* We can completely ignore the PSHARED parameter since inter-process
+     use needs no special preparation.  */
+
+  return 0;
+}
+versioned_symbol (libpthread, __new_sem_init, sem_init, GLIBC_2_1);
diff --git a/nptl/sem_open.c b/nptl/sem_open.c
new file mode 100644 (file)
index 0000000..6fc72f7
--- /dev/null
@@ -0,0 +1,258 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <mntent.h>
+#include <paths.h>
+#include <pthread.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);
+}
+
+
+sem_t *
+sem_open (const char *name, int oflag, ...)
+{
+  char *finalname;
+  size_t namelen;
+  sem_t *result;
+  int fd;
+
+  /* Determine where the shmfs is mounted.  */
+  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;
+    }
+  namelen = strlen (name);
+
+  /* Create the name of the final file.  */
+  finalname = (char *) alloca (mountpoint.dirlen + namelen + 1);
+  __mempcpy (__mempcpy (finalname, mountpoint.dir, mountpoint.dirlen),
+            name, namelen + 1);
+
+  /* If the semaphore object has to exist simply open it.  */
+  if ((oflag & O_CREAT) == 0)
+    {
+      fd = open (finalname, oflag | O_NOFOLLOW);
+
+      if (fd == -1)
+       /* Return.  errno is already set.  */
+       return SEM_FAILED;
+
+      /* Map the sem_t structure from the file.  */
+      result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
+                              MAP_SHARED, fd, 0);
+    }
+  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;
+
+      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;
+       }
+
+      tmpfname = (char *) alloca (mountpoint.dirlen + 6 + 1);
+      strcpy (__mempcpy (tmpfname, mountpoint.dir, mountpoint.dirlen),
+             "XXXXXX");
+
+      fd = mkstemp (tmpfname);
+      if (fd == -1)
+       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));
+
+      if (TEMP_FAILURE_RETRY (write (fd, &initsem, sizeof (sem_t)))
+         != sizeof (sem_t)
+         /* Adjust the permission.  */
+         || fchmod (fd, mode) != 0)
+       {
+       unlink_return:
+         unlink (tmpfname);
+         return SEM_FAILED;
+       }
+
+      /* Map the sem_t structure from the file.  */
+      result = (sem_t *) mmap (NULL, sizeof (sem_t), PROT_READ | PROT_WRITE,
+                              MAP_SHARED, fd, 0);
+      if (result == MAP_FAILED)
+       goto unlink_return;
+
+      /* Create or overwrite the file.  Depending on what is wanted we
+        use rename or link.  */
+      if ((oflag & O_EXCL) == 0)
+       {
+         /* An existing file gets overwritten.  */
+         if (rename (tmpfname, finalname) != 0)
+           {
+           unmap_unlink_return:
+             munmap (result, sizeof (sem_t));
+             goto unlink_return;
+           }
+       }
+      else
+       {
+         /* Don't overwrite an existing file.  */
+         if (link (tmpfname, finalname) != 0)
+           goto unmap_unlink_return;
+
+         /* This went well.  Now remove the temporary name.  This
+            should never fail.  If it fails we leak a file name.
+            Better fix the kernel.  */
+         (void) unlink (tmpfname);
+       }
+    }
+
+  /* We don't need the file descriptor anymore.  */
+  close (fd);
+
+  return result;
+}
diff --git a/nptl/sem_unlink.c b/nptl/sem_unlink.c
new file mode 100644 (file)
index 0000000..b8e3de1
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "semaphoreP.h"
+
+
+int
+sem_unlink (name)
+     const char *name;
+{
+  char *fname;
+  size_t namelen;
+
+  /* Determine where the shmfs is mounted.  */
+  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 -1;
+    }
+
+  /* Construct the filename.  */
+  while (name[0] == '/')
+    ++name;
+
+  if (name[0] == '\0')
+    {
+      /* The name "/" is not supported.  */
+      __set_errno (ENOENT);
+      return -1;
+    }
+  namelen = strlen (name);
+
+  /* Create the name of the file.  */
+  fname = (char *) alloca (mountpoint.dirlen + namelen + 1);
+  __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen),
+            name, namelen + 1);
+
+  /* Now try removing it.  */
+  return unlink (fname);
+}
diff --git a/nptl/semaphore.h b/nptl/semaphore.h
new file mode 100644 (file)
index 0000000..b8861e5
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _SEMAPHORE_H
+#define _SEMAPHORE_H   1
+
+#include <features.h>
+#include <sys/types.h>
+#ifdef __USE_XOPEN2K
+# define __need_timespec
+# include <time.h>
+#endif
+
+/* Get the definition for sem_t.  */
+#include <bits/semaphore.h>
+
+
+__BEGIN_DECLS
+
+/* Initialize semaphore object SEM to VALUE.  If PSHARED then share it
+   with other processes.  */
+extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value)
+     __THROW;
+/* Free resources associated with semaphore object SEM.  */
+extern int sem_destroy (sem_t *__sem) __THROW;
+
+/* Open a named semaphore NAME with open flaot OFLAG.  */
+extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW;
+
+/* Close descriptor for named semaphore SEM.  */
+extern int sem_close (sem_t *__sem) __THROW;
+
+/* Remove named semaphore NAME.  */
+extern int sem_unlink (__const char *__name) __THROW;
+
+/* Wait for SEM being posted.  */
+extern int sem_wait (sem_t *__sem) __THROW;
+
+#ifdef __USE_XOPEN2K
+/* Similar to `sem_wait' but wait only until ABSTIME.  */
+extern int sem_timedwait (sem_t *__restrict __sem,
+                         __const struct timespec *__restrict __abstime)
+     __THROW;
+#endif
+
+/* Test whether SEM is posted.  */
+extern int sem_trywait (sem_t *__sem) __THROW;
+
+/* Post SEM.  */
+extern int sem_post (sem_t *__sem) __THROW;
+
+/* Get current value of SEM and store it in *SVAL.  */
+extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval)
+     __THROW;
+
+
+__END_DECLS
+
+#endif /* semaphore.h */
diff --git a/nptl/semaphoreP.h b/nptl/semaphoreP.h
new file mode 100644 (file)
index 0000000..0d3f6e5
--- /dev/null
@@ -0,0 +1,46 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+/* Mount point of the shared memory filesystem.  */
+struct mountpoint_info
+{
+  char *dir;
+  size_t dirlen;
+};
+
+
+/* Variables used in multiple interfaces.  */
+extern struct mountpoint_info mountpoint attribute_hidden;
+
+extern pthread_once_t __namedsem_once attribute_hidden;
+
+
+/* Initializer for mountpoint.  */
+extern void __where_is_shmfs (void) attribute_hidden;
+
+
+/* Prototypes of functions with multiple interfaces.  */
+extern int __new_sem_init (sem_t *sem, int pshared, unsigned int value);
+extern int __new_sem_destroy (sem_t *sem);
+extern int __new_sem_post (sem_t *sem);
+extern int __new_sem_wait (sem_t *sem);
+extern int __new_sem_trywait (sem_t *sem);
+extern int __new_sem_getvalue (sem_t *sem, int *sval);
diff --git a/nptl/shlib-versions b/nptl/shlib-versions
new file mode 100644 (file)
index 0000000..9493a31
--- /dev/null
@@ -0,0 +1,9 @@
+mips.*-.*-linux.*      libpthread=0            GLIBC_2.0 GLIBC_2.2
+sparc64-.*-linux.*     libpthread=0            GLIBC_2.2
+sh.*-.*-linux.*                libpthread=0            GLIBC_2.2
+ia64.*-.*-linux.*      libpthread=0            GLIBC_2.2
+hppa.*-.*-linux.*      libpthread=0            GLIBC_2.2
+s390x-.*-linux.*       libpthread=0            GLIBC_2.2
+cris-.*-linux.*                libpthread=0            GLIBC_2.2
+x86_64-.*-linux.*      libpthread=0            GLIBC_2.2.5
+.*-.*-linux.*          libpthread=0
diff --git a/nptl/sockperf.c b/nptl/sockperf.c
new file mode 100644 (file)
index 0000000..d29a6ee
--- /dev/null
@@ -0,0 +1,594 @@
+#define _GNU_SOURCE
+#include <argp.h>
+#include <complex.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <gd.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+
+#define size_x 320
+#define size_y 240
+
+
+#define PATH "/tmp/s.sockperf"
+
+
+struct thread_param
+{
+  unsigned int from;
+  unsigned int to;
+  unsigned int nserv;
+};
+
+struct coord
+{
+  unsigned int x;
+  unsigned int y;
+  complex double z;
+};
+
+
+/* We use 64bit values for the times.  */
+typedef unsigned long long int hp_timing_t;
+
+
+static unsigned int nclients = 2;
+static unsigned int nservers = 2;
+
+static bool timing;
+static int points;
+
+
+static complex double top_left = -0.7 + 0.2i;
+static complex double bottom_right = -0.5 - 0.0i;
+
+
+static int colors[256];
+static gdImagePtr image;
+static pthread_mutex_t image_lock;
+
+static int sock;
+
+
+static void *
+client (void *arg)
+{
+  struct thread_param *param = arg;
+  unsigned int cnt;
+  unsigned int nserv = param->nserv;
+  int clisock[nserv];
+  struct pollfd servpoll[nserv];
+  struct sockaddr_un servaddr;
+  socklen_t servlen;
+  struct coord c;
+
+  bool new_coord (void)
+    {
+      if (cnt >= param->to)
+       return false;
+
+      unsigned int row = cnt / size_x;
+      unsigned int col = cnt % size_x;
+
+      c.x = col;
+      c.y = row;
+      c.z = (top_left
+            + ((col
+                * (creal (bottom_right) - creal (top_left))) / size_x)
+            + (_Complex_I * (row * (cimag (bottom_right) - cimag (top_left)))
+               / size_y));
+
+      ++cnt;
+
+      return true;
+    }
+
+
+  for (cnt = 0; cnt < nserv; ++cnt)
+    {
+      servpoll[cnt].fd = socket (AF_UNIX, SOCK_STREAM, 0);
+      if (clisock < 0)
+       {
+         puts ("cannot create socket in client");
+         return NULL;
+       }
+
+      memset (&servaddr, '\0', sizeof (servaddr));
+      servaddr.sun_family = AF_UNIX;
+      strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path));
+      servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1;
+
+
+      int err;
+      while (1)
+       {
+         err = TEMP_FAILURE_RETRY (connect (servpoll[cnt].fd, &servaddr,
+                                            servlen));
+         if (err != -1 || errno != ECONNREFUSED)
+           break;
+
+         pthread_yield ();
+       }
+
+      if (err == -1)
+       {
+         printf ("cannot connect: %m (%d)\n", errno);
+         exit (1);
+       }
+
+      servpoll[cnt].events = POLLOUT;
+      servpoll[cnt].revents = 0;
+    }
+
+  cnt = param->from;
+
+  new_coord ();
+  bool z_valid = true;
+
+  while (1)
+    {
+      int i;
+      int n = poll (servpoll, nserv, -1);
+      if (n == -1)
+       {
+         puts ("poll returned error");
+         break;
+       }
+
+      bool cont = false;
+      for (i = 0; i < nserv && n > 0; ++i)
+       if (servpoll[i].revents != 0)
+         {
+           if (servpoll[i].revents == POLLIN)
+             {
+               unsigned int vals[3];
+               if (TEMP_FAILURE_RETRY (read (servpoll[i].fd, &vals,
+                                             sizeof (vals)))
+                   != sizeof (vals))
+                 {
+                   puts ("read error in client");
+                   return NULL;
+                 }
+
+               pthread_mutex_lock (&image_lock);
+
+               gdImageSetPixel (image, vals[0], vals[1], vals[2]);
+               ++points;
+
+               pthread_mutex_unlock (&image_lock);
+
+               servpoll[i].events = POLLOUT;
+             }
+           else
+             {
+               if (servpoll[i].revents != POLLOUT)
+                 printf ("revents: %hd != POLLOUT ???\n",
+                         servpoll[i].revents);
+
+               if (z_valid)
+                 {
+                   if (TEMP_FAILURE_RETRY (write (servpoll[i].fd, &c,
+                                                  sizeof (c))) != sizeof (c))
+                     {
+                       puts ("write error in client");
+                       return NULL;
+                     }
+                   cont = true;
+                   servpoll[i].events = POLLIN;
+
+                   z_valid = new_coord ();
+                   if (! z_valid)
+                     /* No more to do.  Clear the event fields.  */
+                     for (i = 0; i < nserv; ++i)
+                       if (servpoll[i].events == POLLOUT)
+                         servpoll[i].events = servpoll[i].revents = 0;
+                 }
+               else
+                 servpoll[i].events = servpoll[i].revents = 0;
+             }
+
+           --n;
+         }
+       else if (servpoll[i].events != 0)
+         cont = true;
+
+      if (! cont && ! z_valid)
+       break;
+    }
+
+  c.x = 0xffffffff;
+  c.y = 0xffffffff;
+  for (cnt = 0; cnt < nserv; ++cnt)
+    {
+      TEMP_FAILURE_RETRY (write (servpoll[cnt].fd, &c, sizeof (c)));
+      close (servpoll[cnt].fd);
+    }
+
+  return NULL;
+}
+
+
+static void *
+server (void *arg)
+{
+  struct sockaddr_un cliaddr;
+  socklen_t clilen;
+  int clisock = TEMP_FAILURE_RETRY (accept (sock, &cliaddr, &clilen));
+
+  if (clisock == -1)
+    {
+      puts ("accept failed");
+      return NULL;
+    }
+
+  while (1)
+    {
+      struct coord c;
+
+      if (TEMP_FAILURE_RETRY (read (clisock, &c, sizeof (c))) != sizeof (c))
+       {
+         printf ("server read failed: %m (%d)\n", errno);
+         break;
+       }
+
+      if (c.x == 0xffffffff && c.y == 0xffffffff)
+       break;
+
+      unsigned int rnds = 0;
+      complex double z = c.z;
+      while (cabs (z) < 4.0)
+       {
+         z = z * z - 1;
+         if (++rnds == 255)
+           break;
+       }
+
+      unsigned int vals[3] = { c.x, c.y, rnds };
+      if (TEMP_FAILURE_RETRY (write (clisock, vals, sizeof (vals)))
+         != sizeof (vals))
+       {
+         puts ("server write error");
+         return NULL;
+       }
+    }
+
+  close (clisock);
+
+  return NULL;
+}
+
+
+static const char *outfilename = "test.png";
+
+
+static const struct argp_option options[] =
+  {
+    { "clients", 'c', "NUMBER", 0, "Number of client threads" },
+    { "servers", 's', "NUMBER", 0, "Number of server threads per client" },
+    { "timing", 'T', NULL, 0,
+      "Measure time from startup to the last thread finishing" },
+    { NULL, 0, NULL, 0, NULL }
+  };
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt
+};
+
+
+int
+main (int argc, char *argv[])
+{
+  int cnt;
+  FILE *outfile;
+  struct sockaddr_un servaddr;
+  socklen_t servlen;
+  int remaining;
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+
+  pthread_t servth[nservers * nclients];
+  pthread_t clntth[nclients];
+  struct thread_param clntparam[nclients];
+
+
+  image = gdImageCreate (size_x, size_y);
+  if (image == NULL)
+    {
+      puts ("gdImageCreate failed");
+      return 1;
+    }
+
+  for (cnt = 0; cnt < 255; ++cnt)
+    colors[cnt] = gdImageColorAllocate (image, 256 - cnt, 256 - cnt,
+                                       256 - cnt);
+  /* Black.  */
+  colors[cnt] = gdImageColorAllocate (image, 0, 0, 0);
+
+
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    error (EXIT_FAILURE, errno, "cannot create socket");
+
+  memset (&servaddr, '\0', sizeof (servaddr));
+  servaddr.sun_family = AF_UNIX;
+  strncpy (servaddr.sun_path, PATH, sizeof (servaddr.sun_path));
+  servlen = offsetof (struct sockaddr_un, sun_path) + strlen (PATH) + 1;
+
+  if (bind (sock, &servaddr, servlen) == -1)
+    error (EXIT_FAILURE, errno, "bind failed");
+
+  listen (sock, SOMAXCONN);
+
+  pthread_mutex_init (&image_lock, NULL);
+
+
+  struct sigaction sa;
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  clockid_t cl;
+  struct timespec start_time;
+  if (timing)
+    {
+      if (clock_getcpuclockid (0, &cl) != 0
+         || clock_gettime (cl, &start_time) != 0)
+       timing = false;
+    }
+
+  /* Start the servers.  */
+  for (cnt = 0; cnt < nservers * nclients; ++cnt)
+    {
+      if (pthread_create (&servth[cnt], NULL, server, NULL) != 0)
+       {
+         puts ("pthread_create for server failed");
+         exit (1);
+       }
+    }
+
+  for (cnt = 0; cnt < nclients; ++cnt)
+    {
+      clntparam[cnt].from = cnt * (size_x * size_y) / nclients;
+      clntparam[cnt].to = MIN ((cnt + 1) * (size_x * size_y) / nclients,
+                              size_x * size_y);
+      clntparam[cnt].nserv = nservers;
+
+      if (pthread_create (&clntth[cnt], NULL, client, &clntparam[cnt]) != 0)
+       {
+         puts ("pthread_create for client failed");
+         exit (1);
+       }
+    }
+
+
+  /* Wait for the clients.  */
+  for (cnt = 0; cnt < nclients; ++cnt)
+    if (pthread_join (clntth[cnt], NULL) != 0)
+      {
+       puts ("client pthread_join failed");
+       exit (1);
+      }
+
+  /* Wait for the servers.  */
+  for (cnt = 0; cnt < nclients * nservers; ++cnt)
+    if (pthread_join (servth[cnt], NULL) != 0)
+      {
+       puts ("server pthread_join failed");
+       exit (1);
+      }
+
+
+  if (timing)
+    {
+      struct timespec end_time;
+
+      if (clock_gettime (cl, &end_time) == 0)
+       {
+         end_time.tv_sec -= start_time.tv_sec;
+         end_time.tv_nsec -= start_time.tv_nsec;
+         if (end_time.tv_nsec < 0)
+           {
+             end_time.tv_nsec += 1000000000;
+             --end_time.tv_sec;
+           }
+
+         printf ("\nRuntime: %lu.%09lu seconds\n%d points computed\n",
+                 (unsigned long int) end_time.tv_sec,
+                 (unsigned long int) end_time.tv_nsec,
+                 points);
+       }
+    }
+
+
+  outfile = fopen (outfilename, "w");
+  if (outfile == NULL)
+    error (EXIT_FAILURE, errno, "cannot open output file '%s'", outfilename);
+
+  gdImagePng (image, outfile);
+
+  fclose (outfile);
+
+  unlink (PATH);
+
+  return 0;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'c':
+      nclients = strtoul (arg, NULL, 0);
+      break;
+
+    case 's':
+      nservers = strtoul (arg, NULL, 0);
+      break;
+
+    case 'T':
+      timing = true;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  return 0;
+}
+
+
+static hp_timing_t
+get_clockfreq (void)
+{
+  /* We read the information from the /proc filesystem.  It contains at
+     least one line like
+       cpu MHz         : 497.840237
+     or also
+       cpu MHz         : 497.841
+     We search for this line and convert the number in an integer.  */
+  static hp_timing_t result;
+  int fd;
+
+  /* If this function was called before, we know the result.  */
+  if (result != 0)
+    return result;
+
+  fd = open ("/proc/cpuinfo", O_RDONLY);
+  if (__builtin_expect (fd != -1, 1))
+    {
+      /* XXX AFAIK the /proc filesystem can generate "files" only up
+         to a size of 4096 bytes.  */
+      char buf[4096];
+      ssize_t n;
+
+      n = read (fd, buf, sizeof buf);
+      if (__builtin_expect (n, 1) > 0)
+       {
+         char *mhz = memmem (buf, n, "cpu MHz", 7);
+
+         if (__builtin_expect (mhz != NULL, 1))
+           {
+             char *endp = buf + n;
+             int seen_decpoint = 0;
+             int ndigits = 0;
+
+             /* Search for the beginning of the string.  */
+             while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n')
+               ++mhz;
+
+             while (mhz < endp && *mhz != '\n')
+               {
+                 if (*mhz >= '0' && *mhz <= '9')
+                   {
+                     result *= 10;
+                     result += *mhz - '0';
+                     if (seen_decpoint)
+                       ++ndigits;
+                   }
+                 else if (*mhz == '.')
+                   seen_decpoint = 1;
+
+                 ++mhz;
+               }
+
+             /* Compensate for missing digits at the end.  */
+             while (ndigits++ < 6)
+               result *= 10;
+           }
+       }
+
+      close (fd);
+    }
+
+  return result;
+}
+
+
+int
+clock_getcpuclockid (pid_t pid, clockid_t *clock_id)
+{
+  /* We don't allow any process ID but our own.  */
+  if (pid != 0 && pid != getpid ())
+    return EPERM;
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+  /* Store the number.  */
+  *clock_id = CLOCK_PROCESS_CPUTIME_ID;
+
+  return 0;
+#else
+  /* We don't have a timer for that.  */
+  return ENOENT;
+#endif
+}
+
+
+#define HP_TIMING_NOW(Var)     __asm__ __volatile__ ("rdtsc" : "=A" (Var))
+
+/* Get current value of CLOCK and store it in TP.  */
+int
+clock_gettime (clockid_t clock_id, struct timespec *tp)
+{
+  int retval = -1;
+
+  switch (clock_id)
+    {
+    case CLOCK_PROCESS_CPUTIME_ID:
+      {
+
+       static hp_timing_t freq;
+       hp_timing_t tsc;
+
+       /* Get the current counter.  */
+       HP_TIMING_NOW (tsc);
+
+       if (freq == 0)
+         {
+           freq = get_clockfreq ();
+           if (freq == 0)
+             return EINVAL;
+         }
+
+       /* Compute the seconds.  */
+       tp->tv_sec = tsc / freq;
+
+       /* And the nanoseconds.  This computation should be stable until
+          we get machines with about 16GHz frequency.  */
+       tp->tv_nsec = ((tsc % freq) * UINT64_C (1000000000)) / freq;
+
+       retval = 0;
+      }
+    break;
+
+    default:
+      errno = EINVAL;
+      break;
+    }
+
+  return retval;
+}
diff --git a/nptl/sysdeps/i386/i686/pthread_spin_trylock.S b/nptl/sysdeps/i386/i686/pthread_spin_trylock.S
new file mode 100644 (file)
index 0000000..881976c
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define EBUSY  16
+
+       .globl  pthread_spin_trylock
+       .type   pthread_spin_trylock,@function
+       .align  16
+pthread_spin_trylock:
+       movl    4(%esp), %edx
+       movl    $1, %eax
+       xorl    %ecx, %ecx
+       cmpxchgl %ecx, (%edx)
+       movl    $EBUSY, %ecx
+       movl    $0, %eax
+       cmovne  %ecx, %eax
+       ret
+       .size   pthread_spin_trylock,.-pthread_spin_trylock
diff --git a/nptl/sysdeps/i386/i686/tls.h b/nptl/sysdeps/i386/i686/tls.h
new file mode 100644 (file)
index 0000000..4025ed8
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+
+/* Additional definitions for <tls.h> on i686 and up.  */
+
+
+/* Macros to load from and store into segment registers.  We can use
+   the 32-bit instructions.  */
+#define TLS_GET_GS() \
+  ({ int __seg; __asm ("movl %%gs, %0" : "=q" (__seg)); __seg; })
+#define TLS_SET_GS(val) \
+  __asm ("movl %0, %%gs" :: "q" (val))
+
+
+/* Get the full set of definitions.  */
+#include "../tls.h"
+
+#endif /* tls.h */
diff --git a/nptl/sysdeps/i386/pthread_sigmask.c b/nptl/sysdeps/i386/pthread_sigmask.c
new file mode 100644 (file)
index 0000000..2ae9198
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <signal.h>
+#include <pthreadP.h>
+#include <tls.h>
+#include <sysdep.h>
+
+
+int
+pthread_sigmask (how, newmask, oldmask)
+     int how;
+     const sigset_t *newmask;
+     sigset_t *oldmask;
+{
+  return INLINE_SYSCALL (sigprocmask, 3, how, newmask, oldmask);
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_lock.c b/nptl/sysdeps/i386/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..43a1831
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include "pthreadP.h"
+
+
+#ifdef UP
+# define LOCK
+#else
+# define LOCK "lock;"
+#endif
+
+
+int
+pthread_spin_lock (lock)
+     pthread_spinlock_t *lock;
+{
+  asm ("\n"
+       "1:\t" LOCK "decl %0\n\t"
+       "jne 2f\n\t"
+       ".subsection 1\n\t"
+       ".align 16\n"
+       "2:\trep; nop\n\t"
+       "cmpl $0, %0\n\t"
+       "jg 1b\n\t"
+       "jmp 2b\n\t"
+       ".previous"
+       : "=m" (*lock)
+       : "0" (*lock));
+
+  return 0;
+}
diff --git a/nptl/sysdeps/i386/pthread_spin_unlock.S b/nptl/sysdeps/i386/pthread_spin_unlock.S
new file mode 100644 (file)
index 0000000..d94f1e7
--- /dev/null
@@ -0,0 +1,32 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+       .globl  pthread_spin_unlock
+       .type   pthread_spin_unlock,@function
+       .align  16
+pthread_spin_unlock:
+       movl    4(%esp), %eax
+       movl    $1, (%eax)
+       xorl    %eax, %eax
+       ret
+       .size   pthread_spin_unlock,.-pthread_spin_unlock
+
+       /* The implementation of pthread_spin_init is identical.  */
+       .globl  pthread_spin_init
+pthread_spin_init = pthread_spin_unlock
diff --git a/nptl/sysdeps/i386/pthreaddef.h b/nptl/sysdeps/i386/pthreaddef.h
new file mode 100644 (file)
index 0000000..6efa1b6
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  SSE requires 16
+   bytes.  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     2048
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+/* The signal used for asynchronous cancelation.  */
+#define SIGCANCEL              __SIGRTMIN
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+
+/* While there is no such syscall.  */
+#define __exit_thread_inline(val) \
+  while (1) {                                                                \
+    if (__builtin_constant_p (val) && (val) == 0)                            \
+      asm volatile ("xorl %%ebx, %%ebx; int $0x80" :: "a" (__NR_exit));              \
+    else                                                                     \
+      asm volatile ("movl %1, %%ebx; int $0x80"                                      \
+                   :: "a" (__NR_exit), "r" (val));                           \
+  }
+#define gettid()                                                             \
+  ({ int tid;                                                                \
+     __asm __volatile ("int $0x80" : "=a" (tid) : "0" (__NR_gettid));        \
+     tid; })
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
new file mode 100644 (file)
index 0000000..244a487
--- /dev/null
@@ -0,0 +1,332 @@
+/* Definition for thread-local data handling.  linuxthreads/i386 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+#ifndef __ASSEMBLER__
+# include <stddef.h>
+# include <stdint.h>
+
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+
+typedef struct
+{
+  void *tcb;           /* Pointer to the TCB.  Not necessary the
+                          thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;          /* Pointer to the thread descriptor.  */
+} tcbhead_t;
+#endif
+
+
+/* We require TLS support in the tools.  */
+#ifndef HAVE_TLS_SUPPORT
+# error "TLS support is required."
+#endif
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+/* Alignment requirement for the stack.  For IA-32 this is govern by
+   the SSE memory functions.  */
+#define STACK_ALIGN    16
+
+
+#ifndef __ASSEMBLER__
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The old way: using LDT.  */
+
+/* Structure passed to `modify_ldt', 'set_thread_area', and 'clone' calls.  */
+struct user_desc
+{
+  unsigned int entry_number;
+  unsigned long int base_addr;
+  unsigned int limit;
+  unsigned int seg_32bit:1;
+  unsigned int contents:2;
+  unsigned int read_exec_only:1;
+  unsigned int limit_in_pages:1;
+  unsigned int seg_not_present:1;
+  unsigned int useable:1;
+  unsigned int empty:25;
+};
+
+/* Initializing bit fields is slow.  We speed it up by using a union.  */
+union user_desc_init
+{
+  struct user_desc desc;
+  unsigned int vals[4];
+};
+
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+/* This is the size of the initial TCB.  */
+# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+# define TLS_TCB_SIZE sizeof (struct pthread)
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* The TCB can have any size and the memory following the address the
+   thread pointer points to is unspecified.  Allocate the TCB there.  */
+# define TLS_TCB_AT_TP 1
+
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(descr, dtvp) \
+  ((tcbhead_t *) (descr))->dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_SETMEM (__pd, header.data.dtvp, dtv); })
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+
+/* Macros to load from and store into segment registers.  */
+# ifndef TLS_GET_GS
+#  define TLS_GET_GS() \
+  ({ int __seg; __asm ("movw %%gs, %w0" : "=q" (__seg)); __seg & 0xffff; })
+# endif
+# ifndef TLS_SET_GS
+#  define TLS_SET_GS(val) \
+  __asm ("movw %w0, %%gs" :: "q" (val))
+# endif
+
+
+# ifndef __NR_set_thread_area
+#  define __NR_set_thread_area 243
+# endif
+# ifndef TLS_FLAG_WRITABLE
+#  define TLS_FLAG_WRITABLE            0x00000001
+# endif
+
+// XXX Enable for the real world.
+#if 0
+# ifndef __ASSUME_SET_THREAD_AREA
+#  error "we need set_thread_area"
+# endif
+#endif
+
+# ifdef __PIC__
+#  define TLS_EBX_ARG "r"
+#  define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t"
+# else
+#  define TLS_EBX_ARG "b"
+#  define TLS_LOAD_EBX
+# endif
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(thrdescr, secondcall) \
+  ({ void *_thrdescr = (thrdescr);                                           \
+     tcbhead_t *_head = _thrdescr;                                           \
+     union user_desc_init _segdescr;                                         \
+     int _result;                                                            \
+                                                                             \
+     _head->tcb = _thrdescr;                                                 \
+     /* For now the thread descriptor is at the same address.  */            \
+     _head->self = _thrdescr;                                                \
+                                                                             \
+     /* The 'entry_number' field.  Let the kernel pick a value.  */          \
+     if (secondcall)                                                         \
+       _segdescr.vals[0] = TLS_GET_GS () >> 3;                               \
+     else                                                                    \
+       _segdescr.vals[0] = -1;                                               \
+     /* The 'base_addr' field.  Pointer to the TCB.  */                              \
+     _segdescr.vals[1] = (unsigned long int) _thrdescr;                              \
+     /* The 'limit' field.  We use 4GB which is 0xfffff pages.  */           \
+     _segdescr.vals[2] = 0xfffff;                                            \
+     /* Collapsed value of the bitfield:                                     \
+         .seg_32bit = 1                                                      \
+         .contents = 0                                                       \
+         .read_exec_only = 0                                                 \
+         .limit_in_pages = 1                                                 \
+         .seg_not_present = 0                                                \
+         .useable = 1 */                                                     \
+     _segdescr.vals[3] = 0x51;                                               \
+                                                                             \
+     /* Install the TLS.  */                                                 \
+     asm volatile (TLS_LOAD_EBX                                                      \
+                  "int $0x80\n\t"                                            \
+                  TLS_LOAD_EBX                                               \
+                  : "=a" (_result), "=m" (_segdescr.desc.entry_number)       \
+                  : "0" (__NR_set_thread_area),                              \
+                    TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc));    \
+                                                                             \
+     if (_result == 0)                                                       \
+       /* We know the index in the GDT, now load the segment register.       \
+         The use of the GDT is described by the value 3 in the lower         \
+         three bits of the segment descriptor value.                         \
+                                                                             \
+         Note that we have to do this even if the numeric value of           \
+         the descriptor does not change.  Loading the segment register       \
+         causes the segment information from the GDT to be loaded            \
+         which is necessary since we have changed it.   */                   \
+       TLS_SET_GS (_segdescr.desc.entry_number * 8 + 3);                     \
+                                                                             \
+     _result; })
+
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  ({ struct pthread *__pd;                                                   \
+     THREAD_GETMEM (__pd, header.data.dtvp); })
+
+
+/* Return the thread descriptor for the current thread.
+
+   The contained asm must *not* be marked volatile since otherwise
+   assignments like
+        pthread_descr self = thread_self();
+   do not get optimized away.  */
+# define THREAD_SELF \
+  ({ struct pthread *__self;                                                 \
+     asm ("movl %%gs:%c1,%0" : "=r" (__self)                                 \
+         : "i" (offsetof (struct pthread, header.data.self)));               \
+     __self;})
+
+
+/* Read member of the thread descriptor directly.  */
+# define THREAD_GETMEM(descr, member) \
+  ({ __typeof (descr->member) __value;                                       \
+     if (sizeof (__value) == 1)                                                      \
+       asm ("movb %%gs:%P2,%b0"                                                      \
+           : "=q" (__value)                                                  \
+           : "0" (0), "i" (offsetof (struct pthread, member)));              \
+     else if (sizeof (__value) == 4)                                         \
+       asm ("movl %%gs:%P1,%0"                                               \
+           : "=r" (__value)                                                  \
+           : "i" (offsetof (struct pthread, member)));                       \
+     else                                                                    \
+       {                                                                     \
+        if (sizeof (__value) != 8)                                           \
+          /* There should not be any value with a size other than 1,         \
+             4 or 8.  */                                                     \
+          abort ();                                                          \
+                                                                             \
+        asm ("movl %%gs:%P1,%%eax\n\t"                                       \
+             "movl %%gs:%P2,%%edx"                                           \
+             : "=A" (__value)                                                \
+             : "i" (offsetof (struct pthread, member)),                      \
+               "i" (offsetof (struct pthread, member) + 4));